From e8db80a0ece7645da4bf295b5df1b9a3ae27ae8f Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 4 Sep 2014 08:34:17 +0200 Subject: [PATCH] Extracted ColorPicker code to dedicated widget package (noooooooo) ; Added basic palette creation mechanism (list colors + add color) --- src/css/color-picker-slider.css | 96 ++++++++++ src/css/dialogs-create-palette-method.css | 21 +++ .../dialogs/CreatePaletteController.js | 172 +++++------------- .../dialogs/CreatePaletteMethodController.js | 63 +++++++ .../controller/widgets/HslRgbColorPicker.js | 141 ++++++++++++++ src/piskel-script-list.js | 3 + .../dialogs/create-palette-method.html | 28 +++ src/templates/dialogs/create-palette.html | 1 + 8 files changed, 400 insertions(+), 125 deletions(-) create mode 100644 src/css/color-picker-slider.css create mode 100644 src/css/dialogs-create-palette-method.css create mode 100644 src/js/controller/dialogs/CreatePaletteMethodController.js create mode 100644 src/js/controller/widgets/HslRgbColorPicker.js create mode 100644 src/templates/dialogs/create-palette-method.html diff --git a/src/css/color-picker-slider.css b/src/css/color-picker-slider.css new file mode 100644 index 00000000..05156f72 --- /dev/null +++ b/src/css/color-picker-slider.css @@ -0,0 +1,96 @@ +.color-picker-slider * { + box-sizing: border-box; +} + +.color-picker-slider input[type="range"] { + -webkit-appearance: none; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + width: 100%; + border: none; + padding: 1px 2px; + border-radius: 3px; + background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); + box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; + outline: none; /* no focus outline */ +} + +/* thumb */ + +.color-picker-slider input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + cursor:pointer; + width: 7px; + height: 18px; + border: none; + border-radius: 2px; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ + background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; + background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ +} +.color-picker-slider input[type="range"]::-moz-range-thumb { + width: 7px; + height: 18px; + border: none; + border-radius: 2px; + background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ +} + +.color-picker-slider input[type="range"]::-ms-thumb { + width: 7px; + height: 18px; + border-radius: 2px; + border: 0; + background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ +} + +/*CROSS BROWSER RESET*/ + + +.color-picker-slider input[type="range"]::-moz-range-track { + border: inherit; + background: transparent; +} + +.color-picker-slider input[type="range"]::-ms-track { + border: inherit; + color: transparent; /* don't drawn vertical reference line */ + background: transparent; +} + +.color-picker-slider input[type="range"]::-ms-fill-lower, +.color-picker-slider input[type="range"]::-ms-fill-upper { + background: transparent; +} + +.color-picker-slider input[type="range"]::-ms-tooltip { + display: none; +} + +.color-picker-slider { + padding: 0 10px; + height : 25px; + overflow: hidden; +} + +.color-picker-slider span{ + line-height : 25px; + width : 10px; + float:left; +} + +.color-picker-slider input[type="range"]{ + float:left; + height : 10px; + width : 100px; + margin: 7px 5px; +} + +.color-picker-slider input[type="text"]{ + float:left; + width : 47px; + margin-left: 5px; +} + +.color-picker-slider input[type="range"][data-dimension="h"] { + background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); +} \ No newline at end of file diff --git a/src/css/dialogs-create-palette-method.css b/src/css/dialogs-create-palette-method.css new file mode 100644 index 00000000..767b6c1e --- /dev/null +++ b/src/css/dialogs-create-palette-method.css @@ -0,0 +1,21 @@ +#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/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js index 89d6db77..26551f7b 100644 --- a/src/js/controller/dialogs/CreatePaletteController.js +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -4,6 +4,8 @@ ns.CreatePaletteController = function (piskelController) { this.tinyColor = null; this.hsvColor = {h:0,s:0,v:0}; + this.palette = []; + this.selectedIndex = -1; }; pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); @@ -11,138 +13,58 @@ ns.CreatePaletteController.prototype.init = function () { this.superclass.init.call(this); - $(".color-picker-spectrum").spectrum({ - flat: true, - showInput: true, - showButtons: false, - change : this.setColor.bind(this) - }); - - this.tinyColorPickerContainer = document.querySelector('.color-picker-container'); - this.tinyColorPickerContainer.addEventListener('input', this.onPickerInput_.bind(this)); - + this.colorsList = document.querySelector('.colors-list'); + this.colorPickerContainer = document.querySelector('.color-picker-container'); this.colorPreviewEl = document.querySelector('.color-preview'); - this.setColor("#000000"); - }; + this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - ns.CreatePaletteController.prototype.onPickerInput_ = function (evt) { - var target = evt.target; + this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(this.colorPickerContainer, this.onColorUpdated_.bind(this)); + this.hslRgbColorPicker.init(); - var model = target.dataset.model; - var dimension = target.dataset.dimension; - var value = parseInt(target.value, 10); - - if (dimension === 'v' || dimension === 's') { - value = value/100; - } - - var color; - if (model === 'rgb') { - color = this.tinyColor.toRgb(); - } else if (model === 'hsv') { - color = this.hsvColor; - } - - if (isNaN(value)) { - value = color[dimension]; - } else { - color[dimension] = value; - } - - this.setColor(color); - }; - - ns.CreatePaletteController.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.onColorUpdated_(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.CreatePaletteController.prototype.toTinyColor_ = function (color) { - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } else { - return window.tinycolor(JSON.parse(JSON.stringify(color))); - } - }; - - ns.CreatePaletteController.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : Math.max(0, Math.min(255, color.h)), - s : Math.max(0, Math.min(1, color.s)), - v : Math.max(0, Math.min(1, color.v)) - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - ns.CreatePaletteController.prototype.updateInputs = function () { - var inputs = this.tinyColorPickerContainer.querySelectorAll('input'); - var rgb = this.tinyColor.toRgb(); - - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - if (model === 'rgb') { - input.value = rgb[dimension]; - } else if (model === 'hsv') { - var value = this.hsvColor[dimension]; - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - input.value = Math.round(value); - } - - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.CreatePaletteController.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - if (model === 'hsv') { - start = JSON.parse(JSON.stringify(this.hsvColor)); - start[dimension] = 0; - - end = JSON.parse(JSON.stringify(this.hsvColor)); - end[dimension] = 1; - } else { - start = this.tinyColor.toRgb(); - start[dimension] = 0; - - end = this.tinyColor.toRgb(); - end[dimension] = 255; - } - var colorStart = window.tinycolor(start).toRgbString(); - var colorEnd = window.tinycolor(end).toRgbString(); - slider.style.backgroundImage = "linear-gradient(to right, " + colorStart + " 0, " + colorEnd + " 100%)"; - } + this.refresh_(); }; ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) { this.colorPreviewEl.style.background = color.toRgbString(); + this.palette[this.selectedIndex] = color.toRgbString(); + this.refresh_(); + }; + + 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); + } + }; + + ns.CreatePaletteController.prototype.selectColor_ = function (index) { + this.selectedIndex = 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.refresh_ = function () { + var html = ""; + var tpl = '
'; + this.palette.forEach(function (color, index) { + html += pskl.utils.Template.replace(tpl, {color:color, index:index}); + }); + + html += '
ADD
'; + + this.colorsList.innerHTML = html; }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteMethodController.js b/src/js/controller/dialogs/CreatePaletteMethodController.js new file mode 100644 index 00000000..7fcd17fe --- /dev/null +++ b/src/js/controller/dialogs/CreatePaletteMethodController.js @@ -0,0 +1,63 @@ +(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/widgets/HslRgbColorPicker.js b/src/js/controller/widgets/HslRgbColorPicker.js new file mode 100644 index 00000000..093d67c5 --- /dev/null +++ b/src/js/controller/widgets/HslRgbColorPicker.js @@ -0,0 +1,141 @@ +(function () { + var ns = $.namespace('pskl.controller.widgets'); + + ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { + this.container = container; + this.colorUpdatedCallback = colorUpdatedCallback; + }; + + ns.HslRgbColorPicker.prototype.init = function () { + this.container.addEventListener('input', this.onPickerInput_.bind(this)); + + this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); + + $(this.spectrumEl).spectrum({ + flat: true, + showInput: true, + showButtons: false, + move : this.setColor.bind(this), + change : this.setColor.bind(this) + }); + + this.setColor("#000000"); + }; + + + ns.HslRgbColorPicker.prototype.onPickerInput_ = function (evt) { + var target = evt.target; + + var model = target.dataset.model; + var dimension = target.dataset.dimension; + + var value = parseInt(target.value, 10); + if (dimension === 'v' || dimension === 's') { + value = value/100; + } + + var color; + if (model === 'rgb') { + color = this.tinyColor.toRgb(); + } else if (model === 'hsv') { + color = this.hsvColor; + } + + if (isNaN(value)) { + value = color[dimension]; + } else { + color[dimension] = value; + } + + this.setColor(color); + }; + + ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { + if (!this.unplugged) { + this.unplugged = true; + + this.hsvColor = this.toHsvColor_(inputColor); + this.tinyColor = this.toTinyColor_(inputColor); + + this.updateInputs(); + $(".color-picker-spectrum").spectrum("set", this.tinyColor); + + this.colorUpdatedCallback(this.tinyColor); + + this.unplugged = false; + } + }; + + ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { + if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { + return color; + } else { + return window.tinycolor(JSON.parse(JSON.stringify(color))); + } + }; + + ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { + var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); + if (isHsvColor) { + return { + h : Math.max(0, Math.min(255, color.h)), + s : Math.max(0, Math.min(1, color.s)), + v : Math.max(0, Math.min(1, color.v)) + }; + } else { + return this.toTinyColor_(color).toHsv(); + } + }; + + ns.HslRgbColorPicker.prototype.updateInputs = function () { + var inputs = this.container.querySelectorAll('input'); + var rgb = this.tinyColor.toRgb(); + + + for (var i = 0 ; i < inputs.length ; i++) { + var input = inputs[i]; + var dimension = input.dataset.dimension; + var model = input.dataset.model; + + if (model === 'rgb') { + input.value = rgb[dimension]; + } else if (model === 'hsv') { + var value = this.hsvColor[dimension]; + if (dimension === 'v' || dimension === 's') { + value = 100 * value; + } + input.value = Math.round(value); + } + + if (input.getAttribute('type') === 'range') { + this.updateSliderBackground(input); + } + } + }; + + ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { + var dimension = slider.dataset.dimension; + var model = slider.dataset.model; + + var start, end; + var isHueSlider = dimension === 'h'; + if (!isHueSlider) { + if (model === 'hsv') { + start = JSON.parse(JSON.stringify(this.hsvColor)); + start[dimension] = 0; + + end = JSON.parse(JSON.stringify(this.hsvColor)); + end[dimension] = 1; + } else { + start = this.tinyColor.toRgb(); + start[dimension] = 0; + + end = this.tinyColor.toRgb(); + end[dimension] = 255; + } + var colorStart = window.tinycolor(start).toRgbString(); + var colorEnd = window.tinycolor(end).toRgbString(); + slider.style.backgroundImage = "linear-gradient(to right, " + colorStart + " 0, " + colorEnd + " 100%)"; + } + }; +})(); \ No newline at end of file diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 2a793268..87ecb90e 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -109,6 +109,9 @@ // Dialogs controller "js/controller/dialogs/DialogsController.js", + // Widget controller + "js/controller/widgets/HslRgbColorPicker.js", + // Services "js/service/LocalStorageService.js", "js/service/GithubStorageService.js", diff --git a/src/templates/dialogs/create-palette-method.html b/src/templates/dialogs/create-palette-method.html new file mode 100644 index 00000000..646a942a --- /dev/null +++ b/src/templates/dialogs/create-palette-method.html @@ -0,0 +1,28 @@ +
+

+ 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 679d1c4e..a5e48d51 100644 --- a/src/templates/dialogs/create-palette.html +++ b/src/templates/dialogs/create-palette.html @@ -9,6 +9,7 @@ Name :
+