-
-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
⚡ Add dnd-processor tag that solves edge cases with drag-and-drop beh…
…avior and allows dropping any supported files on any tab
- Loading branch information
1 parent
7f04e30
commit f00de1a
Showing
10 changed files
with
362 additions
and
303 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* This file prevents opening an image or such when a file was dragged into | ||
* ct.js window and it was not catched by other listeners | ||
*/ | ||
|
||
{ | ||
const draghHandler = function draghHandler(e) { | ||
if (e.target.nodeName === 'INPUT' && e.target.type === 'file') { | ||
return; | ||
} | ||
e.preventDefault(); | ||
}; | ||
document.addEventListener('dragenter', draghHandler); | ||
document.addEventListener('dragover', draghHandler); | ||
document.addEventListener('drop', draghHandler); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/** | ||
* @param {object|string} font The font object in ct.js project, or its UID. | ||
* @param {boolean} fs If set to `true`, returns a clean path in a file system. | ||
* Otherwise, returns an URL. | ||
*/ | ||
const getPathToTtf = function getPathToTtf(font, fs) { | ||
const path = require('path'); | ||
if (fs) { | ||
return path.join(global.projdir, 'fonts', font.origname); | ||
} | ||
return `file://${global.projdir}/fonts/${font.origname}`; | ||
}; | ||
|
||
/** | ||
* @param {object|string} font The font object in ct.js project, or its UID. | ||
* @param {boolean} fs If set to `true`, returns a clean path in a file system. | ||
* Otherwise, returns an URL. | ||
*/ | ||
const getFontPreview = function getFontPreview(font, fs) { | ||
const path = require('path'); | ||
if (fs) { | ||
return path.join(global.projdir, 'fonts', `${font.origname}_prev.png`); | ||
} | ||
return `file://${global.projdir}/fonts/${font.origname}_prev.png?cache=${font.lastmod}`; | ||
}; | ||
|
||
const fontGenPreview = async function fontGenPreview(font) { | ||
const template = { | ||
weight: font.weight, | ||
style: font.italic ? 'italic' : 'normal' | ||
}; | ||
const fs = require('fs-extra'); | ||
const face = new FontFace('CTPROJFONT' + font.typefaceName, `url(${getPathToTtf(font)})`, template); | ||
|
||
// Trigger font loading by creating an invisible label with this font | ||
// const elt = document.createElement('span'); | ||
// elt.innerHTML = 'testString'; | ||
// elt.style.position = 'fixed'; | ||
// elt.style.right = '200%'; | ||
// elt.style.fontFamily = 'CTPROJFONT' + font.typefaceName; | ||
// document.body.appendChild(elt); | ||
|
||
const loaded = await face.load(); | ||
loaded.external = true; | ||
loaded.ctId = face.ctId = font.uid; | ||
document.fonts.add(loaded); | ||
// document.body.removeChild(elt); | ||
|
||
const c = document.createElement('canvas'); | ||
c.x = c.getContext('2d'); | ||
c.width = c.height = 64; | ||
c.x.clearRect(0, 0, 64, 64); | ||
c.x.font = `${font.italic ? 'italic ' : ''}${font.weight} ${Math.floor(64 * 0.75)}px "${loaded.family}"`; | ||
c.x.fillStyle = '#000'; | ||
c.x.fillText('Aa', 64 * 0.05, 64 * 0.75); | ||
|
||
// strip off the data:image url prefix to get just the base64-encoded bytes | ||
const dataURL = c.toDataURL(); | ||
const previewBuffer = dataURL.replace(/^data:image\/\w+;base64,/, ''); | ||
const buf = new Buffer(previewBuffer, 'base64'); | ||
await fs.writeFile(getFontPreview(font, true), buf); | ||
}; | ||
|
||
const importTtfToFont = async function importTtfToFont(src) { | ||
const fs = require('fs-extra'), | ||
path = require('path'); | ||
if (path.extname(src) !== '.ttf') { | ||
throw new Error(`[resources/fonts] Rejecting a file as it does not have a .ttf extension: ${src}`); | ||
} | ||
const generateGUID = require('./../../generateGUID'); | ||
const uid = generateGUID(); | ||
await fs.copy(src, path.join(global.projdir, '/fonts/f' + uid + '.ttf')); | ||
const obj = { | ||
typefaceName: path.basename(src).replace('.ttf', ''), | ||
weight: 400, | ||
italic: false, | ||
origname: `f${uid}.ttf`, | ||
lastmod: Number(new Date()), | ||
pixelFont: false, | ||
pixelFontSize: 16, | ||
pixelFontLineHeight: 18, | ||
charsets: ['allInFont'], | ||
customCharset: '', | ||
uid | ||
}; | ||
global.currentProject.fonts.push(obj); | ||
await fontGenPreview(obj); | ||
window.signals.trigger('fontCreated'); | ||
}; | ||
module.exports = { | ||
importTtfToFont, | ||
fontGenPreview, | ||
getFontPreview, | ||
getPathToTtf | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
const path = require('path'); | ||
|
||
const getSkeletonData = function getSkeletonData(skeleton, fs) { | ||
if (fs) { | ||
return path.join(global.projdir, 'img', skeleton.origname); | ||
} | ||
return `file://${global.projdir}/img/${skeleton.origname}`; | ||
}; | ||
const getSkeletonTextureData = function getSkeletonTextureData(skeleton, fs) { | ||
const slice = skeleton.origname.replace('_ske.json', ''); | ||
if (fs) { | ||
return path.join(global.projdir, 'img', `${slice}_tex.json`); | ||
} | ||
return `file://${global.projdir}/img/${slice}_tex.json`; | ||
}; | ||
const getSkeletonTexture = function getSkeletonTexture(skeleton, fs) { | ||
const slice = skeleton.origname.replace('_ske.json', ''); | ||
if (fs) { | ||
return path.join(global.projdir, 'img', `${slice}_tex.png`); | ||
} | ||
return `file://${global.projdir}/img/${slice}_tex.png`; | ||
}; | ||
|
||
const getSkeletonPreview = function getSkeletonPreview(skeleton, fs) { | ||
if (fs) { | ||
return path.join(global.projdir, 'img', `${skeleton.origname}_prev.png`); | ||
} | ||
return `file://${global.projdir}/img/${skeleton.origname}_prev.png`; | ||
}; | ||
|
||
/** | ||
* Generates a square thumbnail of a given skeleton | ||
* @param {String} skeleton The skeleton object to generate a preview for. | ||
* @returns {Promise<void>} Resolves after creating a thumbnail. | ||
*/ | ||
const skeletonGenPreview = function (skeleton) { | ||
const loader = new PIXI.loaders.Loader(), | ||
dbf = dragonBones.PixiFactory.factory; | ||
const fs = require('fs-extra'); | ||
return new Promise((resolve, reject) => { | ||
// Draw the armature on a canvas/in a Pixi.js app | ||
const skelData = getSkeletonData(skeleton), | ||
texData = getSkeletonTextureData(skeleton), | ||
tex = getSkeletonTexture(skeleton); | ||
loader.add(skelData, skelData) | ||
.add(texData, texData) | ||
.add(tex, tex); | ||
loader.load(() => { | ||
dbf.parseDragonBonesData(loader.resources[skelData].data); | ||
dbf.parseTextureAtlasData( | ||
loader.resources[texData].data, | ||
loader.resources[tex].texture | ||
); | ||
const skel = dbf.buildArmatureDisplay('Armature', loader.resources[skelData].data.name); | ||
|
||
const app = new PIXI.Application(); | ||
|
||
const rawSkelBase64 = app.renderer.plugins.extract.base64(skel); | ||
const skelBase64 = rawSkelBase64.replace(/^data:image\/\w+;base64,/, ''); | ||
const buf = new Buffer(skelBase64, 'base64'); | ||
|
||
fs.writeFile(getSkeletonPreview(skeleton, true), buf) | ||
.then(() => { | ||
// Clean memory from DragonBones' armatures | ||
// eslint-disable-next-line no-underscore-dangle | ||
delete dbf._dragonBonesDataMap[loader.resources[skelData].data.name]; | ||
// eslint-disable-next-line no-underscore-dangle | ||
delete dbf._textureAtlasDataMap[loader.resources[skelData].data.name]; | ||
}) | ||
.then(resolve) | ||
.catch(reject); | ||
}); | ||
}); | ||
}; | ||
|
||
const importSkeleton = async function importSkeleton(source) { | ||
const generateGUID = require('./../generateGUID'); | ||
const fs = require('fs-extra'); | ||
|
||
const uid = generateGUID(); | ||
const partialDest = path.join(global.projdir + '/img/skdb' + uid); | ||
|
||
await Promise.all([ | ||
fs.copy(source, partialDest + '_ske.json'), | ||
fs.copy(source.replace('_ske.json', '_tex.json'), partialDest + '_tex.json'), | ||
fs.copy(source.replace('_ske.json', '_tex.png'), partialDest + '_tex.png') | ||
]); | ||
const skel = { | ||
name: path.basename(source).replace('_ske.json', ''), | ||
origname: path.basename(partialDest + '_ske.json'), | ||
from: 'dragonbones', | ||
uid | ||
}; | ||
await skeletonGenPreview(skel); | ||
global.currentProject.skeletons.push(skel); | ||
window.signals.trigger('skeletonImported', skel); | ||
}; | ||
|
||
module.exports = { | ||
getSkeletonData, | ||
getSkeletonTextureData, | ||
getSkeletonTexture, | ||
getSkeletonPreview, | ||
skeletonGenPreview, | ||
importSkeleton | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
dnd-processor | ||
.aDropzone(if="{dropping}") | ||
.middleinner | ||
svg.feather | ||
use(xlink:href="data/icons.svg#download") | ||
h2 {languageJSON.common.fastimport} | ||
input( | ||
type="file" multiple | ||
accept=".png,.jpg,.jpeg,.bmp,.gif,.json,.ttf" | ||
onchange="{dndImport}" | ||
) | ||
script. | ||
this.dndImport = e => { | ||
const files = [...e.target.files].map(file => file.path); | ||
for (let i = 0; i < files.length; i++) { | ||
if (/\.(jpg|gif|png|jpeg)/gi.test(files[i])) { | ||
const {importImageToTexture} = require('./data/node_requires/resources/textures'); | ||
importImageToTexture(files[i]); | ||
} else if (/_ske\.json/i.test(files[i])) { | ||
const {importSkeleton} = require('./data/node_requires/resources/skeletons'); | ||
importSkeleton(files[i]); | ||
} else if (/\.ttf/gi.test(files[i])) { | ||
const {importTtfToFont} = require('./data/node_requires/resources/fonts'); | ||
importTtfToFont(files[i]); | ||
} else { | ||
alertify.log(`Skipped ${files[i]} as it is not supported by drag-and-drop importer.`); | ||
} | ||
} | ||
e.srcElement.value = ''; | ||
this.dropping = false; | ||
e.preventDefault(); | ||
}; | ||
|
||
/* | ||
* drag-n-drop handling | ||
*/ | ||
let dragTimer; | ||
this.onDragOver = e => { | ||
var dt = e.dataTransfer; | ||
if (dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') !== -1 : dt.types.contains('Files'))) { | ||
this.dropping = true; | ||
this.update(); | ||
window.clearTimeout(dragTimer); | ||
} | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
}; | ||
this.onDrop = e => { | ||
e.stopPropagation(); | ||
}; | ||
this.onDragLeave = e => { | ||
dragTimer = window.setTimeout(() => { | ||
this.dropping = false; | ||
this.update(); | ||
}, 25); | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
}; | ||
this.on('mount', () => { | ||
document.addEventListener('dragover', this.onDragOver); | ||
document.addEventListener('dragleave', this.onDragLeave); | ||
document.addEventListener('drop', this.onDrop); | ||
}); | ||
this.on('unmount', () => { | ||
document.removeEventListener('dragover', this.onDragOver); | ||
document.removeEventListener('dragleave', this.onDragLeave); | ||
document.removeEventListener('drop', this.onDrop); | ||
}); |
Oops, something went wrong.