mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Compare commits
21 Commits
v0.10.0
...
greenkeepe
Author | SHA1 | Date | |
---|---|---|---|
5e46d8b7e2 | |||
e15d7b2422 | |||
a8c85b8a29 | |||
89199f2d6a | |||
98768b2e5b | |||
62b1b8baf0 | |||
11a063de12 | |||
6f4413f353 | |||
974450837e | |||
c6c64af2fd | |||
c68b82339c | |||
099ff80155 | |||
f30e16386d | |||
08b97cb6f0 | |||
b6fa769ba1 | |||
47b09b10c5 | |||
f039a89572 | |||
e74329f04e | |||
8959b201e9 | |||
f5491dc557 | |||
9ce3d44cc6 |
25
.codeclimate.yml
Normal file
25
.codeclimate.yml
Normal 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/
|
@ -1,6 +1,8 @@
|
||||
Piskel
|
||||
======
|
||||
|
||||
[](https://greenkeeper.io/)
|
||||
|
||||
[](https://travis-ci.org/juliandescottes/piskel) [](http://gruntjs.com/)
|
||||
|
||||
A simple web-based tool for Spriting and Pixel art.
|
||||
|
28
package.json
28
package.json
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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];
|
||||
|
@ -152,10 +152,10 @@
|
||||
key = key.replace('ctrl', 'cmd');
|
||||
key = key.replace('alt', 'option');
|
||||
}
|
||||
key = key.replace(/left/i, '←');
|
||||
key = key.replace(/up/i, '↑');
|
||||
key = key.replace(/right/i, '→');
|
||||
key = key.replace(/down/i, '↓');
|
||||
key = key.replace(/left/i, '←');
|
||||
key = key.replace(/up/i, '↑');
|
||||
key = key.replace(/right/i, '→');
|
||||
key = key.replace(/down/i, '↓');
|
||||
key = key.replace(/>/g, '>');
|
||||
key = key.replace(/</g, '<');
|
||||
// add spaces around '+' delimiters
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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 () {
|
||||
|
@ -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');
|
||||
|
@ -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));
|
||||
};
|
||||
|
||||
|
27
src/js/lib/scrollifneeded/scrollifneeded.js
Normal file
27
src/js/lib/scrollifneeded/scrollifneeded.js
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
})();
|
||||
|
@ -102,4 +102,8 @@
|
||||
this.shiftFrame(replayData.colDiff, replayData.rowDiff, frame, frame.clone(), event);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ns.Move.prototype.supportsAlt = function() {
|
||||
return true;
|
||||
};
|
||||
})();
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -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)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
Reference in New Issue
Block a user