21 Commits

Author SHA1 Message Date
5e46d8b7e2 docs(readme): add Greenkeeper badge 2017-05-06 14:44:55 +00:00
e15d7b2422 chore(package): update dependencies 2017-05-06 14:43:20 +00:00
a8c85b8a29 Issue #654 : stop using jquery to create the FramesList markup 2017-04-01 12:48:11 +02:00
89199f2d6a Merge pull request #644 from juliandescottes/alt-to-pick-color
select color using alt+click (fixes #623)
2017-03-02 01:52:04 +01:00
98768b2e5b select color using alt+click (fixes #623) 2017-03-02 01:39:28 +01:00
62b1b8baf0 Merge pull request #642 from juliandescottes/sanitize-strings
sanitize strings coming from user inputs
2017-02-23 21:01:05 +01:00
11a063de12 sanitize strings coming from user inputs 2017-02-23 19:37:29 +01:00
6f4413f353 Merge pull request #638 from juliandescottes/nw-warning
add confirmation message when closing desktop app with unsaved changes
2017-02-19 15:14:33 +01:00
974450837e add confirmation message when closing desktop app with unsaved changes 2017-02-19 13:19:09 +01:00
c6c64af2fd Use Q deferred instead of native promise (IE11) 2017-02-11 16:57:56 +01:00
c68b82339c remove classList toggle with 2nd argument for IE11 2017-02-11 16:51:27 +01:00
099ff80155 Merge pull request #634 from zoeesilcock/628-fix-arrows-in-cheatsheet
Use standard HTML entities for the arrows displayed on the keyboard shortcut list
2017-02-05 12:41:30 +01:00
f30e16386d Use standard HTML entities for the arrows displayed on the keyboard shortcut list 2017-02-05 11:47:45 +01:00
08b97cb6f0 select previous layer after deleting layer 2017-02-04 14:32:23 +01:00
b6fa769ba1 temporary fix for layerlist scroll 2017-02-04 14:09:27 +01:00
47b09b10c5 Merge branch 'master' of https://github.com/juliandescottes/piskel 2017-02-04 13:49:20 +01:00
f039a89572 disable layerlist smoothscrolling 2017-02-04 13:43:49 +01:00
e74329f04e Merge pull request #629 from GMartigny/master
Add CodeClimate
2017-02-02 19:30:40 +01:00
8959b201e9 Excludes lib from linting 2017-02-01 16:17:38 +01:00
f5491dc557 Irregular whitespace 2017-02-01 16:15:02 +01:00
9ce3d44cc6 Add config file for CodeClimate 2017-02-01 15:51:13 +01:00
26 changed files with 280 additions and 113 deletions

25
.codeclimate.yml Normal file
View File

@ -0,0 +1,25 @@
engines:
csslint:
enabled: true
duplication:
enabled: true
config:
languages:
- javascript
eslint:
enabled: true
checks:
wrap-iife:
enabled: false
fixme:
enabled: true
ratings:
paths:
- "**.css"
- "**.js"
exclude_paths:
- .github/
- bin/
- misc/
- src/js/lib/
- test/

View File

@ -1,6 +1,8 @@
Piskel
======
[![Greenkeeper badge](https://badges.greenkeeper.io/juliandescottes/piskel.svg)](https://greenkeeper.io/)
[![Travis Status](https://api.travis-ci.org/juliandescottes/piskel.png?branch=master)](https://travis-ci.org/juliandescottes/piskel) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)
A simple web-based tool for Spriting and Pixel art.

View File

@ -28,30 +28,30 @@
},
"devDependencies": {
"dateformat": "2.0.0",
"fs-extra": "1.0.0",
"grunt": "^0.4.5",
"fs-extra": "3.0.1",
"grunt": "^1.0.1",
"grunt-casperjs": "^2.2.1",
"grunt-contrib-clean": "1.0.0",
"grunt-contrib-clean": "1.1.0",
"grunt-contrib-concat": "1.0.1",
"grunt-contrib-connect": "1.0.2",
"grunt-contrib-copy": "1.0.0",
"grunt-contrib-jshint": "1.1.0",
"grunt-contrib-uglify": "1.0.1",
"grunt-contrib-uglify": "2.3.0",
"grunt-contrib-watch": "1.0.0",
"grunt-include-replace": "4.0.1",
"grunt-jscs": "2.8.0",
"grunt-karma": "1.0.0",
"grunt-include-replace": "5.0.0",
"grunt-jscs": "3.0.1",
"grunt-karma": "2.0.0",
"grunt-leading-indent": "0.2.0",
"grunt-nw-builder": "3.1.0",
"grunt-open": "0.2.3",
"grunt-replace": "1.0.1",
"grunt-spritesmith": "6.3.0",
"jasmine-core": "2.1.0",
"karma": "1.3.0",
"karma-chrome-launcher": "1.0.1",
"karma-jasmine": "1.0.2",
"karma-phantomjs-launcher": "0.2.3",
"load-grunt-tasks": "3.5.0",
"grunt-spritesmith": "6.4.0",
"jasmine-core": "2.6.1",
"karma": "1.7.0",
"karma-chrome-launcher": "2.1.1",
"karma-jasmine": "1.1.0",
"karma-phantomjs-launcher": "1.0.4",
"load-grunt-tasks": "3.5.2",
"phantomjs": "2.1.7",
"phantomjs-polyfill-object-assign": "0.0.2",
"promise-polyfill": "6.0.2",

View File

@ -78,7 +78,7 @@
this.framesListController = new pskl.controller.FramesListController(
this.piskelController,
$('#preview-list'));
$('#preview-list-wrapper').get(0));
this.framesListController.init();
this.layersListController = new pskl.controller.LayersListController(this.piskelController);

View File

@ -163,6 +163,9 @@
if (event.button === Constants.MIDDLE_BUTTON) {
this.dragHandler.startDrag(event.clientX, event.clientY);
} else if (event.altKey && !this.currentToolBehavior.supportsAlt()) {
this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame);
this.isPickingColor = true;
} else {
this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame);
$.publish(Events.TOOL_PRESSED);
@ -210,6 +213,8 @@
if (this.isClicked) {
if (pskl.app.mouseStateService.isMiddleButtonPressed()) {
this.dragHandler.updateDrag(x, y);
} else if (this.isPickingColor) {
// Nothing to do on mousemove when picking a color with ALT+click.
} else {
$.publish(Events.MOUSE_EVENT, [event, this]);
this.currentToolBehavior.moveToolAt(
@ -294,39 +299,63 @@
* @private
*/
ns.DrawingController.prototype.onMouseup_ = function (event) {
var frame = this.piskelController.getCurrentFrame();
if (!this.isClicked) {
return;
}
var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
if (event.changedTouches && event.changedTouches[0]) {
coords = this.getSpriteCoordinates(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
}
if (this.isClicked) {
// A mouse button was clicked on the drawing canvas before this mouseup event,
// the user was probably drawing on the canvas.
// Note: The mousemove movement (and the mouseup) may end up outside
// of the drawing canvas.
this.isClicked = false;
// A mouse button was clicked on the drawing canvas before this mouseup event,
// the user was probably drawing on the canvas.
// Note: The mousemove movement (and the mouseup) may end up outside
// of the drawing canvas.
if (pskl.app.mouseStateService.isMiddleButtonPressed()) {
if (this.dragHandler.isDragging()) {
this.dragHandler.stopDrag();
} else if (frame.containsPixel(coords.x, coords.y)) {
var color = pskl.utils.intToColor(frame.getPixel(coords.x, coords.y));
$.publish(Events.SELECT_PRIMARY_COLOR, [color]);
}
} else {
this.currentToolBehavior.releaseToolAt(
coords.x,
coords.y,
this.piskelController.getCurrentFrame(),
this.overlayFrame,
event
);
this.isClicked = false;
$.publish(Events.TOOL_RELEASED);
}
$.publish(Events.MOUSE_EVENT, [event, this]);
var isMiddleButton = pskl.app.mouseStateService.isMiddleButtonPressed();
var isMiddleClick = isMiddleButton && !this.dragHandler.isDragging();
var isMiddleDrag = isMiddleButton && this.dragHandler.isDragging();
if (this.isPickingColor || isMiddleClick) {
// Picking color after ALT+click or middle mouse button click.
this.pickColorAt_(coords);
this.isPickingColor = false;
} else if (isMiddleDrag) {
// Stop the drag handler after a middle button drag action.
this.dragHandler.stopDrag();
} else {
// Regular tool click, release the current tool.
this.currentToolBehavior.releaseToolAt(
coords.x,
coords.y,
this.piskelController.getCurrentFrame(),
this.overlayFrame,
event
);
$.publish(Events.TOOL_RELEASED);
}
$.publish(Events.MOUSE_EVENT, [event, this]);
};
/**
* Send a COLOR selection event for the color contained at the provided coordinates.
* No-op if the coordinate is outside of the drawing canvas.
* @param {Object} coords {x: Number, y: Number}
*/
ns.DrawingController.prototype.pickColorAt_ = function (coords) {
var frame = this.piskelController.getCurrentFrame();
if (!frame.containsPixel(coords.x, coords.y)) {
return;
}
var color = pskl.utils.intToColor(frame.getPixel(coords.x, coords.y));
var isRightButton = pskl.app.mouseStateService.isRightButtonPressed();
var evt = isRightButton ? Events.SELECT_SECONDARY_COLOR : Events.SELECT_PRIMARY_COLOR;
$.publish(evt, [color]);
};
/**

View File

@ -11,6 +11,7 @@
ns.FramesListController = function (piskelController, container) {
this.piskelController = piskelController;
this.container = container;
this.previewList = container.querySelector('#preview-list');
this.refreshZoom_();
this.redrawFlag = true;
@ -31,8 +32,9 @@
$.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this));
$('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this));
this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this));
this.previewListScroller = document.querySelector('#preview-list-scroller');
this.previewListScroller.addEventListener('scroll', this.updateScrollerOverflows.bind(this));
this.container.addEventListener('click', this.onContainerClick_.bind(this));
this.updateScrollerOverflows();
};
@ -64,11 +66,11 @@
};
ns.FramesListController.prototype.updateScrollerOverflows = function () {
var scroller = $('#preview-list-scroller');
var scrollerHeight = scroller.height();
var scrollTop = scroller.scrollTop();
var scrollerContentHeight = $('#preview-list').height();
var treshold = $('.top-overflow').height();
var scroller = this.previewListScroller;
var scrollerHeight = scroller.offsetHeight;
var scrollTop = scroller.scrollTop;
var scrollerContentHeight = this.previewList.offsetHeight;
var treshold = this.container.querySelector('.top-overflow').offsetHeight;
var overflowTop = false;
var overflowBottom = false;
@ -81,9 +83,8 @@
overflowBottom = true;
}
}
var wrapper = $('#preview-list-wrapper');
wrapper.toggleClass('top-overflow-visible', overflowTop);
wrapper.toggleClass('bottom-overflow-visible', overflowBottom);
this.container.classList.toggle('top-overflow-visible', overflowTop);
this.container.classList.toggle('bottom-overflow-visible', overflowBottom);
};
ns.FramesListController.prototype.onContainerClick_ = function (event) {
@ -97,12 +98,12 @@
if (action === ACTION.CLONE) {
this.piskelController.duplicateFrameAt(index);
var clonedTile = this.createPreviewTile_(index + 1);
this.container.get(0).insertBefore(clonedTile, this.tiles[index].nextSibling);
this.previewList.insertBefore(clonedTile, this.tiles[index].nextSibling);
this.tiles.splice(index, 0, clonedTile);
this.updateScrollerOverflows();
} else if (action === ACTION.DELETE) {
this.piskelController.removeFrameAt(index);
this.container.get(0).removeChild(this.tiles[index]);
this.previewList.removeChild(this.tiles[index]);
this.tiles.splice(index, 1);
this.updateScrollerOverflows();
} else if (action === ACTION.SELECT && !this.justDropped) {
@ -111,7 +112,7 @@
this.piskelController.addFrame();
var newtile = this.createPreviewTile_(this.tiles.length);
this.tiles.push(newtile);
this.container.get(0).insertBefore(newtile, this.addFrameTile);
this.previewList.insertBefore(newtile, this.addFrameTile);
this.updateScrollerOverflows();
}
@ -147,7 +148,7 @@
}
// Hide/Show buttons if needed
var buttons = this.container.get(0).querySelectorAll('.delete-frame-action, .dnd-action');
var buttons = this.container.querySelectorAll('.delete-frame-action, .dnd-action');
var display = (this.piskelController.getFrameCount() > 1) ? 'block' : 'none';
for (i = 0, length = buttons.length; i < length; i++) {
buttons[i].style.display = display;
@ -158,7 +159,8 @@
};
ns.FramesListController.prototype.createPreviews_ = function () {
this.container.html('');
this.previewList.innerHTML = '';
// Manually remove tooltips since mouseout events were shortcut by the DOM refresh:
$('.tooltip').remove();
@ -166,7 +168,7 @@
for (var i = 0 ; i < frameCount ; i++) {
var tile = this.createPreviewTile_(i);
this.container.append(tile);
this.previewList.appendChild(tile);
this.tiles[i] = tile;
}
// Append 'new empty frame' button
@ -176,7 +178,7 @@
newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME);
newFrameButton.innerHTML = '<div class="add-frame-action-icon icon-frame-plus-white">' +
'</div><div class="label">Add new frame</div>';
this.container.append(newFrameButton);
this.previewList.appendChild(newFrameButton);
this.addFrameTile = newFrameButton;
this.updateScrollerOverflows();
@ -186,8 +188,7 @@
* @private
*/
ns.FramesListController.prototype.initDragndropBehavior_ = function () {
$('#preview-list').sortable({
$(this.previewList).sortable({
placeholder: 'preview-tile preview-tile-drop-proxy',
update: $.proxy(this.onUpdate_, this),
stop: $.proxy(this.onSortableStop_, this),
@ -195,7 +196,7 @@
axis: 'y',
tolerance: 'pointer'
});
$('#preview-list').disableSelection();
$(this.previewList).disableSelection();
};
/**

View File

@ -31,7 +31,7 @@
}
if (this.piskelName_) {
this.piskelName_.innerHTML = name;
this.piskelName_.textContent = name;
}
} catch (e) {
console.warn('Could not update header : ' + e.message);

View File

@ -27,15 +27,21 @@
};
ns.LayersListController.prototype.renderLayerList_ = function () {
// Backup scroll before refresh.
var scrollTop = this.layersListEl.scrollTop;
this.layersListEl.innerHTML = '';
var layers = this.piskelController.getLayers();
layers.forEach(this.addLayerItem.bind(this));
this.updateButtonStatus_();
// Restore scroll
this.layersListEl.scrollTop = scrollTop;
// Ensure the currently the selected layer is visible.
var currentLayerEl = this.layersListEl.querySelector('.current-layer-item');
if (currentLayerEl) {
currentLayerEl.scrollIntoView({behavior: 'smooth'});
currentLayerEl.scrollIntoViewIfNeeded(false);
}
};

View File

@ -100,7 +100,7 @@
ns.PalettesListController.prototype.getCurrentColorIndex_ = function () {
var currentIndex = 0;
var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME);
if (selectedColor) {
if (selectedColor) {
currentIndex = parseInt(selectedColor.dataset.colorIndex, 10);
}
return currentIndex;

View File

@ -38,7 +38,11 @@
var isWarningDisplayed = this.performanceLinkEl.classList.contains('visible');
// Show/hide the performance warning link depending on the received report.
this.performanceLinkEl.classList.toggle('visible', shouldDisplayWarning);
if (shouldDisplayWarning) {
this.performanceLinkEl.classList.add('visible');
} else {
this.performanceLinkEl.classList.remove('visible');
}
// Show a notification message if the new report indicates a performance issue
// and we were not displaying a warning before.

View File

@ -48,7 +48,10 @@
keys.forEach((function (key) {
var date = pskl.utils.DateUtils.format(key.date, '{{Y}}/{{M}}/{{D}} {{H}}:{{m}}');
html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date});
html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {
name : key.name,
date : date
});
}).bind(this));
var tableBody_ = this.piskelList.get(0).tBodies[0];

View File

@ -152,10 +152,10 @@
key = key.replace('ctrl', 'cmd');
key = key.replace('alt', 'option');
}
key = key.replace(/left/i, '&#65513;');
key = key.replace(/up/i, '&#65514;');
key = key.replace(/right/i, '&#65515;');
key = key.replace(/down/i, '&#65516;');
key = key.replace(/left/i, '&larr;');
key = key.replace(/up/i, '&uarr;');
key = key.replace(/right/i, '&rarr;');
key = key.replace(/down/i, '&darr;');
key = key.replace(/>/g, '&gt;');
key = key.replace(/</g, '&lt;');
// add spaces around '+' delimiters

View File

@ -135,7 +135,7 @@
this.importedImage_.onload = function () {};
var fileName = this.extractFileNameFromPath_(this.file_.name);
this.fileNameContainer.html(fileName);
this.fileNameContainer.text(fileName);
this.fileNameContainer.attr('title', fileName);
this.resizeWidth.val(w);

View File

@ -270,12 +270,16 @@
};
ns.PiskelController.prototype.removeLayerAt = function (index) {
if (this.getLayers().length > 1) {
var layer = this.getLayerAt(index);
if (layer) {
this.piskel.removeLayer(layer);
this.setCurrentLayerIndex(0);
}
if (!this.hasLayerAt(index)) {
return;
}
var layer = this.getLayerAt(index);
this.piskel.removeLayer(layer);
// Update the selected layer if needed.
if (this.getCurrentLayerIndex() === index) {
this.setCurrentLayerIndex(Math.max(0, index - 1));
}
};

View File

@ -124,7 +124,13 @@
if (this.previewSizes.hasOwnProperty(size)) {
var previewSize = this.previewSizes[size];
var isSizeEnabled = validSizes.indexOf(size) != -1;
previewSize.button.classList.toggle('preview-contextual-action-hidden', !isSizeEnabled);
// classList.toggle is not available on IE11.
if (isSizeEnabled) {
previewSize.button.classList.remove('preview-contextual-action-hidden');
} else {
previewSize.button.classList.add('preview-contextual-action-hidden');
}
}
}
@ -174,7 +180,13 @@
ns.PreviewController.prototype.updateOnionSkinPreview_ = function () {
var enabledClassname = 'preview-toggle-onion-skin-enabled';
var isEnabled = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
this.toggleOnionSkinButton.classList.toggle(enabledClassname, isEnabled);
// classList.toggle is not available on IE11.
if (isEnabled) {
this.toggleOnionSkinButton.classList.add(enabledClassname);
} else {
this.toggleOnionSkinButton.classList.remove(enabledClassname);
}
};
ns.PreviewController.prototype.selectPreviewSizeButton_ = function () {

View File

@ -87,7 +87,7 @@
if (background) {
pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, background);
var selected = this.backgroundContainer.querySelector('.selected');
if (selected) {
if (selected) {
selected.classList.remove('selected');
}
target.classList.add('selected');

View File

@ -62,7 +62,7 @@
ns.SaveController.prototype.insertSavePartials_ = function () {
this.getPartials_().forEach(function (partial) {
pskl.utils.Template.insert(this.saveForm, 'beforeend', partial);
this.saveForm.insertAdjacentHTML('beforeend', pskl.utils.Template.get(partial));
}.bind(this));
};

View File

@ -0,0 +1,27 @@
if (!Element.prototype.scrollIntoViewIfNeeded) {
Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {
centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded;
var parent = this.parentNode,
parentComputedStyle = window.getComputedStyle(parent, null),
parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
alignWithTop = overTop && !overBottom;
if ((overTop || overBottom) && centerIfNeeded) {
parent.scrollTop = this.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + this.clientHeight / 2;
}
if ((overLeft || overRight) && centerIfNeeded) {
parent.scrollLeft = this.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + this.clientWidth / 2;
}
if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
this.scrollIntoView(alignWithTop);
}
};
}

View File

@ -6,15 +6,38 @@
};
ns.BeforeUnloadService.prototype.init = function () {
if (pskl.utils.Environment.detectNodeWebkit()) {
// Add a dedicated listener to window 'close' event in nwjs environment.
var win = require('nw.gui').Window.get();
win.on('close', this.onNwWindowClose.bind(this, win));
}
window.addEventListener('beforeunload', this.onBeforeUnload.bind(this));
};
/**
* In nw.js environment "onbeforeunload" is not triggered when closing the window.
* Polyfill the behavior here.
*/
ns.BeforeUnloadService.prototype.onNwWindowClose = function (win) {
var msg = this.onBeforeUnload();
if (msg) {
if (!window.confirm(msg)) {
return false;
}
}
win.close(true);
};
ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) {
pskl.app.backupService.backup();
if (pskl.app.savedStatusService.isDirty()) {
var confirmationMessage = 'Your Piskel seems to have unsaved changes';
(evt || window.event).returnValue = confirmationMessage;
evt = evt || window.event;
if (evt) {
evt.returnValue = confirmationMessage;
}
return confirmationMessage;
}
};

View File

@ -82,4 +82,12 @@
ns.BaseTool.prototype.releaseToolAt = function (col, row, frame, overlay, event) {};
/**
* Does the tool support the ALT modifier. To be overridden by subclasses.
*
* @return {Boolean} true if the tool supports ALT.
*/
ns.BaseTool.prototype.supportsAlt = function () {
return false;
};
})();

View File

@ -102,4 +102,8 @@
this.shiftFrame(replayData.colDiff, replayData.rowDiff, frame, frame.clone(), event);
}.bind(this));
};
ns.Move.prototype.supportsAlt = function() {
return true;
};
})();

View File

@ -16,23 +16,12 @@
},
createFromHTML : function (html) {
var dummyEl = document.createElement('div');
var dummyEl = ns.Template._getDummyEl();
dummyEl.innerHTML = html;
return dummyEl.children[0];
},
var element = dummyEl.children[0];
dummyEl.innerHTML = '';
insert : function (parent, position, templateId, dict) {
var html = pskl.utils.Template.getAndReplace(templateId, dict);
parent.insertAdjacentHTML(position, html);
},
getAndReplace : function (templateId, dict) {
var result = '';
var tpl = pskl.utils.Template.get(templateId);
if (tpl) {
result = pskl.utils.Template.replace(tpl, dict);
}
return result;
return element;
},
replace : function (template, dict) {
@ -49,10 +38,38 @@
value = '';
}
}
// Sanitize all values expect if the key is surrounded by `!`
if (!/^!.*!$/.test(key)) {
value = ns.Template.sanitize(value);
}
template = template.replace(new RegExp('\\{\\{' + key + '\\}\\}', 'g'), value);
}
}
return template;
},
/**
* Sanitize the provided string to make it safer for using in templates.
*/
sanitize : function (string) {
var dummyEl = ns.Template._getDummyEl();
// Apply the unsafe string as text content and
dummyEl.textContent = string;
var sanitizedString = dummyEl.innerHTML;
dummyEl.innerHTML = '';
return sanitizedString;
},
_getDummyEl : function () {
if (!ns.Template._dummyEl) {
ns.Template._dummyEl = document.createElement('div');
}
return ns.Template._dummyEl;
}
};
})();

View File

@ -9,7 +9,8 @@
return pskl.utils.Template.replace(tpl, {
helptext : helpText,
shortcut : shortcut,
descriptors : this.formatDescriptors_(descriptors)
// Avoid sanitization for descriptors (markup)
'!descriptors!' : this.formatDescriptors_(descriptors)
});
};

View File

@ -56,22 +56,22 @@
// Prepare a frames array to store frame objects extracted from the chunks.
var frames = [];
Promise.all(chunks.map(function (chunk) {
Q.all(chunks.map(function (chunk) {
// Create a promise for each chunk.
return new Promise(function (resolve, reject) {
var image = new Image();
// Load the chunk image in an Image object.
image.onload = function () {
// extract the chunkFrames from the chunk image
var chunkFrames = pskl.utils.FrameUtils.createFramesFromChunk(image, chunk.layout);
// add each image to the frames array, at the extracted index
chunkFrames.forEach(function (chunkFrame) {
frames[chunkFrame.index] = chunkFrame.frame;
});
resolve();
};
image.src = chunk.base64PNG;
});
var deferred = Q.defer();
var image = new Image();
// Load the chunk image in an Image object.
image.onload = function () {
// extract the chunkFrames from the chunk image
var chunkFrames = pskl.utils.FrameUtils.createFramesFromChunk(image, chunk.layout);
// add each image to the frames array, at the extracted index
chunkFrames.forEach(function (chunkFrame) {
frames[chunkFrame.index] = chunkFrame.frame;
});
deferred.resolve();
};
image.src = chunk.base64PNG;
return deferred.promise;
})).then(function () {
frames.forEach(layer.addFrame.bind(layer));
this.layers_[index] = layer;

View File

@ -54,6 +54,7 @@
// JSZip https://github.com/Stuk/jszip
"js/lib/jszip/jszip.min.js",
"js/lib/scrollifneeded/scrollifneeded.js",
// Smoothscroll: https://github.com/iamdustan/smoothscroll
"js/lib/smoothscroll/smoothscroll.js",

View File

@ -11,7 +11,7 @@
<script type="text/template" id="tooltip-container-template">
<div class='tooltip-container'>
<div>{{helptext}} <span class='tooltip-shortcut'>{{shortcut}}</span></div>
{{descriptors}}
{{!descriptors!}}
</div>
</script>