From 8441f28ac14a4de58f8ea5f9421c92041b05a5da Mon Sep 17 00:00:00 2001 From: jdescottes Date: Sat, 6 Sep 2014 12:37:11 +0200 Subject: [PATCH] Palette creator can save palettes to local storage --- package.json | 2 +- src/css/dialogs-create-palette-method.css | 21 - src/css/dialogs-create-palette.css | 78 ++++ src/css/dialogs-manage-palettes.css | 212 ---------- src/css/toolbox-palettes-list.css | 22 +- src/index.html | 1 - src/js/Constants.js | 1 - src/js/app.js | 6 +- src/js/controller/PalettesListController.js | 74 ++-- .../dialogs/CreatePaletteController.js | 135 +++++-- .../dialogs/CreatePaletteMethodController.js | 63 --- .../controller/dialogs/DialogsController.js | 10 +- .../dialogs/PaletteManagerController.js | 382 ------------------ src/js/model/Palette.js | 38 ++ src/js/service/PaletteService.js | 61 +++ src/js/utils/Uuid.js | 17 + src/piskel-script-list.js | 5 +- src/piskel-style-list.js | 2 - .../dialogs/create-palette-method.html | 28 -- src/templates/dialogs/create-palette.html | 18 +- src/templates/dialogs/manage-palettes.html | 57 --- src/templates/palettes-list.html | 22 +- test/js/model/PaletteTest.js | 23 ++ test/js/service/PaletteServiceTest.js | 144 +++++++ test/js/utils/UuidTest.js | 27 ++ 25 files changed, 603 insertions(+), 846 deletions(-) delete mode 100644 src/css/dialogs-create-palette-method.css delete mode 100644 src/css/dialogs-manage-palettes.css delete mode 100644 src/js/controller/dialogs/CreatePaletteMethodController.js delete mode 100644 src/js/controller/dialogs/PaletteManagerController.js create mode 100644 src/js/model/Palette.js create mode 100644 src/js/service/PaletteService.js create mode 100644 src/js/utils/Uuid.js delete mode 100644 src/templates/dialogs/create-palette-method.html delete mode 100644 src/templates/dialogs/manage-palettes.html create mode 100644 test/js/model/PaletteTest.js create mode 100644 test/js/service/PaletteServiceTest.js create mode 100644 test/js/utils/UuidTest.js diff --git a/package.json b/package.json index 1da0caa1..679f704b 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "karma": "0.12.17", "karma-chrome-launcher": "^0.1.4", "karma-phantomjs-launcher": "^0.1.4", - "karma-jasmine": "^0.1.5", + "karma-jasmine": "^0.2.0", "nodewebkit": "~0.10.1" }, "window": { diff --git a/src/css/dialogs-create-palette-method.css b/src/css/dialogs-create-palette-method.css deleted file mode 100644 index 767b6c1e..00000000 --- a/src/css/dialogs-create-palette-method.css +++ /dev/null @@ -1,21 +0,0 @@ -#dialog-container.create-palette-method { - width: 500px; - height: 200px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette-method { - margin-top: -100px; -} - -.create-palette-method-item { - line-height : 24px; -} - -.create-palette-method-item label{ - margin-top: 3px; - margin-left: 5px; -} \ No newline at end of file diff --git a/src/css/dialogs-create-palette.css b/src/css/dialogs-create-palette.css index 4fa3b0db..ffbbab28 100644 --- a/src/css/dialogs-create-palette.css +++ b/src/css/dialogs-create-palette.css @@ -51,6 +51,84 @@ margin: 11px; } +.colors-list { + overflow : hidden; + width : 280px; +} + +.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ + position:relative; + float : left; + + width : 44px; + height : 44px; + margin : 10px 0 0 10px; + + box-sizing : border-box; + + cursor : pointer; +} + +.create-palette-color { + border:1px solid #2c2c2c; + transition : border-color 0.2s; +} +.create-palette-color:hover { + border:1px solid gold; +} + +.colors-list-drop-proxy { + border:2px dotted #eee; +} + +.create-palette-new-color { + border:2px dotted gold; + + border-radius: 2px; + line-height: 40px; + text-align: center; + font-size: 20px; + color: gold; +} + +.create-palette-color.selected { + border:2px solid gold; +} + +.create-palette-remove-color { + position: absolute; + top: 0; + right: 0; + padding: 2px 4px; + opacity : 0.2; + + font-weight: bold; + color: rgb(255,255,255); + text-shadow : 0 0 1px rgb(0,0,0); + + transition : opacity 0.3s, color 0.1s; +} + +.light-color .create-palette-remove-color { + color: rgb(0,0,0); + text-shadow : 0 0 1px rgb(255,255,255); +} + +.selected .create-palette-remove-color { + top: -1px; + right: -1px; +} + +.create-palette-color:hover .create-palette-remove-color { + opacity: 0.6; +} + +.create-palette-color .create-palette-remove-color:hover { + opacity: 1; + color: rgb(240,80,80); + text-shadow : 0 0 1px rgb(0,0,0); +} + /*SPECTRUM OVERRIDES*/ .create-palette .sp-container{ diff --git a/src/css/dialogs-manage-palettes.css b/src/css/dialogs-manage-palettes.css deleted file mode 100644 index 0d867a09..00000000 --- a/src/css/dialogs-manage-palettes.css +++ /dev/null @@ -1,212 +0,0 @@ -.palette-manager-wrapper { - height: 100%; - position: relative; -} - -.palette-manager-body { - position: absolute; - top: 45px; - bottom: 0; - right: 0; - left: 0; -} - -.palette-manager-head { - position: absolute; - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.palette-manager-drawer { - width: 200px; - position: absolute; - top: 0; - bottom: 0; -} - -.palette-manager-list { - position: absolute; - top:40px; - right: 0; - bottom: 0; - left: 0; - overflow: auto; -} - -.palette-manager-actions { - position: absolute; - height:40px; - line-height:40px; - width: 100%; - text-align: center; -} - -.palette-manager-actions-button { - width: 80px; - margin: 5px; -} - -.palette-manager-palette-button, -.palette-manager-actions-button { - line-height: 20px; -} - -.palette-manager-list li { - height: 48px; - line-height: 48px; - padding-left:10px; - - font-size: 1.4em; - - box-sizing: border-box; - -moz-box-sizing: border-box; - - border-bottom: 1px solid #666; - cursor:pointer; -} - -.palette-manager-list li:hover { - background : #222; -} - -.palette-manager-list li.selected { - color : gold; - font-weight: bold; -} - -.palette-manager-list li:nth-child(1) { - border-top: 1px solid #666; -} - -.palette-manager-details { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 200px; - - box-sizing: border-box; - -moz-box-sizing: border-box; - - border-left:1px solid #666; -} - -.palette-manager-details-head { - position: absolute; - height:40px; - line-height:40px; - width: 100%; - - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.palette-manager-details-head-name { - padding: 0 10px 0 20px; - font-size: 1.5em; - font-weight: bold; -} - -.palette-manager-details-head .edit-icon { - width: 24px; - display: inline-block; - background-size: 16px; -} - -.palette-manager-details-head-actions { - float: right; - line-height: 40px; - padding-right: 10px; -} - -.palette-manager-details-body { - position: absolute; - top:40px; - right: 0; - bottom: 0; - left: 0; - overflow: auto; - - box-sizing: border-box; - -moz-box-sizing: border-box; -} - - - -.palette-manager-color-card { - width: 120px; - height: 180px; - display: inline-block; - position: relative; - margin: 20px 0 20px 20px; - box-shadow: 0 0 0px 0px gold; - transition: box-shadow 0.3s; -} - -.palette-manager-color-card:hover { - box-shadow: 0 0 4px 1px gold; -} - -.palette-manager-delete-card { - position: absolute; - top: 0; - right: 0; - width: 20px; - - text-align: center; - font-size: 1.6em; - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 2px rgb(0,0,0); - cursor: pointer; - - opacity : 0.2; - transition : opacity 0.3s, color 0.1s; -} - -.palette-manager-color-card:hover .palette-manager-delete-card { - opacity : 0.6; -} - -.palette-manager-color-card .palette-manager-delete-card:hover { - opacity : 1; - color: rgb(240,80,80); -} - -.palette-manager-new-color .palette-manager-color-square { - border: 3px dotted #888; - border-bottom-width: 0; - box-sizing: border-box; - -moz-box-sizing: border-box; - border-radius: 3px 3px 0 0; - cursor: pointer; - text-align: center; - font-size: 24px; - color: #888; - line-height: 120px; -} - -.palette-manager-color-square { - width: 120px; - height: 120px; - cursor: pointer; - /*background-image:url(../img/tools/eyedropper.png);*/ -} - -.palette-manager-color-details { - color : #666; - background: #eee; - height: 60px; - padding-left: 5px; -} - -.palette-manager-color-details li{ - line-height: 20px; - font-weight: bold; -} \ No newline at end of file diff --git a/src/css/toolbox-palettes-list.css b/src/css/toolbox-palettes-list.css index 10799c35..64d64218 100644 --- a/src/css/toolbox-palettes-list.css +++ b/src/css/toolbox-palettes-list.css @@ -55,8 +55,28 @@ border-right-color: transparent; } - .palettes-list-secondary-color:before { right: 1px; border-left-color: transparent; +} + +.palette-action { + width : 18px; + height : 18px; + line-height : 16px; + + text-align:center; + float : right; + font-size : 12px; + border: 1px solid gold; + border-radius : 2px; + box-sizing : border-box; + margin : 3px 3px 3px 0; + + cursor : pointer; + transition : color 0.3s; +} + +.palette-action:hover { + color : gold; } \ No newline at end of file diff --git a/src/index.html b/src/index.html index 7846b43a..969a082e 100644 --- a/src/index.html +++ b/src/index.html @@ -68,7 +68,6 @@
-
diff --git a/src/js/Constants.js b/src/js/Constants.js index f017ca5e..0ce59ab4 100644 --- a/src/js/Constants.js +++ b/src/js/Constants.js @@ -27,7 +27,6 @@ var Constants = { NO_PALETTE_ID : '__no-palette', CURRENT_COLORS_PALETTE_ID : '__current-colors', - MANAGE_PALETTE_ID : '__manage-palettes', // Used for Spectrum input PREFERRED_COLOR_FORMAT : 'rgb', diff --git a/src/js/app.js b/src/js/app.js index 0ed608b8..4932a16b 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -39,6 +39,9 @@ this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); this.piskelController.init(); + this.paletteService = new pskl.service.PaletteService(); + this.paletteService.init(); + this.paletteController = new pskl.controller.PaletteController(); this.paletteController.init(); @@ -129,9 +132,6 @@ if (pskl.devtools) { pskl.devtools.init(); } - - // FIXME : remove - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); }, loadPiskel_ : function (serializedPiskel, descriptor, fps) { diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 7d325dd0..11522faf 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -13,19 +13,26 @@ ns.PalettesListController = function (paletteController, usedColorService) { this.usedColorService = usedColorService; + this.paletteService = pskl.app.paletteService; this.paletteController = paletteController; }; ns.PalettesListController.prototype.init = function () { this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); + this.colorListContainer_ = document.querySelector('.palettes-list-colors'); this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - this.createPaletteButton_ = document.querySelector('.create-palette-button'); + + var createPaletteButton_ = document.querySelector('.create-palette-button'); + var paletteActions = document.querySelector('.palette-actions'); this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - this.createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); + + createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); + paletteActions.addEventListener('click', this.onPaletteActionsClick_.bind(this)); + $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); @@ -42,7 +49,7 @@ id : Constants.CURRENT_COLORS_PALETTE_ID, name : 'Current colors' }]; - palettes = palettes.concat(this.retrievePalettes()); + palettes = palettes.concat(this.paletteService.getPalettes()); var html = palettes.map(function (palette) { return pskl.utils.Template.replace('', palette); @@ -74,7 +81,7 @@ if (paletteId === Constants.CURRENT_COLORS_PALETTE_ID) { colors = this.usedColorService.getCurrentColors(); } else { - var palette = this.getPaletteById(paletteId, this.retrievePalettes()); + var palette = this.paletteService.getPaletteById(paletteId); if (palette) { colors = palette.colors; } @@ -87,14 +94,14 @@ return colors; }; - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - this.colorPaletteSelect_.value = paletteId; - }; - ns.PalettesListController.prototype.selectPaletteFromUserSettings = function () { this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE)); }; + ns.PalettesListController.prototype.selectPalette = function (paletteId) { + this.colorPaletteSelect_.value = paletteId; + }; + ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { var paletteId = this.colorPaletteSelect_.value; pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); @@ -102,7 +109,39 @@ }; ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette-method'); + $.publish(Events.DIALOG_DISPLAY, 'create-palette'); + }; + + ns.PalettesListController.prototype.onPaletteActionsClick_ = function (evt) { + var classList = evt.target.classList; + if (classList.contains('palette-action-edit')) { + this.editSelectedPalette_(); + } else if (classList.contains('palette-action-delete')) { + this.deleteSelectedPalette_(); + } else if (classList.contains('palette-action-download')) { + this.downloadSelectedPalette_(); + } + }; + + ns.PalettesListController.prototype.editSelectedPalette_ = function () { + var paletteId = this.colorPaletteSelect_.value; + $.publish(Events.DIALOG_DISPLAY, { + dialogId : 'create-palette', + initArgs : paletteId + }); + }; + + ns.PalettesListController.prototype.deleteSelectedPalette_ = function () { + var paletteId = this.colorPaletteSelect_.value; + var palette = this.paletteService.getPaletteById(paletteId); + if (window.confirm('Are you sure you want to delete palette ' + palette.name)) { + this.paletteService.deletePaletteById(palette.id); + this.selectPalette(Constants.CURRENT_COLORS_PALETTE_ID); + } + }; + + ns.PalettesListController.prototype.downloadSelectedPalette_ = function () { + window.alert('not implemented yet'); }; ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { @@ -155,21 +194,4 @@ this.selectPaletteFromUserSettings(); this.fillColorListContainer(); }; - - ns.PalettesListController.prototype.getPaletteById = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; - - ns.PalettesListController.prototype.retrievePalettes = function () { - var palettesString = window.localStorage.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js index 26551f7b..51a6c78b 100644 --- a/src/js/controller/dialogs/CreatePaletteController.js +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -2,22 +2,34 @@ var ns = $.namespace('pskl.controller.dialogs'); ns.CreatePaletteController = function (piskelController) { - this.tinyColor = null; - this.hsvColor = {h:0,s:0,v:0}; - this.palette = []; + this.paletteService = pskl.app.paletteService; this.selectedIndex = -1; }; pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - ns.CreatePaletteController.prototype.init = function () { + ns.CreatePaletteController.prototype.init = function (paletteId) { this.superclass.init.call(this); + console.log(paletteId); + if (paletteId) { + var palette = this.paletteService.getPaletteById(paletteId); + this.palette = pskl.model.Palette.fromObject(palette); + } else { + paletteId = pskl.utils.Uuid.generate(); + this.palette = new pskl.model.Palette(paletteId, 'New palette', []); + } this.colorsList = document.querySelector('.colors-list'); this.colorPickerContainer = document.querySelector('.color-picker-container'); this.colorPreviewEl = document.querySelector('.color-preview'); + this.submitButton = document.querySelector('.create-palette-submit'); + this.nameInput = document.querySelector('input[name="palette-name"]'); + this.nameInput.value = this.palette.name; + this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); + this.submitButton.addEventListener('click', this.onSubmitButtonClick_.bind(this)); + this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(this.colorPickerContainer, this.onColorUpdated_.bind(this)); this.hslRgbColorPicker.init(); @@ -26,45 +38,114 @@ }; ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) { - this.colorPreviewEl.style.background = color.toRgbString(); - this.palette[this.selectedIndex] = color.toRgbString(); - this.refresh_(); + var rgbColor = color.toRgbString(); + this.colorPreviewEl.style.background = rgbColor; + this.palette.set(this.selectedIndex, rgbColor); + + this.refreshColorElement_(this.selectedIndex); + }; + + /** + * Lightweight refresh only changing the color of one element of the palette color list + */ + ns.CreatePaletteController.prototype.refreshColorElement_ = function (index) { + var color = this.palette.get(this.selectedIndex); + var element = document.querySelector('[data-palette-index="'+index+'"]'); + if (element) { + element.style.background = color; + element.classList.toggle('light-color', this.isLight_(color)); + } }; ns.CreatePaletteController.prototype.onColorContainerClick_ = function (evt) { var target = evt.target; - if (target.dataset.paletteIndex) { - this.selectColor_(target.dataset.paletteIndex); - } else if (target.classList.contains('add-color-button')) { - this.palette.push(this.palette[this.selectedIndex] || "#000000"); - this.refresh_(); - this.selectColor_(this.palette.length-1); + if (target.classList.contains('create-palette-color')) { + this.onPaletteColorClick_(evt, target); + } else if (target.classList.contains('create-palette-new-color')) { + this.onNewColorClick_(evt, target); + } else if (target.classList.contains('create-palette-remove-color')) { + this.onRemoveColorClick_(evt, target); } + this.refresh_(); + }; + + ns.CreatePaletteController.prototype.onPaletteColorClick_ = function (evt, target) { + var index = parseInt(target.dataset.paletteIndex,10); + this.selectColor_(index); + }; + + ns.CreatePaletteController.prototype.onRemoveColorClick_ = function (evt, target) { + var colorElement = target.parentNode; + var index = parseInt(colorElement.dataset.paletteIndex,10); + this.removeColor_(index); + }; + + ns.CreatePaletteController.prototype.onNewColorClick_ = function (evt, target) { + var newColor = this.palette.get(this.selectedIndex) || '#000000'; + this.palette.add(newColor); + this.selectColor_(this.palette.size()-1); + }; + + ns.CreatePaletteController.prototype.onSubmitButtonClick_ = function (evt) { + this.paletteService.savePalette(this.palette); + this.closeDialog(); + }; + + ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { + this.palette.name = this.nameInput.value; }; ns.CreatePaletteController.prototype.selectColor_ = function (index) { this.selectedIndex = index; + this.hslRgbColorPicker.setColor(this.palette.get(index)); + }; - var previous = this.colorsList.querySelector('.selectedColor'); - if (previous) { - previous.classList.remove('selected'); - } - - var next = this.colorsList.querySelector('[data-palette-index="'+index+'"]'); - next.classList.add('selected'); - - this.hslRgbColorPicker.setColor(this.palette[index]); + ns.CreatePaletteController.prototype.removeColor_ = function (index) { + this.palette.removeAt(index); + this.refresh_(); }; ns.CreatePaletteController.prototype.refresh_ = function () { var html = ""; - var tpl = '
'; - this.palette.forEach(function (color, index) { - html += pskl.utils.Template.replace(tpl, {color:color, index:index}); - }); + var tpl = pskl.utils.Template.get('create-palette-color-template'); + var colors = this.palette.colors; - html += '
ADD
'; + colors.forEach(function (color, index) { + var isSelected = (index === this.selectedIndex); + + html += pskl.utils.Template.replace(tpl, { + color:color, index:index, + ':selected':isSelected, + ':light-color':this.isLight_(color) + }); + }.bind(this)); + + html += '
  • +
  • '; this.colorsList.innerHTML = html; + + $('.colors-list').sortable({ + placeholder: 'colors-list-drop-proxy', + update: this.onDrop_.bind(this), + items: '.create-palette-color' + }); + }; + + ns.CreatePaletteController.prototype.isLight_ = function (color) { + var rgb = window.tinycolor(color).toRgb(); + return rgb.r+rgb.b+rgb.g > 128*3; + }; + + + ns.CreatePaletteController.prototype.onDrop_ = function (evt, drop) { + var colorElement = drop.item.get(0); + + var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); + var newIndex = $('.create-palette-color').index(drop.item); + this.palette.move(oldIndex, newIndex); + + this.selectedIndex = newIndex; + + this.refresh_(); }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteMethodController.js b/src/js/controller/dialogs/CreatePaletteMethodController.js deleted file mode 100644 index 7fcd17fe..00000000 --- a/src/js/controller/dialogs/CreatePaletteMethodController.js +++ /dev/null @@ -1,63 +0,0 @@ -(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteMethodController = function (piskelController) { - }; - - pskl.utils.inherit(ns.CreatePaletteMethodController, ns.AbstractDialogController); - - ns.CreatePaletteMethodController.prototype.init = function () { - this.superclass.init.call(this); - - this.createButton = document.querySelector('.create-palette-method-continue'); - this.cancelButton = document.querySelector('.create-palette-method-cancel'); - - this.createButton.addEventListener('click', this.onCreateButtonClick_.bind(this)); - - this.cancelButton.addEventListener('click', function () { - $.publish(Events.DIALOG_HIDE); - }); - }; - - ns.CreatePaletteMethodController.prototype.onCreateButtonClick_ = function (evt) { - var method = this.getSelectedMethod_(); - - var initArgs = { - method : method - }; - - if (method === 'palette') { - initArgs.paletteId = this.getSelectedPaletteId_(); - } - - this.closeDialog(); - - window.setTimeout(function () { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : initArgs - }); - },500); - }; - - ns.CreatePaletteMethodController.prototype.getSelectedMethod_ = function (evt) { - var options = document.querySelectorAll('.create-palette-method-list input[type="radio"]'); - - var method; - for (var i = 0 ; i < options.length ; i++) { - console.log(options[i]); - if (options[i].checked) { - method = options[i].value; - } - } - - return method; - }; - - ns.CreatePaletteMethodController.prototype.getSelectedPaletteId_ = function (evt) { - var select = document.querySelector('.palettes-list-select'); - return select.value; - }; - - -})(); \ No newline at end of file diff --git a/src/js/controller/dialogs/DialogsController.js b/src/js/controller/dialogs/DialogsController.js index 02c99001..0d8008bf 100644 --- a/src/js/controller/dialogs/DialogsController.js +++ b/src/js/controller/dialogs/DialogsController.js @@ -2,14 +2,6 @@ var ns = $.namespace('pskl.controller.dialogs'); var dialogs = { - 'manage-palettes' : { - template : 'templates/dialogs/manage-palettes.html', - controller : ns.PaletteManagerController - }, - 'create-palette-method' : { - template : 'templates/dialogs/create-palette-method.html', - controller : ns.CreatePaletteMethodController - }, 'create-palette' : { template : 'templates/dialogs/create-palette.html', controller : ns.CreatePaletteController @@ -35,7 +27,7 @@ $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'manage-palettes')); + pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palettes')); this.dialogWrapper_.classList.add('animated'); }; diff --git a/src/js/controller/dialogs/PaletteManagerController.js b/src/js/controller/dialogs/PaletteManagerController.js deleted file mode 100644 index dc16ba4d..00000000 --- a/src/js/controller/dialogs/PaletteManagerController.js +++ /dev/null @@ -1,382 +0,0 @@ -(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var tinycolor = window.tinycolor; - - var SELECTED_CLASSNAME = 'selected'; - var NEW_COLOR_CLASS = 'palette-manager-new-color'; - var CLOSE_ICON_CLASS = 'palette-manager-delete-card'; - var EDIT_NAME_CLASS = 'edit-icon'; - - ns.PaletteManagerController = function (piskelController) { - this.piskelController = piskelController; - this.palettes = this.retrieveUserPalettes(); - this.originalPalettes = this.retrieveUserPalettes(); - this.selectedPaletteId = null; - - // Keep track of all spectrum instances created, to dispose them when closing the popup - this.spectrumContainers = []; - }; - - pskl.utils.inherit(ns.PaletteManagerController, ns.AbstractDialogController); - - ns.PaletteManagerController.prototype.init = function () { - this.superclass.init.call(this); - - this.palettesList = document.querySelector('.palette-manager-list'); - this.paletteBody = document.querySelector('.palette-manager-details-body'); - this.paletteHead = document.querySelector('.palette-manager-details-head'); - this.createButton = document.querySelector('.palette-manager-actions-button[data-action="create"]'); - this.saveAllButton = document.querySelector('.palette-manager-actions-button[data-action="save-all"]'); - - this.colorCardTemplate = pskl.utils.Template.get('palette-color-card-template'); - this.newColorTemplate = pskl.utils.Template.get('palette-new-color-template'); - this.paletteHeadTemplate = pskl.utils.Template.get('palette-details-head-template'); - - // Events - this.palettesList.addEventListener('click', this.onPaletteListClick.bind(this)); - // Delegated event listener for events repeated on all cards - this.paletteBody.addEventListener('click', this.delegatedPaletteBodyClick.bind(this)); - this.paletteHead.addEventListener('click', this.delegatedPaletteHeadClick.bind(this)); - this.createButton.addEventListener('click', this.onCreateClick_.bind(this)); - this.saveAllButton.addEventListener('click', this.saveAll.bind(this)); - - // Init markup - this.createPaletteListMarkup(); - if (this.palettes.length > 0) { - this.selectPalette(this.palettes[0].id); - } else { - this.createPalette('New palette'); - } - }; - - ns.PaletteManagerController.prototype.destroy = function () { - this.destroySpectrumPickers(); - }; - - ns.PaletteManagerController.prototype.onCreateClick_ = function (evt) { - this.createPalette(); - }; - - ns.PaletteManagerController.prototype.createPalette = function (name) { - if (!name) { - name = window.prompt('Please enter a name for your palette', 'New palette'); - } - if (name) { - var palette = this.createPaletteObject(name); - this.palettes.push(palette); - this.createPaletteListMarkup(); - this.selectPalette(palette.id); - } - }; - - ns.PaletteManagerController.prototype.createPaletteObject = function (name) { - return { - id : 'palette-' + Date.now() + '-' + Math.floor(Math.random()*1000), - name : name, - colors : [] - }; - }; - - ns.PaletteManagerController.prototype.redraw = function () { - this.createPaletteListMarkup(); - this.selectPalette(this.selectedPaletteId); - }; - - ns.PaletteManagerController.prototype.selectPalette = function (paletteId) { - this.deselectCurrentPalette(); - var paletteListItem = this.palettesList.querySelector('[data-palette-id='+paletteId+']'); - if (paletteListItem) { - this.selectedPaletteId = paletteId; - paletteListItem.classList.add(SELECTED_CLASSNAME); - this.refreshPaletteDetails(); - } - }; - - ns.PaletteManagerController.prototype.refreshPaletteDetails = function () { - this.createPaletteHeadMarkup(); - this.createPaletteBodyMarkup(); - this.initPaletteDetailsEvents(); - this.initPaletteCardsSpectrum(); - }; - - ns.PaletteManagerController.prototype.createPaletteListMarkup = function () { - var html = this.palettes.map(function (palette) { - var paletteCopy = { - id : palette.id, - name : this.isPaletteModified(palette) ? palette.name + " *" : palette.name - }; - return pskl.utils.Template.replace('
  • {{name}}
  • ', paletteCopy); - }.bind(this)).join(''); - this.palettesList.innerHTML = html; - }; - - /** - * Fill the palette body container with color cards for the selected palette - */ - ns.PaletteManagerController.prototype.createPaletteHeadMarkup = function () { - var palette = this.getSelectedPalette(); - var dict = { - 'name' : palette.name, - 'save:disabled' : !this.isPaletteModified(palette), - 'revert:disabled' : !this.isPaletteModified(palette), - 'delete:disabled' : this.palettes.length < 2 - }; - var html = pskl.utils.Template.replace(this.paletteHeadTemplate, dict); - - this.paletteHead.innerHTML = html; - }; - - ns.PaletteManagerController.prototype.isPaletteModified = function (palette) { - var isModified = false; - var originalPalette = this.getPaletteById(palette.id, this.originalPalettes); - if (originalPalette) { - var differentName = originalPalette.name !== palette.name; - var differentColors = palette.colors.join('') !== originalPalette.colors.join(''); - isModified = differentName || differentColors; - } else { - isModified = true; - } - return isModified; - }; - - /** - * Fill the palette body container with color cards for the selected palette - */ - ns.PaletteManagerController.prototype.createPaletteBodyMarkup = function () { - var palette = this.getSelectedPalette(); - - var html = this.getColorCardsMarkup(palette.colors); - html += pskl.utils.Template.replace(this.newColorTemplate, {classname : NEW_COLOR_CLASS}); - - this.paletteBody.innerHTML = html; - }; - - ns.PaletteManagerController.prototype.initPaletteDetailsEvents = function () { - // New Card click event - var newCard = this.paletteBody.querySelector('.' + NEW_COLOR_CLASS); - newCard.addEventListener('click', this.onNewCardClick.bind(this)); - - if (this.palettes.length < 2) { - var deleteButton = this.paletteHead.querySelector('.palette-manager-palette-button[data-action="delete"]'); - deleteButton.setAttribute("disabled", "disabled"); - } - }; - - ns.PaletteManagerController.prototype.onNewCardClick = function () { - var color; - var palette = this.getSelectedPalette(); - if (palette && palette.colors.length > 0) { - color = palette.colors[palette.colors.length-1]; - } else { - color = '#FFFFFF'; - } - this.addColorInSelectedPalette(color); - }; - - ns.PaletteManagerController.prototype.delegatedPaletteBodyClick = function (event) { - var target = event.target; - if (target.classList.contains(CLOSE_ICON_CLASS)) { - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - this.removeColorInSelectedPalette(colorId); - } - }; - - ns.PaletteManagerController.prototype.delegatedPaletteHeadClick = function (event) { - var target = event.target; - if (target.classList.contains(EDIT_NAME_CLASS)) { - this.renameSelectedPalette(); - } else if (target.classList.contains('palette-manager-palette-button')) { - var action = target.dataset.action; - if (action === 'save') { - this.savePalette(this.getSelectedPalette().id); - this.redraw(); - } else if (action === 'revert') { - this.revertChanges(); - } else if (action === 'delete') { - this.deleteSelectedPalette(); - } - } - }; - - ns.PaletteManagerController.prototype.getSpectrumSelector_ = function () { - return ':not(.' + NEW_COLOR_CLASS + ')>.palette-manager-color-square'; - }; - - ns.PaletteManagerController.prototype.initPaletteCardsSpectrum = function () { - var oSelf = this; - var container = $(this.getSpectrumSelector_()); - container.spectrum({ - clickoutFiresChange : true, - showInput: true, - showButtons: false, - change : function (color) { - var target = this; - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - oSelf.updateColorInSelectedPalette(colorId, color); - }, - beforeShow : function() { - var target = this; - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - var palette = oSelf.getSelectedPalette(); - var color = palette.colors[colorId]; - container.spectrum("set", color); - } - }); - - this.spectrumContainers.push(container); - }; - - /** - * Destroy all spectrum instances generated by the palette manager - */ - ns.PaletteManagerController.prototype.destroySpectrumPickers = function () { - this.spectrumContainers.forEach(function (container) { - container.spectrum("destroy"); - }); - this.spectrumContainers = []; - }; - - ns.PaletteManagerController.prototype.updateColorInSelectedPalette = function (colorId, color) { - var palette = this.getSelectedPalette(); - var hexColor = '#' + (color.toHex().toUpperCase()); - palette.colors.splice(colorId, 1, hexColor); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.addColorInSelectedPalette = function (color) { - var selectedPalette = this.getSelectedPalette(); - selectedPalette.colors.push(color); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.removeColorInSelectedPalette = function (colorId) { - var palette = this.getSelectedPalette(); - palette.colors.splice(colorId, 1); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.renameSelectedPalette = function () { - var palette = this.getSelectedPalette(); - var name = window.prompt('Please enter a new name for palette "' + palette.name + '"', palette.name); - if (name) { - palette.name = name; - this.redraw(); - } - }; - - ns.PaletteManagerController.prototype.getSelectedPalette = function () { - return this.getPaletteById(this.selectedPaletteId, this.palettes); - }; - - ns.PaletteManagerController.prototype.getColorCardsMarkup = function (colors) { - var html = colors.map(function (color, index) { - var dict = { - colorId : index, - hex : color, - rgb : tinycolor(color).toRgbString(), - hsl : tinycolor(color).toHslString() - }; - return pskl.utils.Template.replace(this.colorCardTemplate, dict); - }.bind(this)).join(''); - return html; - }; - - ns.PaletteManagerController.prototype.getPaletteById = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; - - ns.PaletteManagerController.prototype.removePaletteById = function (paletteId, palettes) { - var palette = this.getPaletteById(paletteId, palettes); - if (palette) { - var index = palettes.indexOf(palette); - palettes.splice(index, 1); - } - }; - - ns.PaletteManagerController.prototype.deselectCurrentPalette = function () { - var selectedItem = this.palettesList.querySelector('.' + SELECTED_CLASSNAME); - if (selectedItem) { - this.selectedPaletteId = null; - selectedItem.classList.remove(SELECTED_CLASSNAME); - } - }; - - ns.PaletteManagerController.prototype.revertChanges = function () { - var palette = this.getSelectedPalette(); - var originalPalette = this.getPaletteById(palette.id, this.originalPalettes); - palette.name = originalPalette.name; - palette.colors = originalPalette.colors.slice(0); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.deleteSelectedPalette = function () { - var palette = this.getSelectedPalette(); - if (this.palettes.length > 1) { - if (window.confirm('Are you sure you want to delete "' + palette.name + '" ?')) { - this.removePaletteById(palette.id, this.palettes); - this.removePaletteById(palette.id, this.originalPalettes); - - this.persistToLocalStorage(); - - this.createPaletteListMarkup(); - this.selectPalette(this.palettes[0].id); - } - } - }; - - ns.PaletteManagerController.prototype.onPaletteListClick = function (event) { - var target = event.target; - if (target.dataset.paletteId) { - this.selectPalette(target.dataset.paletteId); - } - }; - - ns.PaletteManagerController.prototype.saveAll = function () { - this.palettes.forEach(function (palette) { - this.savePalette(palette.id); - }.bind(this)); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.savePalette = function (paletteId) { - var palette = this.getPaletteById(paletteId, this.palettes); - var originalPalette = this.getPaletteById(paletteId, this.originalPalettes); - if (originalPalette) { - originalPalette.name = palette.name; - originalPalette.colors = palette.colors; - } else { - this.originalPalettes.push(palette); - } - - this.persistToLocalStorage(); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteManagerController.prototype.persistToLocalStorage = function () { - window.localStorage.setItem('piskel.palettes', JSON.stringify(this.originalPalettes)); - this.originalPalettes = this.retrieveUserPalettes(); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteManagerController.prototype.retrieveUserPalettes = function () { - var palettesString = window.localStorage.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; - -})(); \ No newline at end of file diff --git a/src/js/model/Palette.js b/src/js/model/Palette.js new file mode 100644 index 00000000..d2bc04de --- /dev/null +++ b/src/js/model/Palette.js @@ -0,0 +1,38 @@ +(function () { + var ns = $.namespace('pskl.model'); + + ns.Palette = function (id, name, colors) { + this.id = id; + this.name = name; + this.colors = colors; + }; + + ns.Palette.fromObject = function (paletteObj) { + var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); + return new ns.Palette(paletteObj.id, paletteObj.name, colors); + }; + + ns.Palette.prototype.get = function (index) { + return this.colors[index]; + }; + + ns.Palette.prototype.set = function (index, color) { + this.colors[index] = color; + }; + + ns.Palette.prototype.add = function (color) { + this.colors.push(color); + }; + + ns.Palette.prototype.size = function () { + return this.colors.length; + }; + + ns.Palette.prototype.removeAt = function (index) { + this.colors.splice(index, 1); + }; + + ns.Palette.prototype.move = function (oldIndex, newIndex) { + this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); + }; +})(); \ No newline at end of file diff --git a/src/js/service/PaletteService.js b/src/js/service/PaletteService.js new file mode 100644 index 00000000..7188ab55 --- /dev/null +++ b/src/js/service/PaletteService.js @@ -0,0 +1,61 @@ +(function () { + var ns = $.namespace('pskl.service'); + ns.PaletteService = function () { + this.palettes = []; + this.localStorageService = window.localStorage; + }; + + ns.PaletteService.prototype.init = function () {}; + + ns.PaletteService.prototype.getPalettes = function () { + var palettesString = this.localStorageService.getItem('piskel.palettes'); + return JSON.parse(palettesString) || []; + }; + + ns.PaletteService.prototype.getPaletteById = function (paletteId) { + var palettes = this.getPalettes(); + return this.findPaletteInArray_(paletteId, palettes); + }; + + ns.PaletteService.prototype.savePalette = function (palette) { + var palettes = this.getPalettes(); + var existingPalette = this.findPaletteInArray_(palette.id, palettes); + if (existingPalette) { + var currentIndex = palettes.indexOf(existingPalette); + palettes.splice(currentIndex, 1, palette); + } else { + palettes.push(palette); + } + + this.savePalettes_(palettes); + + $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); + window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); + }; + + ns.PaletteService.prototype.deletePaletteById = function (id) { + var palettes = this.getPalettes(); + var filteredPalettes = palettes.filter(function (palette) { + return palette.id !== id; + }); + + this.savePalettes_(filteredPalettes); + }; + + ns.PaletteService.prototype.savePalettes_ = function (palettes) { + this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); + $.publish(Events.PALETTE_LIST_UPDATED); + }; + + ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { + var match = null; + + palettes.forEach(function (palette) { + if (palette.id === paletteId) { + match = palette; + } + }); + + return match; + }; +})(); \ No newline at end of file diff --git a/src/js/utils/Uuid.js b/src/js/utils/Uuid.js new file mode 100644 index 00000000..685d315c --- /dev/null +++ b/src/js/utils/Uuid.js @@ -0,0 +1,17 @@ +(function(){ + var ns = $.namespace('pskl.utils'); + + var s4 = function () { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + }; + + ns.Uuid = { + generate : function () { + return 'ss-s-s-s-sss'.replace(/s/g, function () { + return s4(); + }); + } + }; +})(); \ No newline at end of file diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 87ecb90e..a699101a 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -25,6 +25,7 @@ "js/utils/PiskelFileUtils.js", "js/utils/Template.js", "js/utils/UserSettings.js", + "js/utils/Uuid.js", "js/utils/Xhr.js", "js/utils/serialization/Serializer.js", "js/utils/serialization/Deserializer.js", @@ -50,6 +51,7 @@ "js/model/Layer.js", "js/model/piskel/Descriptor.js", "js/model/frame/CachedFrameProcessor.js", + "js/model/Palette.js", "js/model/Piskel.js", // Selection @@ -99,9 +101,7 @@ // Dialogs sub-controllers "js/controller/dialogs/AbstractDialogController.js", - "js/controller/dialogs/PaletteManagerController.js", "js/controller/dialogs/CreatePaletteController.js", - "js/controller/dialogs/CreatePaletteMethodController.js", "js/controller/dialogs/ImportImageController.js", "js/controller/dialogs/BrowseLocalController.js", @@ -119,6 +119,7 @@ "js/service/BackupService.js", "js/service/BeforeUnloadService.js", "js/service/HistoryService.js", + "js/service/PaletteService.js", "js/service/SavedStatusService.js", "js/service/keyboard/ShortcutService.js", "js/service/keyboard/KeycodeTranslator.js", diff --git a/src/piskel-style-list.js b/src/piskel-style-list.js index 65ebdcca..e20c191d 100644 --- a/src/piskel-style-list.js +++ b/src/piskel-style-list.js @@ -14,10 +14,8 @@ "css/color-picker-slider.css", "css/dialogs.css", "css/dialogs-import-image.css", - "css/dialogs-manage-palettes.css", "css/dialogs-browse-local.css", "css/dialogs-create-palette.css", - "css/dialogs-create-palette-method.css", "css/toolbox.css", "css/toolbox-layers-list.css", "css/toolbox-palettes-list.css", diff --git a/src/templates/dialogs/create-palette-method.html b/src/templates/dialogs/create-palette-method.html deleted file mode 100644 index 646a942a..00000000 --- a/src/templates/dialogs/create-palette-method.html +++ /dev/null @@ -1,28 +0,0 @@ -
    -

    - Create palette - X -

    -
    - Select your creation method : -
      -
    • - - -
    • -
    • - -
      -
    • -
    • - - - -
    • -
    - - -
    -
    \ No newline at end of file diff --git a/src/templates/dialogs/create-palette.html b/src/templates/dialogs/create-palette.html index a5e48d51..79d783d6 100644 --- a/src/templates/dialogs/create-palette.html +++ b/src/templates/dialogs/create-palette.html @@ -4,12 +4,11 @@ X
    -
    - Name : + Name :
    -
    +
      @@ -46,8 +45,7 @@
      - - +
      + +
      \ No newline at end of file diff --git a/src/templates/dialogs/manage-palettes.html b/src/templates/dialogs/manage-palettes.html deleted file mode 100644 index 3b1dc019..00000000 --- a/src/templates/dialogs/manage-palettes.html +++ /dev/null @@ -1,57 +0,0 @@ -
      -

      - Palette manager - X -

      -
      -
      -
      - - -
      -
        -
      -
      -
      -
      -
      -
      -
      -
      - - - - - - \ No newline at end of file diff --git a/src/templates/palettes-list.html b/src/templates/palettes-list.html index bfffbe50..f103c8eb 100644 --- a/src/templates/palettes-list.html +++ b/src/templates/palettes-list.html @@ -1,18 +1,30 @@
      -

      Palettes -
      +

      -
      +
      dl
      +
      d
      +
      e