Merge pull request #334 from juliandescottes/add-custom-shortcuts
Close #287
This commit is contained in:
commit
0dff1f7a9a
60 changed files with 1290 additions and 537 deletions
3
src/css/animations.css
Normal file
3
src/css/animations.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
@keyframes fade {
|
||||
50% { opacity: 0.5; }
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
.cheatsheet-link {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
|
||||
padding: 1px 0 0 45px;
|
||||
color : gold;
|
||||
font-weight: bold;
|
||||
font-size : 1.25em;
|
||||
line-height: 20px;
|
||||
|
||||
cursor : pointer;
|
||||
|
||||
background-image:url('../img/keyboard.png');
|
||||
background-size:35px 20px;
|
||||
background-repeat:no-repeat;
|
||||
opacity: 0.5;
|
||||
z-index: 11000;
|
||||
transition : opacity 0.3s;
|
||||
}
|
||||
|
||||
.cheatsheet-link:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#cheatsheet-wrapper {
|
||||
position: absolute;
|
||||
z-index: 10000;
|
||||
|
||||
top: 50px;
|
||||
right: 50px;
|
||||
bottom: 50px;
|
||||
left: 50px;
|
||||
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing : border-box;
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cheatsheet-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing : border-box;
|
||||
|
||||
padding: 20px 3%;
|
||||
border-radius: 3px;
|
||||
background: rgba(0,0,0,0.9);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cheatsheet-container .cheatsheet-title {
|
||||
font-size:24px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.cheatsheet-container .cheatsheet-title:nth-of-type(2) {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.cheatsheet-section {
|
||||
float: left;
|
||||
width : 33%;
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut {
|
||||
overflow: hidden;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.cheatsheet-icon.tool-icon {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: 0 20px 0 0;
|
||||
|
||||
background-size: 20px 20px;
|
||||
background-position: 5px 5px;
|
||||
}
|
||||
|
||||
.cheatsheet-description {
|
||||
font-family:Courier;
|
||||
color: white;
|
||||
font-size : 13px;
|
||||
margin-left: 20px;
|
||||
line-height : 30px;
|
||||
}
|
||||
|
||||
.cheatsheet-key {
|
||||
display : inline-block;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 10px;
|
||||
|
||||
border : 1px solid gold;
|
||||
border-radius: 2px;
|
||||
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing : border-box;
|
||||
|
||||
text-align: center;
|
||||
font-family:Courier;
|
||||
font-weight: bold;
|
||||
font-size : 18px;
|
||||
color: gold;
|
||||
}
|
173
src/css/dialogs-cheatsheet.css
Normal file
173
src/css/dialogs-cheatsheet.css
Normal file
|
@ -0,0 +1,173 @@
|
|||
.cheatsheet-link {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
|
||||
padding: 1px 0 0 45px;
|
||||
color : gold;
|
||||
font-weight: bold;
|
||||
font-size : 1.25em;
|
||||
line-height: 20px;
|
||||
|
||||
cursor : pointer;
|
||||
|
||||
background-image:url('../img/keyboard.png');
|
||||
background-size:35px 20px;
|
||||
background-repeat:no-repeat;
|
||||
|
||||
opacity: 0.5;
|
||||
z-index: 11000;
|
||||
transition : opacity 0.3s;
|
||||
}
|
||||
|
||||
.cheatsheet-link:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cheatsheet-container {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
|
||||
bottom: 46px;
|
||||
padding: 20px 3%;
|
||||
border-radius: 3px;
|
||||
background-color: rgba(0,0,0,0.9);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cheatsheet-container .cheatsheet-title {
|
||||
font-size:24px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.cheatsheet-container .cheatsheet-title:nth-of-type(1) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.cheatsheet-section {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
|
||||
vertical-align: top;
|
||||
padding : 0 20px 20px 20px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.cheatsheet-boxes {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
float: left;
|
||||
}
|
||||
|
||||
@media (min-width: 1300px) {
|
||||
.cheatsheet-container > div {
|
||||
width: 33%;
|
||||
}
|
||||
.cheatsheet-boxes {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut {
|
||||
overflow: hidden;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.cheatsheet-icon.tool-icon {
|
||||
float: left;
|
||||
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: 0 10px 0 0;
|
||||
|
||||
background-size: 20px 20px;
|
||||
background-position: 5px 5px;
|
||||
}
|
||||
|
||||
.cheatsheet-description {
|
||||
color: white;
|
||||
font-size : 14px;
|
||||
margin-left: 10px;
|
||||
line-height : 30px;
|
||||
}
|
||||
|
||||
.cheatsheet-key {
|
||||
box-sizing: border-box;
|
||||
display : inline-block;
|
||||
height: 30px;
|
||||
line-height: 26px;
|
||||
padding: 0 10px;
|
||||
|
||||
border : 2px solid white;
|
||||
border-radius: 2px;
|
||||
|
||||
text-align: center;
|
||||
font-family:Courier;
|
||||
font-weight: bold;
|
||||
font-size : 18px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cheatsheet-shorcut-conflict .cheatsheet-key {
|
||||
border-color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut-editable {
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut-editable .cheatsheet-key {
|
||||
border-color: gold;
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut-editing .cheatsheet-key {
|
||||
animation: fade .5s infinite;
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut-undefined .cheatsheet-key {
|
||||
border-color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
/*Cheatsheet actions*/
|
||||
|
||||
.cheatsheet-actions {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
|
||||
bottom : 0;
|
||||
left : 0;
|
||||
right : 0;
|
||||
height : 46px;
|
||||
|
||||
padding : 10px;
|
||||
overflow: hidden;
|
||||
|
||||
background-color : gold;
|
||||
}
|
||||
|
||||
.cheatsheet-helptext {
|
||||
font-size: 14px;
|
||||
height : 26px;
|
||||
line-height : 26px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.cheatsheet-helptext-tooltip {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cheatsheet-helptext-tooltip-item {
|
||||
line-height: 0.9em;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.cheatsheet-button {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
|
@ -44,10 +44,6 @@
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.animated #dialog-container {
|
||||
transition:margin-top 0.2s;
|
||||
}
|
||||
|
||||
.show #dialog-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
@ -70,6 +66,14 @@
|
|||
position : relative;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
position: absolute;
|
||||
top: 45px;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dialog-head {
|
||||
width: 100%;
|
||||
background: gold;
|
||||
|
@ -77,6 +81,7 @@
|
|||
padding: 10px;
|
||||
color: black;
|
||||
font-size: 1.8em;
|
||||
height: 45px;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
border-radius: 0 0 0 2px;
|
||||
}
|
||||
|
||||
|
||||
.palettes-list-color:nth-child(1):after {
|
||||
content: "1";
|
||||
}
|
||||
|
@ -64,6 +63,7 @@
|
|||
.palettes-list-color:nth-child(-n+5) {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.palettes-list-color div {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
|
|
@ -90,13 +90,15 @@
|
|||
<iframe src="templates/dialogs/create-palette.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/dialogs/import-image.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/dialogs/browse-local.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/dialogs/cheatsheet.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<iframe src="templates/cheatsheet.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
|
||||
<iframe src="templates/misc-templates.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
|
||||
<iframe src="templates/popup-preview.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
|
||||
|
||||
<span class="cheatsheet-link" rel="tooltip" data-placement="right" title="Keyboard shortcuts"> </span>
|
||||
|
||||
<script type="text/javascript" src="piskel-boot.js"></script>
|
||||
<!--body-main-end-->
|
||||
<!-- the comment above indicates the end of the markup reused by the editor integrated in piskelapp.com -->
|
||||
|
|
|
@ -27,6 +27,7 @@ var Events = {
|
|||
* 2nd argument: New value
|
||||
*/
|
||||
USER_SETTINGS_CHANGED: 'USER_SETTINGS_CHANGED',
|
||||
SHORTCUTS_CHANGED: 'SHORTCUTS_CHANGED',
|
||||
|
||||
CLOSE_SETTINGS_DRAWER : 'CLOSE_SETTINGS_DRAWER',
|
||||
|
||||
|
|
|
@ -127,9 +127,6 @@
|
|||
this.imageUploadService = new pskl.service.ImageUploadService();
|
||||
this.imageUploadService.init();
|
||||
|
||||
this.cheatsheetService = new pskl.service.keyboard.CheatsheetService();
|
||||
this.cheatsheetService.init();
|
||||
|
||||
this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController);
|
||||
this.savedStatusService.init();
|
||||
|
||||
|
|
|
@ -62,9 +62,10 @@
|
|||
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
|
||||
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
|
||||
|
||||
pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1));
|
||||
pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.RESET_ZOOM, this.resetZoom_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.INCREASE_ZOOM, this.increaseZoom_.bind(this, 1));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.DECREASE_ZOOM, this.decreaseZoom_.bind(this, 1));
|
||||
|
||||
window.setTimeout(function () {
|
||||
this.afterWindowResize_();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
ns.LayersListController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
this.layerPreviewShortcut = pskl.service.keyboard.Shortcuts.MISC.LAYER_PREVIEW ;
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.init = function () {
|
||||
|
@ -36,10 +37,9 @@
|
|||
var descriptors = [{description : 'Opacity defined in PREFERENCES'}];
|
||||
var helpText = 'Preview all layers';
|
||||
|
||||
var toggleLayerPreviewTooltip = pskl.utils.TooltipFormatter.format(helpText, TOGGLE_LAYER_SHORTCUT, descriptors);
|
||||
this.toggleLayerPreviewEl.setAttribute('title', toggleLayerPreviewTooltip);
|
||||
|
||||
pskl.app.shortcutService.addShortcut(TOGGLE_LAYER_SHORTCUT, this.toggleLayerPreview_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(this.layerPreviewShortcut, this.toggleLayerPreview_.bind(this));
|
||||
var tooltip = pskl.utils.TooltipFormatter.format(helpText, this.layerPreviewShortcut, descriptors);
|
||||
this.toggleLayerPreviewEl.setAttribute('title', tooltip);
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.updateButtonStatus_ = function () {
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
document.body.appendChild(message);
|
||||
|
||||
message.querySelector('.close').addEventListener('click', this.removeMessage_.bind(this));
|
||||
if (messageInfo.behavior) {
|
||||
messageInfo.behavior(message);
|
||||
}
|
||||
|
||||
if (messageInfo.hideDelay) {
|
||||
window.setTimeout(this.removeMessage_.bind(this), messageInfo.hideDelay);
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
$.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true}));
|
||||
$.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false}));
|
||||
|
||||
pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.SWAP, this.swapColors.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.RESET, this.resetColors.bind(this));
|
||||
|
||||
var spectrumCfg = {
|
||||
showPalette: true,
|
||||
|
|
|
@ -37,9 +37,10 @@
|
|||
$.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
|
||||
|
||||
pskl.app.shortcutService.addShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('<', this.selectPreviousColor_.bind(this));
|
||||
pskl.app.shortcutService.addShortcuts('123465789'.split(''), this.selectColorForKey_.bind(this));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.PREVIOUS_COLOR, this.selectPreviousColor_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.NEXT_COLOR, this.selectNextColor_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.SELECT_COLOR, this.selectColorForKey_.bind(this));
|
||||
|
||||
this.fillPaletteList();
|
||||
this.updateFromUserSettings();
|
||||
|
@ -151,7 +152,9 @@
|
|||
};
|
||||
|
||||
ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) {
|
||||
$.publish(Events.DIALOG_DISPLAY, 'create-palette');
|
||||
$.publish(Events.DIALOG_DISPLAY, {
|
||||
dialogId : 'create-palette'
|
||||
});
|
||||
};
|
||||
|
||||
ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) {
|
||||
|
|
|
@ -2,29 +2,26 @@
|
|||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
ns.ToolController = function () {
|
||||
var toDescriptor = function (id, shortcut, instance) {
|
||||
return {id:id, shortcut:shortcut, instance:instance};
|
||||
};
|
||||
|
||||
this.tools = [
|
||||
toDescriptor('simplePen', 'P', new pskl.tools.drawing.SimplePen()),
|
||||
toDescriptor('verticalMirrorPen', 'V', new pskl.tools.drawing.VerticalMirrorPen()),
|
||||
toDescriptor('paintBucket', 'B', new pskl.tools.drawing.PaintBucket()),
|
||||
toDescriptor('colorSwap', 'A', new pskl.tools.drawing.ColorSwap()),
|
||||
toDescriptor('eraser', 'E', new pskl.tools.drawing.Eraser()),
|
||||
toDescriptor('stroke', 'L', new pskl.tools.drawing.Stroke()),
|
||||
toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()),
|
||||
toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()),
|
||||
toDescriptor('move', 'M', new pskl.tools.drawing.Move()),
|
||||
toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.selection.ShapeSelect()),
|
||||
toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.selection.RectangleSelect()),
|
||||
toDescriptor('lassoSelect', 'H', new pskl.tools.drawing.selection.LassoSelect()),
|
||||
toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()),
|
||||
toDescriptor('dithering', 'T', new pskl.tools.drawing.DitheringTool()),
|
||||
toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker())
|
||||
new pskl.tools.drawing.SimplePen(),
|
||||
new pskl.tools.drawing.VerticalMirrorPen(),
|
||||
new pskl.tools.drawing.PaintBucket(),
|
||||
new pskl.tools.drawing.ColorSwap(),
|
||||
new pskl.tools.drawing.Eraser(),
|
||||
new pskl.tools.drawing.Stroke(),
|
||||
new pskl.tools.drawing.Rectangle(),
|
||||
new pskl.tools.drawing.Circle(),
|
||||
new pskl.tools.drawing.Move(),
|
||||
new pskl.tools.drawing.selection.ShapeSelect(),
|
||||
new pskl.tools.drawing.selection.RectangleSelect(),
|
||||
new pskl.tools.drawing.selection.LassoSelect(),
|
||||
new pskl.tools.drawing.Lighten(),
|
||||
new pskl.tools.drawing.DitheringTool(),
|
||||
new pskl.tools.drawing.ColorPicker()
|
||||
];
|
||||
|
||||
this.toolIconRenderer = new pskl.tools.IconMarkupRenderer();
|
||||
this.iconMarkupRenderer = new pskl.tools.IconMarkupRenderer();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -41,6 +38,7 @@
|
|||
$('#tool-section').mousedown($.proxy(this.onToolIconClicked_, this));
|
||||
|
||||
$.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this));
|
||||
$.subscribe(Events.SHORTCUTS_CHANGED, this.createToolsDom_.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -53,8 +51,8 @@
|
|||
stage.removeClass(previousSelectedToolClass);
|
||||
stage.removeClass(pskl.tools.drawing.Move.TOOL_ID);
|
||||
}
|
||||
stage.addClass(tool.instance.toolId);
|
||||
stage.data('selected-tool-class', tool.instance.toolId);
|
||||
stage.addClass(tool.toolId);
|
||||
stage.data('selected-tool-class', tool.toolId);
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) {
|
||||
|
@ -72,12 +70,12 @@
|
|||
this.activateToolOnStage_(this.currentSelectedTool);
|
||||
|
||||
var selectedToolElement = $('#tool-section .tool-icon.selected');
|
||||
var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']');
|
||||
var toolElement = $('[data-tool-id=' + tool.toolId + ']');
|
||||
|
||||
selectedToolElement.removeClass('selected');
|
||||
toolElement.addClass('selected');
|
||||
|
||||
$.publish(Events.TOOL_SELECTED, [tool.instance]);
|
||||
$.publish(Events.TOOL_SELECTED, [tool]);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -96,18 +94,16 @@
|
|||
}
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) {
|
||||
for (var i = 0 ; i < this.tools.length ; i++) {
|
||||
var tool = this.tools[i];
|
||||
if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) {
|
||||
this.selectTool_(tool);
|
||||
}
|
||||
ns.ToolController.prototype.onKeyboardShortcut_ = function(toolId, charkey) {
|
||||
var tool = this.getToolById_(toolId);
|
||||
if (tool !== null) {
|
||||
this.selectTool_(tool);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.getToolById_ = function (toolId) {
|
||||
return pskl.utils.Array.find(this.tools, function (tool) {
|
||||
return tool.instance.toolId == toolId;
|
||||
return tool.toolId == toolId;
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -118,14 +114,15 @@
|
|||
var html = '';
|
||||
for (var i = 0 ; i < this.tools.length ; i++) {
|
||||
var tool = this.tools[i];
|
||||
html += this.toolIconRenderer.render(tool.instance, tool.shortcut);
|
||||
html += this.iconMarkupRenderer.render(tool);
|
||||
}
|
||||
$('#tools-container').html(html);
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.addKeyboardShortcuts_ = function () {
|
||||
for (var i = 0 ; i < this.tools.length ; i++) {
|
||||
pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this));
|
||||
var tool = this.tools[i];
|
||||
pskl.app.shortcutService.registerShortcut(tool.shortcut, this.onKeyboardShortcut_.bind(this, tool.toolId));
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -2,15 +2,10 @@
|
|||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
ns.TransformationsController = function () {
|
||||
|
||||
var toDescriptor = function (id, shortcut, instance) {
|
||||
return {id:id, shortcut:shortcut, instance:instance};
|
||||
};
|
||||
|
||||
this.tools = [
|
||||
toDescriptor('flip', '', new pskl.tools.transform.Flip()),
|
||||
toDescriptor('rotate', '', new pskl.tools.transform.Rotate()),
|
||||
toDescriptor('clone', '', new pskl.tools.transform.Clone())
|
||||
new pskl.tools.transform.Flip(),
|
||||
new pskl.tools.transform.Rotate(),
|
||||
new pskl.tools.transform.Clone()
|
||||
];
|
||||
|
||||
this.toolIconRenderer = new pskl.tools.IconMarkupRenderer();
|
||||
|
@ -25,9 +20,9 @@
|
|||
|
||||
ns.TransformationsController.prototype.applyTool = function (toolId, evt) {
|
||||
this.tools.forEach(function (tool) {
|
||||
if (tool.instance.toolId === toolId) {
|
||||
if (tool.toolId === toolId) {
|
||||
$.publish(Events.TRANSFORMATION_EVENT, [toolId, evt]);
|
||||
tool.instance.apply(evt);
|
||||
tool.applyTransformation(evt);
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
@ -39,7 +34,7 @@
|
|||
|
||||
ns.TransformationsController.prototype.createToolsDom_ = function() {
|
||||
var html = this.tools.reduce(function (p, tool) {
|
||||
return p + this.toolIconRenderer.render(tool.instance, tool.shortcut, 'left');
|
||||
return p + this.toolIconRenderer.render(tool, tool.shortcut, 'left');
|
||||
}.bind(this), '');
|
||||
this.toolsContainer.innerHTML = html;
|
||||
};
|
||||
|
|
173
src/js/controller/dialogs/CheatsheetController.js
Normal file
173
src/js/controller/dialogs/CheatsheetController.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
|
||||
var SHORTCUT_EDITING_CLASSNAME = 'cheatsheet-shortcut-editing';
|
||||
|
||||
ns.CheatsheetController = function () {};
|
||||
|
||||
pskl.utils.inherit(ns.CheatsheetController, ns.AbstractDialogController);
|
||||
|
||||
ns.CheatsheetController.prototype.init = function () {
|
||||
this.superclass.init.call(this);
|
||||
|
||||
this.cheatsheetEl = document.getElementById('cheatsheetContainer');
|
||||
this.eventTrapInput = document.getElementById('cheatsheetEventTrap');
|
||||
|
||||
pskl.utils.Event.addEventListener('.cheatsheet-restore-defaults', 'click', this.onRestoreDefaultsClick_, this);
|
||||
pskl.utils.Event.addEventListener(this.cheatsheetEl, 'click', this.onCheatsheetClick_, this);
|
||||
pskl.utils.Event.addEventListener(this.eventTrapInput, 'keydown', this.onEventTrapKeydown_, this);
|
||||
|
||||
$.subscribe(Events.SHORTCUTS_CHANGED, this.onShortcutsChanged_.bind(this));
|
||||
|
||||
this.initMarkup_();
|
||||
document.querySelector('.cheatsheet-helptext').setAttribute('title', this.getHelptextTitle_());
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.destroy = function () {
|
||||
this.eventTrapInput.blur();
|
||||
pskl.utils.Event.removeAllEventListeners();
|
||||
this.cheatsheetEl = null;
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.onRestoreDefaultsClick_ = function () {
|
||||
if (window.confirm('Replace all custom shortcuts by the default Piskel shortcuts ?')) {
|
||||
pskl.app.shortcutService.restoreDefaultShortcuts();
|
||||
}
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.onShortcutsChanged_ = function () {
|
||||
this.initMarkup_();
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.onCheatsheetClick_ = function (evt) {
|
||||
var shortcutEl = pskl.utils.Dom.getParentWithData(evt.target, 'shortcutId');
|
||||
if (!shortcutEl) {
|
||||
pskl.utils.Dom.removeClass(SHORTCUT_EDITING_CLASSNAME);
|
||||
return;
|
||||
}
|
||||
|
||||
var shortcutId = shortcutEl.dataset.shortcutId;
|
||||
var shortcut = pskl.app.shortcutService.getShortcutById(shortcutId);
|
||||
|
||||
if (shortcutEl.classList.contains(SHORTCUT_EDITING_CLASSNAME)) {
|
||||
shortcutEl.classList.remove(SHORTCUT_EDITING_CLASSNAME);
|
||||
this.eventTrapInput.blur();
|
||||
} else if (shortcut.isEditable()) {
|
||||
shortcutEl.classList.add(SHORTCUT_EDITING_CLASSNAME);
|
||||
this.eventTrapInput.focus();
|
||||
}
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.onEventTrapKeydown_ = function (evt) {
|
||||
var shortcutEl = document.querySelector('.' + SHORTCUT_EDITING_CLASSNAME);
|
||||
if (!shortcutEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
var shortcutId = shortcutEl.dataset.shortcutId;
|
||||
var shortcut = pskl.app.shortcutService.getShortcutById(shortcutId);
|
||||
var shortcutKeyObject = pskl.service.keyboard.KeyUtils.createKeyFromEvent(evt);
|
||||
var shortcutKeyString = pskl.service.keyboard.KeyUtils.stringify(shortcutKeyObject);
|
||||
|
||||
pskl.app.shortcutService.updateShortcut(shortcut, shortcutKeyString);
|
||||
|
||||
shortcutEl.classList.remove(SHORTCUT_EDITING_CLASSNAME);
|
||||
this.eventTrapInput.blur();
|
||||
|
||||
evt.preventDefault();
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.initMarkup_ = function () {
|
||||
this.initMarkupForCategory_('TOOL', '.cheatsheet-tool-shortcuts', this.getToolIconClass_);
|
||||
this.initMarkupForCategory_('MISC', '.cheatsheet-misc-shortcuts');
|
||||
this.initMarkupForCategory_('COLOR', '.cheatsheet-color-shortcuts');
|
||||
this.initMarkupForCategory_('SELECTION', '.cheatsheet-selection-shortcuts');
|
||||
this.initMarkupForCategory_('STORAGE', '.cheatsheet-storage-shortcuts');
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.getToolIconClass_ = function (shortcut) {
|
||||
return 'tool-icon ' + shortcut.getId();
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.initMarkupForCategory_ = function (category, container, iconClassProvider) {
|
||||
var shortcutMap = pskl.service.keyboard.Shortcuts[category];
|
||||
|
||||
var descriptors = Object.keys(shortcutMap).map(function (shortcutKey) {
|
||||
return this.toDescriptor_(shortcutMap[shortcutKey], iconClassProvider);
|
||||
}.bind(this));
|
||||
|
||||
this.initMarkupForDescriptors_(descriptors, container);
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.toDescriptor_ = function (shortcut, iconClassProvider) {
|
||||
var iconClass = typeof iconClassProvider == 'function' ? iconClassProvider(shortcut) : '';
|
||||
return {
|
||||
'shortcut' : shortcut,
|
||||
'iconClass' : iconClass
|
||||
};
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.initMarkupForDescriptors_ = function (descriptors, containerSelector) {
|
||||
var container = document.querySelector(containerSelector);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
var markupArray = descriptors.map(this.getMarkupForDescriptor_.bind(this));
|
||||
container.innerHTML = markupArray.join('');
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.getMarkupForDescriptor_ = function (descriptor) {
|
||||
var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template');
|
||||
var shortcut = descriptor.shortcut;
|
||||
var description = shortcut.isCustom() ? shortcut.getDescription() + ' *' : shortcut.getDescription();
|
||||
|
||||
var shortcutClasses = [];
|
||||
if (shortcut.isUndefined()) {
|
||||
shortcutClasses.push('cheatsheet-shortcut-undefined');
|
||||
}
|
||||
if (shortcut.isEditable()) {
|
||||
shortcutClasses.push('cheatsheet-shortcut-editable');
|
||||
}
|
||||
|
||||
var title = shortcut.isEditable() ? 'Click to edit the key' : 'Shortcut cannot be remapped';
|
||||
|
||||
var markup = pskl.utils.Template.replace(shortcutTemplate, {
|
||||
id : shortcut.getId(),
|
||||
title : title,
|
||||
icon : descriptor.iconClass,
|
||||
description : description,
|
||||
key : this.formatKey_(shortcut.getDisplayKey()),
|
||||
className : shortcutClasses.join(' ')
|
||||
});
|
||||
|
||||
return markup;
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.formatKey_ = function (key) {
|
||||
if (pskl.utils.UserAgent.isMac) {
|
||||
key = key.replace('ctrl', 'cmd');
|
||||
}
|
||||
key = key.replace(/up/i, '↑');
|
||||
key = key.replace(/down/i, '↓');
|
||||
key = key.replace(/>/g, '>');
|
||||
key = key.replace(/</g, '<');
|
||||
// add spaces around '+' delimiters
|
||||
key = key.replace(/([^ ])\+([^ ])/g, '$1 + $2');
|
||||
return key;
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.getHelptextTitle_ = function () {
|
||||
var helpItems = [
|
||||
'Click on a shortcut to change the key.',
|
||||
'When the shortcut blinks, press the key on your keyboard to assign it.',
|
||||
'White shortcuts can not be edited.',
|
||||
'Click on \'Restore default shortcuts\' to erase all custom shortcuts.'
|
||||
];
|
||||
|
||||
var helptextTitle = helpItems.reduce(function (p, n) {
|
||||
return p + '<div class="cheatsheet-helptext-tooltip-item">' + n + '</div>';
|
||||
}, '');
|
||||
helptextTitle = '<div class="cheatsheet-helptext-tooltip">' + helptextTitle + '</div>';
|
||||
return helptextTitle;
|
||||
};
|
||||
})();
|
|
@ -2,6 +2,10 @@
|
|||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
|
||||
var dialogs = {
|
||||
'cheatsheet' : {
|
||||
template : 'templates/dialogs/cheatsheet.html',
|
||||
controller : ns.CheatsheetController
|
||||
},
|
||||
'create-palette' : {
|
||||
template : 'templates/dialogs/create-palette.html',
|
||||
controller : ns.CreatePaletteController
|
||||
|
@ -18,78 +22,108 @@
|
|||
|
||||
ns.DialogsController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
this.closePopupShortcut = pskl.service.keyboard.Shortcuts.MISC.CLOSE_POPUP;
|
||||
this.currentDialog_ = null;
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.init = function () {
|
||||
this.dialogContainer_ = document.getElementById('dialog-container');
|
||||
this.dialogWrapper_ = document.getElementById('dialog-container-wrapper');
|
||||
|
||||
$.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this));
|
||||
$.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this));
|
||||
$.subscribe(Events.DIALOG_HIDE, this.hideDialog.bind(this));
|
||||
|
||||
pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette'));
|
||||
var createPaletteShortcut = pskl.service.keyboard.Shortcuts.COLOR.CREATE_PALETTE;
|
||||
pskl.app.shortcutService.registerShortcut(createPaletteShortcut, this.onCreatePaletteShortcut_.bind(this));
|
||||
|
||||
var cheatsheetShortcut = pskl.service.keyboard.Shortcuts.MISC.CHEATSHEET;
|
||||
pskl.app.shortcutService.registerShortcut(cheatsheetShortcut, this.onCheatsheetShortcut_.bind(this));
|
||||
pskl.utils.Event.addEventListener('.cheatsheet-link', 'click', this.onCheatsheetShortcut_, this);
|
||||
|
||||
// adding the .animated class here instead of in the markup to avoid an animation during app startup
|
||||
this.dialogWrapper_.classList.add('animated');
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.onCreatePaletteShortcut_ = function () {
|
||||
this.toggleDialog_('create-palette');
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.onCheatsheetShortcut_ = function () {
|
||||
this.toggleDialog_('cheatsheet');
|
||||
};
|
||||
|
||||
/**
|
||||
* If no dialog is currently displayed, the dialog with the provided id will be displayed.
|
||||
* If a dialog is displayed and has the same id as the provided id, hide it.
|
||||
* Otherwise, no-op.
|
||||
*/
|
||||
ns.DialogsController.prototype.toggleDialog_ = function (dialogId) {
|
||||
if (!this.isDisplayingDialog_()) {
|
||||
this.showDialog(dialogId);
|
||||
} else if (this.getCurrentDialogId_() === dialogId) {
|
||||
this.hideDialog();
|
||||
}
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) {
|
||||
var dialogId, initArgs;
|
||||
if (typeof args === 'string') {
|
||||
dialogId = args;
|
||||
} else {
|
||||
dialogId = args.dialogId;
|
||||
initArgs = args.initArgs;
|
||||
}
|
||||
if (!this.isDisplayed()) {
|
||||
var config = dialogs[dialogId];
|
||||
if (config) {
|
||||
this.dialogContainer_.classList.add(dialogId);
|
||||
this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template);
|
||||
|
||||
var controller = new config.controller(this.piskelController);
|
||||
controller.init(initArgs);
|
||||
|
||||
this.showDialogWrapper_();
|
||||
this.currentDialog_ = {
|
||||
id : dialogId,
|
||||
controller : controller
|
||||
};
|
||||
} else {
|
||||
console.error('Could not find dialog configuration for dialogId : ' + dialogId);
|
||||
}
|
||||
}
|
||||
this.showDialog(args.dialogId, args.initArgs);
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.onDialogHideEvent_ = function () {
|
||||
this.hideDialog();
|
||||
};
|
||||
ns.DialogsController.prototype.showDialog = function (dialogId, initArgs) {
|
||||
if (this.isDisplayingDialog_()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ns.DialogsController.prototype.showDialogWrapper_ = function () {
|
||||
pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this));
|
||||
var config = dialogs[dialogId];
|
||||
if (!config) {
|
||||
console.error('Could not find dialog configuration for dialogId : ' + dialogId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialogContainer_.classList.add(dialogId);
|
||||
|
||||
this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template);
|
||||
var controller = new config.controller(this.piskelController);
|
||||
controller.init(initArgs);
|
||||
|
||||
this.currentDialog_ = {
|
||||
id : dialogId,
|
||||
controller : controller
|
||||
};
|
||||
|
||||
pskl.app.shortcutService.registerShortcut(this.closePopupShortcut, this.hideDialog.bind(this));
|
||||
this.dialogWrapper_.classList.add('show');
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.hideDialog = function () {
|
||||
var currentDialog = this.currentDialog_;
|
||||
if (currentDialog) {
|
||||
currentDialog.controller.destroy();
|
||||
var dialogId = this.currentDialog_.id;
|
||||
window.setTimeout(function () {
|
||||
this.dialogContainer_.classList.remove(dialogId);
|
||||
}.bind(this), 800);
|
||||
if (this.isHiding_ || !this.isDisplayingDialog_()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hideDialogWrapper_();
|
||||
this.currentDialog_ = null;
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.hideDialogWrapper_ = function () {
|
||||
pskl.app.shortcutService.removeShortcut('ESC');
|
||||
pskl.app.shortcutService.unregisterShortcut(this.closePopupShortcut);
|
||||
this.dialogWrapper_.classList.remove('show');
|
||||
window.setTimeout(this.cleanupDialogContainer_.bind(this), 500);
|
||||
this.isHiding_ = true;
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.isDisplayed = function () {
|
||||
ns.DialogsController.prototype.cleanupDialogContainer_ = function () {
|
||||
this.dialogContainer_.classList.remove(this.currentDialog_.id);
|
||||
this.currentDialog_.controller.destroy();
|
||||
this.currentDialog_ = null;
|
||||
|
||||
this.dialogContainer_.innerHTML = '';
|
||||
this.isHiding_ = false;
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.isDisplayingDialog_ = function () {
|
||||
return this.currentDialog_ !== null;
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.getCurrentDialogId_ = function () {
|
||||
if (this.currentDialog_) {
|
||||
return this.currentDialog_.id;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -30,10 +30,11 @@
|
|||
this.saveWrap_('moveLayerDown', true);
|
||||
this.saveWrap_('removeCurrentLayer', true);
|
||||
|
||||
pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.PREVIOUS_FRAME, this.selectPreviousFrame.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.NEXT_FRAME, this.selectNextFrame.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.NEW_FRAME, this.addFrameAtCurrentIndex.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.DUPLICATE_FRAME, this.duplicateCurrentFrame.bind(this));
|
||||
};
|
||||
|
||||
ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) {
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
this.elapsedTime = 0;
|
||||
this.currentIndex = 0;
|
||||
|
||||
this.onionSkinShortcut = pskl.service.keyboard.Shortcuts.MISC.ONION_SKIN;
|
||||
this.originalSizeShortcut = pskl.service.keyboard.Shortcuts.MISC.X1_PREVIEW;
|
||||
|
||||
this.renderFlag = true;
|
||||
|
||||
/**
|
||||
|
@ -47,8 +50,8 @@
|
|||
pskl.utils.Event.addEventListener(this.openPopupPreview, 'click', this.onOpenPopupPreviewClick_, this);
|
||||
pskl.utils.Event.addEventListener(this.originalSizeButton, 'click', this.onOriginalSizeButtonClick_, this);
|
||||
|
||||
pskl.app.shortcutService.addShortcut(ONION_SKIN_SHORTCUT, this.toggleOnionSkin_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut(ORIGINAL_SIZE_SHORTCUT, this.onOriginalSizeButtonClick_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(this.onionSkinShortcut, this.toggleOnionSkin_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(this.originalSizeShortcut, this.onOriginalSizeButtonClick_.bind(this));
|
||||
|
||||
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
|
||||
|
@ -66,9 +69,9 @@
|
|||
};
|
||||
|
||||
ns.PreviewController.prototype.initTooltips_ = function () {
|
||||
var onionSkinTooltip = pskl.utils.TooltipFormatter.format('Toggle onion skin', ONION_SKIN_SHORTCUT);
|
||||
var onionSkinTooltip = pskl.utils.TooltipFormatter.format('Toggle onion skin', this.onionSkinShortcut);
|
||||
this.toggleOnionSkinButton.setAttribute('title', onionSkinTooltip);
|
||||
var originalSizeTooltip = pskl.utils.TooltipFormatter.format('Original size preview', ORIGINAL_SIZE_SHORTCUT);
|
||||
var originalSizeTooltip = pskl.utils.TooltipFormatter.format('Original size preview', this.originalSizeShortcut);
|
||||
this.originalSizeButton.setAttribute('title', originalSizeTooltip);
|
||||
};
|
||||
|
||||
|
|
|
@ -71,7 +71,9 @@
|
|||
};
|
||||
|
||||
ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) {
|
||||
$.publish(Events.DIALOG_DISPLAY, 'browse-local');
|
||||
$.publish(Events.DIALOG_DISPLAY, {
|
||||
dialogId : 'browse-local'
|
||||
});
|
||||
this.closeDrawer_();
|
||||
};
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
}
|
||||
|
||||
event.preventDefault = function () {};
|
||||
pskl.app.shortcutService.onKeyUp_(event);
|
||||
pskl.app.shortcutService.onKeyDown_(event);
|
||||
};
|
||||
|
||||
ns.DrawingTestPlayer.prototype.playColorEvent_ = function (recordEvent) {
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
$.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this));
|
||||
$.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this));
|
||||
|
||||
pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('del', this.erase.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.PASTE, this.paste.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.CUT, this.cut.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.COPY, this.copy.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.DELETE, this.onDeleteShortcut_.bind(this));
|
||||
|
||||
$.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this));
|
||||
};
|
||||
|
@ -54,7 +54,7 @@
|
|||
this.cleanSelection_();
|
||||
};
|
||||
|
||||
ns.SelectionManager.prototype.onBackPressed_ = function(evt) {
|
||||
ns.SelectionManager.prototype.onDeleteShortcut_ = function(evt) {
|
||||
if (this.currentSelection) {
|
||||
this.erase();
|
||||
} else {
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
ns.HistoryService.prototype.init = function () {
|
||||
$.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this));
|
||||
|
||||
this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this));
|
||||
this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this));
|
||||
this.shortcutService.addShortcut('ctrl+shift+Z', this.redo.bind(this));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
this.shortcutService.registerShortcut(shortcuts.MISC.UNDO, this.undo.bind(this));
|
||||
this.shortcutService.registerShortcut(shortcuts.MISC.REDO, this.redo.bind(this));
|
||||
|
||||
this.saveState({
|
||||
type : ns.HistoryService.SNAPSHOT
|
||||
|
|
|
@ -1,150 +0,0 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.service.keyboard');
|
||||
|
||||
ns.CheatsheetService = function () {
|
||||
this.isDisplayed = false;
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.init = function () {
|
||||
this.cheatsheetLinkEl = document.querySelector('.cheatsheet-link');
|
||||
this.cheatsheetEl = document.getElementById('cheatsheet-wrapper');
|
||||
if (!this.cheatsheetEl) {
|
||||
throw 'cheatsheetEl DOM element could not be retrieved';
|
||||
}
|
||||
|
||||
this.initMarkup_();
|
||||
pskl.app.shortcutService.addShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this));
|
||||
|
||||
pskl.utils.Event.addEventListener(document.body, 'click', this.onBodyClick_, this);
|
||||
|
||||
$.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this));
|
||||
$.subscribe(Events.ESCAPE, this.onEscape_.bind(this));
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.onBodyClick_ = function (evt) {
|
||||
var isOnCheatsheet = this.cheatsheetEl.contains(evt.target);
|
||||
var isOnLink = this.cheatsheetLinkEl.contains(evt.target);
|
||||
if (isOnLink) {
|
||||
this.toggleCheatsheet_();
|
||||
} else if (!isOnCheatsheet) {
|
||||
this.hideCheatsheet_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.toggleCheatsheet_ = function () {
|
||||
if (this.isDisplayed) {
|
||||
this.hideCheatsheet_();
|
||||
} else {
|
||||
this.showCheatsheet_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.onEscape_ = function () {
|
||||
if (this.isDisplayed) {
|
||||
this.hideCheatsheet_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.showCheatsheet_ = function () {
|
||||
pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this));
|
||||
this.cheatsheetEl.style.display = 'block';
|
||||
this.isDisplayed = true;
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.hideCheatsheet_ = function () {
|
||||
pskl.app.shortcutService.removeShortcut('ESC');
|
||||
this.cheatsheetEl.style.display = 'none';
|
||||
this.isDisplayed = false;
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkup_ = function () {
|
||||
this.initMarkupForTools_();
|
||||
this.initMarkupForMisc_();
|
||||
this.initMarkupForColors_();
|
||||
this.initMarkupForSelection_();
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkupForTools_ = function () {
|
||||
var descriptors = pskl.app.toolController.tools.map(function (tool) {
|
||||
return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId);
|
||||
}.bind(this));
|
||||
|
||||
var container = this.cheatsheetEl.querySelector('.cheatsheet-tool-shortcuts');
|
||||
this.initMarkupForDescriptors_(descriptors, container);
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkupForMisc_ = function () {
|
||||
var descriptors = [
|
||||
this.toDescriptor_('0', 'Reset zoom level'),
|
||||
this.toDescriptor_('+/-', 'Zoom in/Zoom out'),
|
||||
this.toDescriptor_('ctrl + Z', 'Undo'),
|
||||
this.toDescriptor_('ctrl + Y', 'Redo'),
|
||||
this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */
|
||||
this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */
|
||||
this.toDescriptor_('N', 'Create new frame'),
|
||||
this.toDescriptor_('shift + N', 'Duplicate selected frame'),
|
||||
this.toDescriptor_('shift + ?', 'Open/Close this popup'),
|
||||
this.toDescriptor_('alt + 1', 'Toggle original size preview'),
|
||||
this.toDescriptor_('alt + O', 'Toggle Onion Skin'),
|
||||
this.toDescriptor_('alt + L', 'Toggle Layer Preview')
|
||||
];
|
||||
|
||||
var container = this.cheatsheetEl.querySelector('.cheatsheet-misc-shortcuts');
|
||||
this.initMarkupForDescriptors_(descriptors, container);
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkupForColors_ = function () {
|
||||
var descriptors = [
|
||||
this.toDescriptor_('X', 'Swap primary/secondary colors'),
|
||||
this.toDescriptor_('D', 'Reset default colors'),
|
||||
this.toDescriptor_('alt + P', 'Create a Palette'),
|
||||
this.toDescriptor_('</>', 'Select prev/next palette color'),
|
||||
this.toDescriptor_('1 to 9', 'Select palette color at index')
|
||||
];
|
||||
|
||||
var container = this.cheatsheetEl.querySelector('.cheatsheet-colors-shortcuts');
|
||||
this.initMarkupForDescriptors_(descriptors, container);
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkupForSelection_ = function () {
|
||||
var descriptors = [
|
||||
this.toDescriptor_('ctrl + X', 'Cut selection'),
|
||||
this.toDescriptor_('ctrl + C', 'Copy selection'),
|
||||
this.toDescriptor_('ctrl + V', 'Paste selection'),
|
||||
this.toDescriptor_('del', 'Delete selection')
|
||||
];
|
||||
|
||||
var container = this.cheatsheetEl.querySelector('.cheatsheet-selection-shortcuts');
|
||||
this.initMarkupForDescriptors_(descriptors, container);
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) {
|
||||
if (pskl.utils.UserAgent.isMac) {
|
||||
shortcut = shortcut.replace('ctrl', 'cmd');
|
||||
}
|
||||
return {
|
||||
'shortcut' : shortcut,
|
||||
'description' : description,
|
||||
'icon' : icon
|
||||
};
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkupForDescriptors_ = function (descriptors, container) {
|
||||
descriptors.forEach(function (descriptor) {
|
||||
var shortcut = this.getDomFromDescriptor_(descriptor);
|
||||
container.appendChild(shortcut);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) {
|
||||
var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template');
|
||||
var markup = pskl.utils.Template.replace(shortcutTemplate, {
|
||||
shortcutIcon : descriptor.icon,
|
||||
shortcutDescription : descriptor.description,
|
||||
shortcutKey : descriptor.shortcut
|
||||
});
|
||||
|
||||
return pskl.utils.Template.createFromHTML(markup);
|
||||
};
|
||||
|
||||
})();
|
80
src/js/service/keyboard/KeyUtils.js
Normal file
80
src/js/service/keyboard/KeyUtils.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.service.keyboard');
|
||||
|
||||
ns.KeyUtils = {
|
||||
createKeyFromString : function (shortcutKeyString) {
|
||||
shortcutKeyString = shortcutKeyString.toLowerCase();
|
||||
var modifiers = {
|
||||
alt : shortcutKeyString.indexOf('alt+') != -1,
|
||||
shift : shortcutKeyString.indexOf('shift+') != -1,
|
||||
ctrl : shortcutKeyString.indexOf('ctrl+') != -1
|
||||
};
|
||||
|
||||
var parts = shortcutKeyString.split(/\+(?!$)/);
|
||||
var key = parts[parts.length - 1];
|
||||
|
||||
return {
|
||||
key : key.toUpperCase(),
|
||||
modifiers : modifiers
|
||||
};
|
||||
},
|
||||
|
||||
createKeyFromEvent : function (evt) {
|
||||
var keycode = evt.which;
|
||||
var key = ns.KeycodeTranslator.toChar(keycode);
|
||||
if (!key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
key : key.toUpperCase(),
|
||||
modifiers : {
|
||||
alt : evt.altKey,
|
||||
shift : evt.shiftKey,
|
||||
ctrl : ns.KeyUtils.isCtrlKeyPressed_(evt)
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
equals : function (key1, key2) {
|
||||
key1 = typeof key1 === 'string' ? ns.KeyUtils.createKeyFromString(key1) : key1;
|
||||
key2 = typeof key2 === 'string' ? ns.KeyUtils.createKeyFromString(key2) : key2;
|
||||
|
||||
var isKeyMatching = key1.key === key2.key &&
|
||||
key1.modifiers.alt === key2.modifiers.alt &&
|
||||
key1.modifiers.shift === key2.modifiers.shift &&
|
||||
key1.modifiers.ctrl === key2.modifiers.ctrl;
|
||||
|
||||
return isKeyMatching;
|
||||
},
|
||||
|
||||
stringify : function (shortcutKeyObject) {
|
||||
var modifierString = ns.KeyUtils.getModifiersString(shortcutKeyObject.modifiers);
|
||||
if (modifierString) {
|
||||
return modifierString + '+' + shortcutKeyObject.key;
|
||||
}
|
||||
|
||||
return shortcutKeyObject.key;
|
||||
},
|
||||
|
||||
getModifiersString : function (modifiers) {
|
||||
var keyBuffer = [];
|
||||
|
||||
if (modifiers.alt) {
|
||||
keyBuffer.push('alt');
|
||||
}
|
||||
if (modifiers.ctrl) {
|
||||
keyBuffer.push('ctrl');
|
||||
}
|
||||
if (modifiers.shift) {
|
||||
keyBuffer.push('shift');
|
||||
}
|
||||
|
||||
return keyBuffer.join('+');
|
||||
},
|
||||
|
||||
isCtrlKeyPressed_ : function (evt) {
|
||||
return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey;
|
||||
}
|
||||
};
|
||||
})();
|
|
@ -17,7 +17,9 @@
|
|||
// 61 on Firefox for =/+ key
|
||||
61 : '+',
|
||||
188 : '<',
|
||||
190 : '>'
|
||||
190 : '>',
|
||||
219 : '[',
|
||||
221 : ']'
|
||||
};
|
||||
|
||||
var ns = $.namespace('pskl.service.keyboard');
|
||||
|
|
124
src/js/service/keyboard/Shortcut.js
Normal file
124
src/js/service/keyboard/Shortcut.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.service.keyboard');
|
||||
|
||||
/**
|
||||
* Keyboard shortcut wrapper, use it to register on the ShortcutService.
|
||||
*
|
||||
* @param {String} id Shortcut identifier
|
||||
* @param {String} description Shortcut description
|
||||
* @param {String|Array<String>} defaultKeys combination of modifiers + ([a-z0-9] or a special key)
|
||||
* Special keys are defined in KeycodeTranslator. If the shortcut supports several keys,
|
||||
* use an array of String keys
|
||||
*/
|
||||
ns.Shortcut = function (id, description, defaultKeys, displayKey) {
|
||||
this.id_ = id;
|
||||
this.description_ = description;
|
||||
if (typeof defaultKeys === 'string') {
|
||||
defaultKeys = [defaultKeys];
|
||||
}
|
||||
this.defaultKeys_ = defaultKeys;
|
||||
this.displayKey_ = displayKey;
|
||||
};
|
||||
|
||||
ns.Shortcut.USER_SETTINGS_PREFIX = 'shortcut.';
|
||||
|
||||
ns.Shortcut.prototype.getId = function () {
|
||||
return this.id_;
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.getDescription = function () {
|
||||
return this.description_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the array of String keys that match this shortcut
|
||||
* @return {Array<String>} array of keys
|
||||
*/
|
||||
ns.Shortcut.prototype.getKeys = function () {
|
||||
var keys = pskl.UserSettings.get(this.getLocalStorageKey_()) || this.defaultKeys_;
|
||||
|
||||
if (typeof keys === 'string') {
|
||||
return [keys];
|
||||
}
|
||||
|
||||
if (!Array.isArray(keys)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return keys;
|
||||
};
|
||||
|
||||
/**
|
||||
* For now, only shortcuts with a single key mapped can be edited
|
||||
* @return {Boolean} true if the shortcut can be updated
|
||||
*/
|
||||
ns.Shortcut.prototype.isEditable = function () {
|
||||
return this.getKeys().length < 2;
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.isCustom = function () {
|
||||
var keys = this.getKeys();
|
||||
if (keys.length !== this.defaultKeys_.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// for some default keys
|
||||
return this.defaultKeys_.some(function (defaultKey) {
|
||||
// no match can be found in the current keys
|
||||
return !keys.some(function (key) {
|
||||
return ns.KeyUtils.equals(key, defaultKey);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.isUndefined = function () {
|
||||
return this.getKeys().length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the key to be displayed for this shortcut, if
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
ns.Shortcut.prototype.getDisplayKey = function () {
|
||||
if (this.isUndefined()) {
|
||||
return '???';
|
||||
}
|
||||
|
||||
if (this.displayKey_) {
|
||||
return this.displayKey_;
|
||||
}
|
||||
|
||||
return this.getKeys()[0];
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.restoreDefault = function (keys) {
|
||||
pskl.UserSettings.set(this.getLocalStorageKey_(), '');
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.updateKeys = function (keys) {
|
||||
pskl.UserSettings.set(this.getLocalStorageKey_(), keys);
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.removeKeys = function (keysToRemove) {
|
||||
if (!this.isEditable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var keys = this.getKeys();
|
||||
var updatedKeys = keys.filter(function (key) {
|
||||
return !keysToRemove.some(function (keyToRemove) {
|
||||
return ns.KeyUtils.equals(key, keyToRemove);
|
||||
});
|
||||
});
|
||||
|
||||
if (updatedKeys.length !== keys.length) {
|
||||
this.updateKeys(updatedKeys);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
ns.Shortcut.prototype.getLocalStorageKey_ = function () {
|
||||
return ns.Shortcut.USER_SETTINGS_PREFIX + this.id_;
|
||||
};
|
||||
})();
|
|
@ -2,111 +2,70 @@
|
|||
var ns = $.namespace('pskl.service.keyboard');
|
||||
|
||||
ns.ShortcutService = function () {
|
||||
this.shortcuts_ = {};
|
||||
this.shortcuts_ = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
ns.ShortcutService.prototype.init = function() {
|
||||
$(document.body).keydown($.proxy(this.onKeyUp_, this));
|
||||
$(document.body).keydown($.proxy(this.onKeyDown_, this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a keyboard shortcut
|
||||
* @param {String} rawKey (case insensitive) a key is a combination of modifiers + ([a-z0-9] or
|
||||
* a special key) (check list of supported special keys in KeycodeTranslator)
|
||||
* eg. 'ctrl+A',
|
||||
* 'del'
|
||||
* 'ctrl+shift+S'
|
||||
* @param {pskl.service.keyboard.Shortcut} shortcut
|
||||
* @param {Function} callback should return true to let the original event perform its default action
|
||||
*/
|
||||
ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) {
|
||||
var parsedKey = this.parseKey_(rawKey.toLowerCase());
|
||||
|
||||
var key = parsedKey.key;
|
||||
var meta = parsedKey.meta;
|
||||
|
||||
this.shortcuts_[key] = this.shortcuts_[key] || {};
|
||||
|
||||
if (this.shortcuts_[key][meta]) {
|
||||
var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key;
|
||||
console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered');
|
||||
} else {
|
||||
this.shortcuts_[key][meta] = callback;
|
||||
ns.ShortcutService.prototype.registerShortcut = function (shortcut, callback) {
|
||||
if (!(shortcut instanceof ns.Shortcut)) {
|
||||
throw 'Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut';
|
||||
}
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.addShortcuts = function (keys, callback) {
|
||||
keys.forEach(function (key) {
|
||||
this.addShortcut(key, callback);
|
||||
}.bind(this));
|
||||
};
|
||||
if (typeof callback != 'function') {
|
||||
throw 'Invalid callback argument, please provide a function';
|
||||
}
|
||||
|
||||
ns.ShortcutService.prototype.removeShortcut = function (rawKey) {
|
||||
var parsedKey = this.parseKey_(rawKey.toLowerCase());
|
||||
var key = parsedKey.key;
|
||||
var meta = parsedKey.meta;
|
||||
|
||||
this.shortcuts_[key] = this.shortcuts_[key] || {};
|
||||
|
||||
this.shortcuts_[key][meta] = null;
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.parseKey_ = function (key) {
|
||||
var meta = this.getMetaKey_({
|
||||
alt : key.indexOf('alt+') != -1,
|
||||
shift : key.indexOf('shift+') != -1,
|
||||
ctrl : key.indexOf('ctrl+') != -1
|
||||
this.shortcuts_.push({
|
||||
shortcut : shortcut,
|
||||
callback : callback
|
||||
});
|
||||
|
||||
var parts = key.split(/\+(?!$)/);
|
||||
key = parts[parts.length - 1];
|
||||
return {meta : meta, key : key};
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.getMetaKey_ = function (meta) {
|
||||
var keyBuffer = [];
|
||||
['alt', 'ctrl', 'shift'].forEach(function (metaKey) {
|
||||
if (meta[metaKey]) {
|
||||
keyBuffer.push(metaKey);
|
||||
ns.ShortcutService.prototype.unregisterShortcut = function (shortcut) {
|
||||
var index = -1;
|
||||
this.shortcuts_.forEach(function (s, i) {
|
||||
if (s.shortcut === shortcut) {
|
||||
index = i;
|
||||
}
|
||||
});
|
||||
|
||||
if (keyBuffer.length > 0) {
|
||||
return keyBuffer.join('+');
|
||||
} else {
|
||||
return 'normal';
|
||||
if (index != -1) {
|
||||
this.shortcuts_.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.ShortcutService.prototype.onKeyUp_ = function(evt) {
|
||||
if (!this.isInInput_(evt)) {
|
||||
// jquery names FTW ...
|
||||
var keycode = evt.which;
|
||||
var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode);
|
||||
|
||||
var keyShortcuts = this.shortcuts_[charkey];
|
||||
if (keyShortcuts) {
|
||||
var meta = this.getMetaKey_({
|
||||
alt : this.isAltKeyPressed_(evt),
|
||||
shift : this.isShiftKeyPressed_(evt),
|
||||
ctrl : this.isCtrlKeyPressed_(evt)
|
||||
});
|
||||
var cb = keyShortcuts[meta];
|
||||
|
||||
if (cb) {
|
||||
var bubble = cb(charkey);
|
||||
if (bubble !== true) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
$.publish(Events.KEYBOARD_EVENT, [evt]);
|
||||
}
|
||||
}
|
||||
ns.ShortcutService.prototype.onKeyDown_ = function(evt) {
|
||||
var eventKey = ns.KeyUtils.createKeyFromEvent(evt);
|
||||
if (this.isInInput_(evt) || !eventKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.shortcuts_.forEach(function (shortcutInfo) {
|
||||
shortcutInfo.shortcut.getKeys().forEach(function (shortcutKey) {
|
||||
if (!ns.KeyUtils.equals(shortcutKey, eventKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bubble = shortcutInfo.callback(eventKey.key);
|
||||
if (bubble !== true) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
$.publish(Events.KEYBOARD_EVENT, [evt]);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isInInput_ = function (evt) {
|
||||
|
@ -114,15 +73,58 @@
|
|||
return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA';
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) {
|
||||
return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey;
|
||||
ns.ShortcutService.prototype.getShortcutById = function (id) {
|
||||
return pskl.utils.Array.find(this.getShortcuts(), function (shortcut) {
|
||||
return shortcut.getId() === id;
|
||||
});
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) {
|
||||
return evt.shiftKey;
|
||||
ns.ShortcutService.prototype.getShortcuts = function () {
|
||||
var shortcuts = [];
|
||||
ns.Shortcuts.CATEGORIES.forEach(function (category) {
|
||||
var shortcutMap = ns.Shortcuts[category];
|
||||
Object.keys(shortcutMap).forEach(function (shortcutKey) {
|
||||
shortcuts.push(shortcutMap[shortcutKey]);
|
||||
});
|
||||
});
|
||||
return shortcuts;
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) {
|
||||
return evt.altKey;
|
||||
ns.ShortcutService.prototype.updateShortcut = function (shortcut, keyAsString) {
|
||||
var key = keyAsString.replace(/\s/g, '');
|
||||
|
||||
var isForbiddenKey = ns.Shortcuts.FORBIDDEN_KEYS.indexOf(key) != -1;
|
||||
if (isForbiddenKey) {
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{
|
||||
'content': 'Key cannot be remapped (' + keyAsString + ')',
|
||||
'hideDelay' : 5000
|
||||
}]);
|
||||
} else {
|
||||
this.removeKeyFromAllShortcuts_(key);
|
||||
shortcut.updateKeys([key]);
|
||||
$.publish(Events.SHORTCUTS_CHANGED);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.removeKeyFromAllShortcuts_ = function (key) {
|
||||
this.getShortcuts().forEach(function (s) {
|
||||
if (s.removeKeys([key])) {
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{
|
||||
'content': 'Shortcut key removed for ' + s.getId(),
|
||||
'hideDelay' : 5000
|
||||
}]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Restore the default piskel key for all shortcuts
|
||||
*/
|
||||
ns.ShortcutService.prototype.restoreDefaultShortcuts = function () {
|
||||
this.getShortcuts().forEach(function (shortcut) {
|
||||
shortcut.restoreDefault();
|
||||
});
|
||||
$.publish(Events.SHORTCUTS_CHANGED);
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
79
src/js/service/keyboard/Shortcuts.js
Normal file
79
src/js/service/keyboard/Shortcuts.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.service.keyboard');
|
||||
|
||||
var createShortcut = function (id, description, defaultKey, displayKey) {
|
||||
return new ns.Shortcut(id, description, defaultKey, displayKey);
|
||||
};
|
||||
|
||||
ns.Shortcuts = {
|
||||
/**
|
||||
* List of keys that cannot be remapped. Either alternate keys, which are not displayed.
|
||||
* Or really custom shortcuts such as the 1-9 for color palette shorctus
|
||||
*/
|
||||
FORBIDDEN_KEYS : ['1', '2', '3', '4', '5', '6', '7', '8', '9', '?', 'shift+?',
|
||||
'del', 'back', 'ctrl+Y', 'ctrl+shift+Z'],
|
||||
|
||||
/**
|
||||
* Syntax : createShortcut(id, description, default key(s))
|
||||
*/
|
||||
TOOL : {
|
||||
PEN : createShortcut('tool-pen', 'Pen tool', 'P'),
|
||||
MIRROR_PEN : createShortcut('tool-vertical-mirror-pen', 'Vertical mirror pen tool', 'V'),
|
||||
PAINT_BUCKET : createShortcut('tool-paint-bucket', 'Paint bucket tool', 'B'),
|
||||
COLORSWAP : createShortcut('tool-colorswap', 'Magic bucket tool', 'A'),
|
||||
ERASER : createShortcut('tool-eraser', 'Eraser pen tool', 'E'),
|
||||
STROKE : createShortcut('tool-stroke', 'Stroke tool', 'L'),
|
||||
RECTANGLE : createShortcut('tool-rectangle', 'Rectangle tool', 'R'),
|
||||
CIRCLE : createShortcut('tool-circle', 'Circle tool', 'C'),
|
||||
MOVE : createShortcut('tool-move', 'Move tool', 'M'),
|
||||
SHAPE_SELECT : createShortcut('tool-shape-select', 'Shape selection', 'Z'),
|
||||
RECTANGLE_SELECT : createShortcut('tool-rectangle-select', 'Rectangle selection', 'S'),
|
||||
LASSO_SELECT : createShortcut('tool-lasso-select', 'Lasso selection', 'H'),
|
||||
LIGHTEN : createShortcut('tool-lighten', 'Lighten tool', 'U'),
|
||||
DITHERING : createShortcut('tool-dithering', 'Dithering tool', 'T'),
|
||||
COLORPICKER : createShortcut('tool-colorpicker', 'Color picker', 'O')
|
||||
},
|
||||
|
||||
SELECTION : {
|
||||
CUT : createShortcut('selection-cut', 'Cut selection', 'ctrl+X'),
|
||||
COPY : createShortcut('selection-copy', 'Copy selection', 'ctrl+C'),
|
||||
PASTE : createShortcut('selection-paste', 'Paste selection', 'ctrl+V'),
|
||||
DELETE : createShortcut('selection-delete', 'Delete selection', ['del', 'back'])
|
||||
},
|
||||
|
||||
MISC : {
|
||||
RESET_ZOOM : createShortcut('reset-zoom', 'Reset zoom level', '0'),
|
||||
INCREASE_ZOOM : createShortcut('increase-zoom', 'Increase zoom level', '+'),
|
||||
DECREASE_ZOOM : createShortcut('decrease-zoom', 'Decrease zoom level', '-'),
|
||||
UNDO : createShortcut('undo', 'Undo', 'ctrl+Z'),
|
||||
REDO : createShortcut('redo', 'Redo', ['ctrl+Y', 'ctrl+shift+Z']),
|
||||
PREVIOUS_FRAME : createShortcut('previous-frame', 'Select previous frame', 'up'),
|
||||
NEXT_FRAME : createShortcut('next-frame', 'Select next frame', 'down'),
|
||||
NEW_FRAME : createShortcut('new-frame', 'Create new empty frame', 'N'),
|
||||
DUPLICATE_FRAME : createShortcut('duplicate-frame', 'Duplicate selected frame', 'shift+N'),
|
||||
CHEATSHEET : createShortcut('cheatsheet', 'Open the keyboard shortcut cheatsheet', ['?', 'shift+?']),
|
||||
X1_PREVIEW : createShortcut('x1-preview', 'Toggle original size preview', 'alt+1'),
|
||||
ONION_SKIN : createShortcut('onion-skin', 'Toggle onion skin', 'alt+O'),
|
||||
LAYER_PREVIEW : createShortcut('layer-preview', 'Toggle layer preview', 'alt+L'),
|
||||
CLOSE_POPUP : createShortcut('close-popup', 'Close an opened popup', 'ESC')
|
||||
},
|
||||
|
||||
STORAGE : {
|
||||
SAVE : createShortcut('save', 'Save the current sprite', 'ctrl+S'),
|
||||
OPEN : createShortcut('open', '(desktop) Open a .piskel file', 'ctrl+O'),
|
||||
SAVE_AS : createShortcut('save-as', '(desktop) Save as new', 'ctrl+shift+S')
|
||||
},
|
||||
|
||||
COLOR : {
|
||||
SWAP : createShortcut('swap-colors', 'Swap primary/secondary colors', 'X'),
|
||||
RESET : createShortcut('reset-colors', 'Reset default colors', 'D'),
|
||||
CREATE_PALETTE : createShortcut('create-palette', 'Open the palette creation popup', 'alt+P'),
|
||||
PREVIOUS_COLOR : createShortcut('previous-color', 'Select the previous color in the current palette', '<'),
|
||||
NEXT_COLOR : createShortcut('next-color', 'Select the next color in the current palette', '>'),
|
||||
SELECT_COLOR : createShortcut('select-color', 'Select a palette color in the current palette',
|
||||
'123456789'.split(''), '1 to 9')
|
||||
},
|
||||
|
||||
CATEGORIES : ['TOOL', 'SELECTION', 'MISC', 'STORAGE', 'COLOR']
|
||||
};
|
||||
})();
|
|
@ -10,9 +10,10 @@
|
|||
};
|
||||
|
||||
ns.StorageService.prototype.init = function () {
|
||||
pskl.app.shortcutService.addShortcut('ctrl+o', this.onOpenKey_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+s', this.onSaveKey_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+shift+s', this.onSaveAsKey_.bind(this));
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.STORAGE.OPEN, this.onOpenKey_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.STORAGE.SAVE, this.onSaveKey_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.STORAGE.SAVE_AS, this.onSaveAsKey_.bind(this));
|
||||
|
||||
$.subscribe(Events.BEFORE_SAVING_PISKEL, this.setSavingFlag_.bind(this, true));
|
||||
$.subscribe(Events.AFTER_SAVING_PISKEL, this.setSavingFlag_.bind(this, false));
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
|
||||
ns.IconMarkupRenderer = function () {};
|
||||
|
||||
ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) {
|
||||
ns.IconMarkupRenderer.prototype.render = function (tool, tooltipPosition) {
|
||||
tooltipPosition = tooltipPosition || 'right';
|
||||
var tpl = pskl.utils.Template.get('drawingTool-item-template');
|
||||
return pskl.utils.Template.replace(tpl, {
|
||||
cssclass : ['tool-icon', tool.toolId].join(' '),
|
||||
toolid : tool.toolId,
|
||||
title : this.getTooltipText(tool, shortcut),
|
||||
title : this.getTooltipText(tool),
|
||||
tooltipposition : tooltipPosition
|
||||
});
|
||||
};
|
||||
|
||||
ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) {
|
||||
ns.IconMarkupRenderer.prototype.getTooltipText = function(tool) {
|
||||
var descriptors = tool.tooltipDescriptors;
|
||||
return pskl.utils.TooltipFormatter.format(tool.getHelpText(), shortcut, descriptors);
|
||||
return pskl.utils.TooltipFormatter.format(tool.getHelpText(), tool.shortcut, descriptors);
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
this.toolId = 'tool-circle';
|
||||
this.helpText = 'Circle tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.CIRCLE;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.Circle, ns.ShapeTool);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
ns.ColorPicker = function() {
|
||||
this.toolId = 'tool-colorpicker';
|
||||
this.helpText = 'Color picker';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.COLORPICKER;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ColorPicker, ns.BaseTool);
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
ns.ColorSwap = function() {
|
||||
this.toolId = 'tool-colorswap';
|
||||
|
||||
this.helpText = 'Paint all pixels of the same color';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.COLORSWAP;
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Apply to all layers'},
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
ns.SimplePen.call(this);
|
||||
this.toolId = 'tool-dithering';
|
||||
this.helpText = 'Dithering tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.DITHERING;
|
||||
};
|
||||
pskl.utils.inherit(ns.DitheringTool, ns.SimplePen);
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
|
||||
ns.Eraser = function() {
|
||||
this.superclass.constructor.call(this);
|
||||
|
||||
this.toolId = 'tool-eraser';
|
||||
this.helpText = 'Eraser tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.ERASER;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.Eraser, ns.SimplePen);
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
|
||||
ns.Lighten = function() {
|
||||
this.superclass.constructor.call(this);
|
||||
this.toolId = 'tool-lighten';
|
||||
|
||||
this.toolId = 'tool-lighten';
|
||||
this.helpText = 'Lighten';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.LIGHTEN;
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Darken'},
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
ns.Move = function() {
|
||||
this.toolId = ns.Move.TOOL_ID;
|
||||
this.helpText = 'Move tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.MOVE;
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Apply to all layers'},
|
||||
|
@ -21,6 +22,10 @@
|
|||
this.startRow = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* The move tool id is used by the ToolController and the BaseSelect and needs to be
|
||||
* easliy accessible
|
||||
*/
|
||||
ns.Move.TOOL_ID = 'tool-move';
|
||||
|
||||
pskl.utils.inherit(ns.Move, ns.BaseTool);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
ns.PaintBucket = function() {
|
||||
this.toolId = 'tool-paint-bucket';
|
||||
this.helpText = 'Paint bucket tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.PAINT_BUCKET;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.PaintBucket, ns.BaseTool);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
this.toolId = 'tool-rectangle';
|
||||
this.helpText = 'Rectangle tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.RECTANGLE;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.Rectangle, ns.ShapeTool);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
ns.SimplePen = function() {
|
||||
this.toolId = 'tool-pen';
|
||||
this.helpText = 'Pen tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.PEN;
|
||||
|
||||
this.previousCol = null;
|
||||
this.previousRow = null;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
ns.Stroke = function() {
|
||||
this.toolId = 'tool-stroke';
|
||||
this.helpText = 'Stroke tool';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.STROKE;
|
||||
|
||||
// Stroke's first point coordinates (set in applyToolAt)
|
||||
this.startCol = null;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
this.toolId = 'tool-vertical-mirror-pen';
|
||||
this.helpText = 'Vertical Mirror pen';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.MIRROR_PEN;
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Use horizontal axis'},
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
ns.AbstractDragSelect = function () {
|
||||
ns.BaseSelect.call(this);
|
||||
|
||||
this.hasSelection = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.LassoSelect = function() {
|
||||
ns.AbstractDragSelect.call(this);
|
||||
|
||||
this.toolId = 'tool-lasso-select';
|
||||
this.helpText = 'Lasso selection';
|
||||
|
||||
ns.AbstractDragSelect.call(this);
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.LASSO_SELECT;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.LassoSelect, ns.AbstractDragSelect);
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.RectangleSelect = function() {
|
||||
ns.AbstractDragSelect.call(this);
|
||||
|
||||
this.toolId = 'tool-rectangle-select';
|
||||
this.helpText = 'Rectangle selection';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.RECTANGLE_SELECT;
|
||||
|
||||
ns.AbstractDragSelect.call(this);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.RectangleSelect, ns.AbstractDragSelect);
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
var ns = $.namespace('pskl.tools.drawing.selection');
|
||||
|
||||
ns.ShapeSelect = function() {
|
||||
this.toolId = 'tool-shape-select';
|
||||
|
||||
this.helpText = 'Shape selection';
|
||||
|
||||
ns.BaseSelect.call(this);
|
||||
|
||||
this.toolId = 'tool-shape-select';
|
||||
this.helpText = 'Shape selection';
|
||||
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.SHAPE_SELECT;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ShapeSelect, ns.BaseSelect);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
pskl.utils.inherit(ns.AbstractTransformTool, pskl.tools.Tool);
|
||||
|
||||
ns.AbstractTransformTool.prototype.apply = function (evt) {
|
||||
ns.AbstractTransformTool.prototype.applyTransformation = function (evt) {
|
||||
var allFrames = evt.shiftKey;
|
||||
var allLayers = evt.ctrlKey;
|
||||
|
||||
|
|
|
@ -26,14 +26,29 @@
|
|||
return false;
|
||||
},
|
||||
|
||||
getParentWithData : function (node, data) {
|
||||
getParentWithData : function (node, dataName) {
|
||||
while (node) {
|
||||
if (node.dataset && typeof node.dataset[data] !== 'undefined') {
|
||||
if (node.dataset && typeof node.dataset[dataName] !== 'undefined') {
|
||||
return node;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
getData : function (node, dataName) {
|
||||
var parent = ns.Dom.getParentWithData(node, dataName);
|
||||
if (parent !== null) {
|
||||
return parent.dataset[dataName];
|
||||
}
|
||||
},
|
||||
|
||||
removeClass : function (className, container) {
|
||||
container = container || document;
|
||||
var elements = container.querySelectorAll('.' + className);
|
||||
for (var i = 0 ; i < elements.length ; i++) {
|
||||
elements[i].classList.remove(className);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
ns.TooltipFormatter.format = function(helpText, shortcut, descriptors) {
|
||||
var tpl = pskl.utils.Template.get('tooltip-container-template');
|
||||
shortcut = shortcut ? '(' + shortcut + ')' : '';
|
||||
shortcut = shortcut ? '(' + shortcut.getDisplayKey() + ')' : '';
|
||||
return pskl.utils.Template.replace(tpl, {
|
||||
helptext : helpText,
|
||||
shortcut : shortcut,
|
||||
|
|
|
@ -91,6 +91,10 @@
|
|||
* @private
|
||||
*/
|
||||
checkKeyValidity_ : function(key) {
|
||||
if (key.indexOf(pskl.service.keyboard.Shortcut.USER_SETTINGS_PREFIX) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var isValidKey = key in this.KEY_TO_DEFAULT_VALUE_MAP_;
|
||||
if (!isValidKey) {
|
||||
console.error('UserSettings key <' + key + '> not found in supported keys.');
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
"js/utils/FileUtils.js",
|
||||
"js/utils/FileUtilsDesktop.js",
|
||||
"js/utils/FrameUtils.js",
|
||||
"js/utils/LayerUtils.js",
|
||||
"js/utils/ImageResizer.js",
|
||||
"js/utils/LayerUtils.js",
|
||||
"js/utils/PixelUtils.js",
|
||||
"js/utils/PiskelFileUtils.js",
|
||||
"js/utils/Template.js",
|
||||
|
@ -128,6 +128,7 @@
|
|||
"js/controller/dialogs/CreatePaletteController.js",
|
||||
"js/controller/dialogs/ImportImageController.js",
|
||||
"js/controller/dialogs/BrowseLocalController.js",
|
||||
"js/controller/dialogs/CheatsheetController.js",
|
||||
|
||||
// Dialogs controller
|
||||
"js/controller/dialogs/DialogsController.js",
|
||||
|
@ -157,9 +158,11 @@
|
|||
"js/service/palette/reader/PaletteTxtReader.js",
|
||||
"js/service/palette/PaletteImportService.js",
|
||||
"js/service/SavedStatusService.js",
|
||||
"js/service/keyboard/ShortcutService.js",
|
||||
"js/service/keyboard/KeycodeTranslator.js",
|
||||
"js/service/keyboard/CheatsheetService.js",
|
||||
"js/service/keyboard/KeyUtils.js",
|
||||
"js/service/keyboard/Shortcut.js",
|
||||
"js/service/keyboard/Shortcuts.js",
|
||||
"js/service/keyboard/ShortcutService.js",
|
||||
"js/service/ImageUploadService.js",
|
||||
"js/service/CurrentColorsService.js",
|
||||
"js/service/FileDropperService.js",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
(typeof exports != "undefined" ? exports : pskl_exports).styles = [
|
||||
"css/reset.css",
|
||||
"css/style.css",
|
||||
"css/animations.css",
|
||||
"css/layout.css",
|
||||
"css/font-icon.css",
|
||||
"css/forms.css",
|
||||
|
@ -14,12 +15,12 @@
|
|||
"css/settings-save.css",
|
||||
"css/tools.css",
|
||||
"css/icons.css",
|
||||
"css/cheatsheet.css",
|
||||
"css/color-picker-slider.css",
|
||||
"css/dialogs.css",
|
||||
"css/dialogs-import-image.css",
|
||||
"css/dialogs-browse-local.css",
|
||||
"css/dialogs-cheatsheet.css",
|
||||
"css/dialogs-create-palette.css",
|
||||
"css/dialogs-import-image.css",
|
||||
"css/notifications.css",
|
||||
"css/toolbox.css",
|
||||
"css/toolbox-layers-list.css",
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<div id="cheatsheet-wrapper" style="display:none">
|
||||
<div class="cheatsheet-container">
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Tool shortcuts</h3>
|
||||
<ul class="cheatsheet-tool-shortcuts"></ul>
|
||||
</div>
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Misc shortcuts</h3>
|
||||
<ul class="cheatsheet-misc-shortcuts"></ul>
|
||||
</div>
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Selection shortcuts</h3>
|
||||
<ul class="cheatsheet-selection-shortcuts"></ul>
|
||||
<h3 class="cheatsheet-title">Color shortcuts</h3>
|
||||
<ul class="cheatsheet-colors-shortcuts"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="cheatsheet-link"
|
||||
rel="tooltip" data-placement="right" title="Keyboard shortcuts"> </span>
|
||||
<script type="text/template" id="cheatsheet-shortcut-template">
|
||||
<li class="cheatsheet-shortcut">
|
||||
<div class="cheatsheet-icon {{shortcutIcon}}"></div>
|
||||
<span class="cheatsheet-key">{{shortcutKey}}</span>
|
||||
<span class="cheatsheet-description">{{shortcutDescription}}</span>
|
||||
</li>
|
||||
</script>
|
|
@ -3,7 +3,7 @@
|
|||
Browse Local Piskels
|
||||
<span class="dialog-close">X</span>
|
||||
</h3>
|
||||
<div style="padding:10px 20px; font-size:1.5em">
|
||||
<div class="dialog-content" style="padding:10px 20px; font-size:1.5em; overflow: auto;">
|
||||
<table class="local-piskel-list">
|
||||
<thead>
|
||||
<tr class="local-piskel-list-head">
|
||||
|
|
46
src/templates/dialogs/cheatsheet.html
Normal file
46
src/templates/dialogs/cheatsheet.html
Normal file
|
@ -0,0 +1,46 @@
|
|||
<div id="cheatsheetContainer" class="dialog-wrapper">
|
||||
<h3 class="dialog-head">
|
||||
<span class="dialog-title">Keyboard shortcuts</span>
|
||||
<span class="dialog-close">X</span>
|
||||
</h3>
|
||||
<div class="cheatsheet-container dialog-content">
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Tool shortcuts</h3>
|
||||
<ul class="cheatsheet-tool-shortcuts"></ul>
|
||||
</div>
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Misc shortcuts</h3>
|
||||
<ul class="cheatsheet-misc-shortcuts"></ul>
|
||||
</div>
|
||||
<div class="cheatsheet-boxes">
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Selection shortcuts</h3>
|
||||
<ul class="cheatsheet-selection-shortcuts"></ul>
|
||||
</div>
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Color shortcuts</h3>
|
||||
<ul class="cheatsheet-color-shortcuts"></ul>
|
||||
</div>
|
||||
<div class="cheatsheet-section">
|
||||
<h3 class="cheatsheet-title">Storage shortcuts</h3>
|
||||
<ul class="cheatsheet-storage-shortcuts"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cheatsheet-actions">
|
||||
<span class="cheatsheet-helptext" rel="tooltip" data-placement="top" title="!!!Set in CheatsheetController!!!"><b>Customize shortcuts ?</b></span>
|
||||
<button type="button" name="cheatsheet-restore-defaults" data-action="restore-defaults" class="button cheatsheet-button cheatsheet-restore-defaults">Restore default shortcuts</button>
|
||||
</div>
|
||||
|
||||
<!-- Event trap to capture keyboard remaps -->
|
||||
<div style="position:relative; overflow:hidden; width:1px; height:1px;">
|
||||
<input type="text" id="cheatsheetEventTrap" style="position:absolute; top:-1000px;" />
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/template" id="cheatsheet-shortcut-template">
|
||||
<li class="cheatsheet-shortcut {{className}}" data-shortcut-id="{{id}}">
|
||||
<div class="cheatsheet-icon {{icon}}"></div>
|
||||
<span class="cheatsheet-key" rel="tooltip" data-placement="top" title="{{title}}">{{key}}</span>
|
||||
<span class="cheatsheet-description">{{description}}</span>
|
||||
</li>
|
||||
</script>
|
|
@ -17,7 +17,7 @@ describe("SelectionManager suite", function() {
|
|||
* @Mock
|
||||
*/
|
||||
pskl.app.shortcutService = {
|
||||
addShortcut : function () {}
|
||||
registerShortcut : function () {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,7 @@ describe("SelectionManager suite", function() {
|
|||
selectionManager.init();
|
||||
|
||||
selection = new pskl.selection.BaseSelection();
|
||||
|
||||
|
||||
selection.pixels = [];
|
||||
});
|
||||
|
||||
|
@ -161,7 +161,7 @@ describe("SelectionManager suite", function() {
|
|||
[R, B, T],
|
||||
[T, R, B]
|
||||
]);
|
||||
|
||||
|
||||
selection.move(-1, 0);
|
||||
|
||||
console.log('[SelectionManager] ... paste out of bounds');
|
||||
|
|
|
@ -28,7 +28,8 @@ describe("History Service suite", function() {
|
|||
}
|
||||
};
|
||||
var mockShortcutService = {
|
||||
addShortcut : function () {}
|
||||
registerShortcuts : function () {},
|
||||
registerShortcut : function () {}
|
||||
};
|
||||
return new pskl.service.HistoryService(mockPiskelController, mockShortcutService);
|
||||
};
|
||||
|
|
275
test/js/service/keyboard/ShortcutServiceTest.js
Normal file
275
test/js/service/keyboard/ShortcutServiceTest.js
Normal file
|
@ -0,0 +1,275 @@
|
|||
describe("ShortcutService test suite", function() {
|
||||
|
||||
var A_KEY = 'A';
|
||||
var B_KEY = 'B';
|
||||
var A_KEYCODE = 65;
|
||||
var B_KEYCODE = 66;
|
||||
|
||||
var service;
|
||||
|
||||
beforeEach(function() {
|
||||
service = new pskl.service.keyboard.ShortcutService();
|
||||
});
|
||||
|
||||
var createEvent = function (keycode) {
|
||||
return {
|
||||
which : keycode,
|
||||
altKey : false,
|
||||
withAltKey : function () {
|
||||
this.altKey = true;
|
||||
return this;
|
||||
},
|
||||
ctrlKey : false,
|
||||
withCtrlKey : function () {
|
||||
this.ctrlKey = true;
|
||||
return this;
|
||||
},
|
||||
shiftKey : false,
|
||||
withShiftKey : function () {
|
||||
this.shiftKey = true;
|
||||
return this;
|
||||
},
|
||||
preventDefaultCalled : false,
|
||||
preventDefault : function () {
|
||||
this.preventDefaultCalled = true;
|
||||
},
|
||||
target : {
|
||||
nodeName : 'div'
|
||||
},
|
||||
setNodeName : function (nodeName) {
|
||||
this.target.nodeName = nodeName;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var setTargetName = function (evt, targetName) {
|
||||
evt.target = {
|
||||
nodeName : targetName
|
||||
};
|
||||
};
|
||||
|
||||
it("accepts only shortcut instances", function() {
|
||||
console.log('[ShortcutService] accepts only shortcut instances');
|
||||
|
||||
console.log('[ShortcutService] ... fails for missing shortcut');
|
||||
expect(function () {
|
||||
service.registerShortcut();
|
||||
}).toThrow('Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut');
|
||||
|
||||
console.log('[ShortcutService] ... fails for shortcut as empty object');
|
||||
expect(function () {
|
||||
service.registerShortcut({});
|
||||
}).toThrow('Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut');
|
||||
|
||||
console.log('[ShortcutService] ... fails for shortcut as a string');
|
||||
expect(function () {
|
||||
service.registerShortcut('alt+F4');
|
||||
}).toThrow('Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut');
|
||||
|
||||
var shortcut = new pskl.service.keyboard.Shortcut('shortcut-id', '', A_KEY);
|
||||
|
||||
console.log('[ShortcutService] ... fails for missing callback');
|
||||
expect(function () {
|
||||
service.registerShortcut(shortcut);
|
||||
}).toThrow('Invalid callback argument, please provide a function');
|
||||
|
||||
console.log('[ShortcutService] ... fails for invalid callback');
|
||||
expect(function () {
|
||||
service.registerShortcut(shortcut, {callback : function () {}});
|
||||
}).toThrow('Invalid callback argument, please provide a function');
|
||||
|
||||
console.log('[ShortcutService] ... is ok for valid arguments');
|
||||
service.registerShortcut(shortcut, function () {});
|
||||
});
|
||||
|
||||
it ("triggers shortcut", function () {
|
||||
console.log('[ShortcutService] triggers shortcut');
|
||||
var callbackCalled = false;
|
||||
|
||||
console.log('[ShortcutService] ... register shortcut for A');
|
||||
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
|
||||
service.registerShortcut(shortcutA, function () {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut is called');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE));
|
||||
expect(callbackCalled).toBe(true);
|
||||
});
|
||||
|
||||
it ("triggers shortcuts independently", function () {
|
||||
console.log('[ShortcutService] registers shortcuts');
|
||||
|
||||
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
|
||||
var shortcutB = new pskl.service.keyboard.Shortcut('shortcut-b', '', B_KEY);
|
||||
var shortcutA_B = new pskl.service.keyboard.Shortcut('shortcut-a&b', '', [A_KEY, B_KEY]);
|
||||
|
||||
var counters = {
|
||||
a : 0,
|
||||
b : 0,
|
||||
a_b : 0
|
||||
};
|
||||
|
||||
console.log('[ShortcutService] ... register separate shortcuts for A and B');
|
||||
service.registerShortcut(shortcutA, function () {
|
||||
counters.a++;
|
||||
});
|
||||
service.registerShortcut(shortcutB, function () {
|
||||
counters.b++;
|
||||
});
|
||||
service.registerShortcut(shortcutA_B, function () {
|
||||
counters.a_b++;
|
||||
});
|
||||
|
||||
console.log('[ShortcutService] ... trigger A, expect counter A at 1, B at 0, A_B at 1');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE));
|
||||
expect(counters.a).toBe(1);
|
||||
expect(counters.b).toBe(0);
|
||||
expect(counters.a_b).toBe(1);
|
||||
|
||||
console.log('[ShortcutService] ... trigger A, expect counter A at 1, B at 1, A_B at 2');
|
||||
service.onKeyDown_(createEvent(B_KEYCODE));
|
||||
expect(counters.a).toBe(1);
|
||||
expect(counters.b).toBe(1);
|
||||
expect(counters.a_b).toBe(2);
|
||||
});
|
||||
|
||||
it ("unregisters shortcut", function () {
|
||||
console.log('[ShortcutService] unregisters shortcut');
|
||||
var callbackCalled = false;
|
||||
|
||||
console.log('[ShortcutService] ... register shortcut for A');
|
||||
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
|
||||
service.registerShortcut(shortcutA, function () {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
console.log('[ShortcutService] ... unregister shortcut A');
|
||||
service.unregisterShortcut(shortcutA);
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut callback is not called');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE));
|
||||
expect(callbackCalled).toBe(false);
|
||||
});
|
||||
|
||||
it ("unregisters shortcut without removing other shortcuts", function () {
|
||||
console.log('[ShortcutService] unregisters shortcut');
|
||||
var callbackCalled = false;
|
||||
|
||||
console.log('[ShortcutService] ... register shortcut for A & B');
|
||||
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
|
||||
var shortcutB = new pskl.service.keyboard.Shortcut('shortcut-b', '', B_KEY);
|
||||
service.registerShortcut(shortcutA, function () {});
|
||||
service.registerShortcut(shortcutB, function () {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
console.log('[ShortcutService] ... unregister shortcut A');
|
||||
service.unregisterShortcut(shortcutA);
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut callback for B can still be called');
|
||||
service.onKeyDown_(createEvent(B_KEYCODE));
|
||||
expect(callbackCalled).toBe(true);
|
||||
});
|
||||
|
||||
it ("supports unregistering unknown shortcuts", function () {
|
||||
console.log('[ShortcutService] unregisters shortcut');
|
||||
var callbackCalled = false;
|
||||
|
||||
console.log('[ShortcutService] ... register shortcut for A');
|
||||
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
|
||||
service.registerShortcut(shortcutA, function () {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
console.log('[ShortcutService] ... unregister shortcut B, which was not registered in the first place');
|
||||
var shortcutB = new pskl.service.keyboard.Shortcut('shortcut-b', '', B_KEY);
|
||||
service.unregisterShortcut(shortcutB);
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut callback for A can still be called');
|
||||
callbackCalled = false;
|
||||
service.onKeyDown_(createEvent(A_KEYCODE));
|
||||
expect(callbackCalled).toBe(true);
|
||||
});
|
||||
|
||||
it ("does not trigger shortcuts from INPUT or TEXTAREA", function () {
|
||||
console.log('[ShortcutService] triggers shortcut');
|
||||
var callbackCalled = false;
|
||||
|
||||
console.log('[ShortcutService] ... register shortcut for A');
|
||||
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
|
||||
service.registerShortcut(shortcutA, function () {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut is not called from event on INPUT');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).setNodeName('INPUT'));
|
||||
expect(callbackCalled).toBe(false);
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut is not called from event on TEXTAREA');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).setNodeName('TEXTAREA'));
|
||||
expect(callbackCalled).toBe(false);
|
||||
|
||||
console.log('[ShortcutService] ... verify shortcut is called from event on LINK');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).setNodeName('A'));
|
||||
expect(callbackCalled).toBe(true);
|
||||
});
|
||||
|
||||
it ("supports meta modifiers", function () {
|
||||
console.log('[ShortcutService] triggers shortcut');
|
||||
var callbackCalled = false;
|
||||
|
||||
console.log('[ShortcutService] ... create various A shortcuts with modifiers');
|
||||
var shortcuts = [
|
||||
new pskl.service.keyboard.Shortcut('a', '', A_KEY),
|
||||
new pskl.service.keyboard.Shortcut('a_ctrl', '', 'ctrl+' + A_KEY),
|
||||
new pskl.service.keyboard.Shortcut('a_ctrl_shift', '', 'ctrl+shift+' + A_KEY),
|
||||
new pskl.service.keyboard.Shortcut('a_ctrl_shift_alt', '', 'ctrl+shift+alt+' + A_KEY),
|
||||
new pskl.service.keyboard.Shortcut('a_alt', '', 'alt+' + A_KEY)
|
||||
];
|
||||
|
||||
var counters = {
|
||||
a : 0,
|
||||
a_ctrl : 0,
|
||||
a_ctrl_shift : 0,
|
||||
a_ctrl_shift_alt : 0,
|
||||
a_alt : 0,
|
||||
};
|
||||
|
||||
shortcuts.forEach(function (shortcut) {
|
||||
service.registerShortcut(shortcut, function () {
|
||||
counters[shortcut.getId()]++;
|
||||
});
|
||||
});
|
||||
|
||||
var verifyCounters = function (a, a_c, a_cs, a_csa, a_a) {
|
||||
expect(counters.a).toBe(a);
|
||||
expect(counters.a_ctrl).toBe(a_c);
|
||||
expect(counters.a_ctrl_shift).toBe(a_cs);
|
||||
expect(counters.a_ctrl_shift_alt).toBe(a_csa);
|
||||
expect(counters.a_alt).toBe(a_a);
|
||||
};
|
||||
|
||||
console.log('[ShortcutService] ... trigger A, expect counters CTRL+A, CTRL+SHIFT+A, CTRL+SHIFT+ALT+A, ALT+A to remain at 0');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE));
|
||||
verifyCounters(1,0,0,0,0);
|
||||
|
||||
console.log('[ShortcutService] ... trigger CTRL+A, expect counters CTRL+SHIFT+A, CTRL+SHIFT+ALT+A, ALT+A to remain at 0');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).withCtrlKey());
|
||||
verifyCounters(1,1,0,0,0);
|
||||
|
||||
console.log('[ShortcutService] ... trigger CTRL+A, expect counters CTRL+SHIFT+ALT+A, ALT+A to remain at 0');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).withCtrlKey().withShiftKey());
|
||||
verifyCounters(1,1,1,0,0);
|
||||
|
||||
console.log('[ShortcutService] ... trigger CTRL+A, expect counter ALT+A to remain at 0');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).withCtrlKey().withShiftKey().withAltKey());
|
||||
verifyCounters(1,1,1,1,0);
|
||||
|
||||
console.log('[ShortcutService] ... trigger CTRL+A, expect all counters at 1');
|
||||
service.onKeyDown_(createEvent(A_KEYCODE).withAltKey());
|
||||
verifyCounters(1,1,1,1,1);
|
||||
});
|
||||
|
||||
});
|
|
@ -16,7 +16,7 @@ describe("Storage Service test suite", function() {
|
|||
save : function () {}
|
||||
};
|
||||
pskl.app.shortcutService = {
|
||||
addShortcut : function () {}
|
||||
registerShortcut : function () {}
|
||||
};
|
||||
|
||||
storageService = new pskl.service.storage.StorageService();
|
||||
|
|
Loading…
Reference in a new issue