From a7109fe0cb5b5af65ef77785c15207eb46482d98 Mon Sep 17 00:00:00 2001
From: tocque <364004564@qq.com>
Date: Sat, 22 Dec 2018 23:19:21 +0900
Subject: [PATCH] colorPicker
---
_server/colorPicker/colorPicker.data.js | 28 +
_server/colorPicker/colorPicker.js | 1414 +++++++++++++++++++++++
_server/colorPicker/colors.js | 732 ++++++++++++
_server/colorPicker/jsColor.js | 258 +++++
_server/css/editor.css | 23 +
editor.html | 37 +
6 files changed, 2492 insertions(+)
create mode 100644 _server/colorPicker/colorPicker.data.js
create mode 100644 _server/colorPicker/colorPicker.js
create mode 100644 _server/colorPicker/colors.js
create mode 100644 _server/colorPicker/jsColor.js
diff --git a/_server/colorPicker/colorPicker.data.js b/_server/colorPicker/colorPicker.data.js
new file mode 100644
index 00000000..e4169baf
--- /dev/null
+++ b/_server/colorPicker/colorPicker.data.js
@@ -0,0 +1,28 @@
+;(function(window, undefined){
+ "use strict"
+
+ // see colorPicker.html for the following encrypted variables... will only be used in buildView()
+ var _html = ('^§app alpha-bg-w">^§slds">^§sldl-1">$^§sldl-2">$^§sldl-3">$^§curm">$^§sldr-1">$^§sldr-2">$^§sldr-4">$^§curl">$^§curr">$$^§opacity">|^§opacity-slider">$$$^§memo">^§raster">$^§raster-bg">$|$|$|$|$|$|$|$|$^§memo-store">$^§memo-cursor">$$^§panel">^§hsv">^hsl-mode §ß">$^hsv-h-ß §ß">H$^hsv-h-~ §~">-^§nsarrow">$$^hsl-h-@ §@">H$^hsv-s-ß §ß">S$^hsv-s-~ §~">-$^hsl-s-@ §@">S$^hsv-v-ß §ß">B$^hsv-v-~ §~">-$^hsl-l-@ §@">L$$^§hsl §hide">^hsv-mode §ß">$^hsl-h-ß §ß">H$^hsl-h-~ §~">-$^hsv-h-@ §@">H$^hsl-s-ß §ß">S$^hsl-s-~ §~">-$^hsv-s-@ §@">S$^hsl-l-ß §ß">L$^hsl-l-~ §~">-$^hsv-v-@ §@">B$$^§rgb">^rgb-r-ß §ß">R$^rgb-r-~ §~">-$^rgb-r-@ §ß"> $^rgb-g-ß §ß">G$^rgb-g-~ §~">-$^rgb-g-@ §ß"> $^rgb-b-ß §ß">B$^rgb-b-~ §~">-$^rgb-b-@ §ß"> $$^§cmyk">^Lab-mode §ß">$^cmyk-c-ß §@">C$^cmyk-c-~ §~">-$^Lab-L-@ §@">L$^cmyk-m-ß §@">M$^cmyk-m-~ §~">-$^Lab-a-@ §@">a$^cmyk-y-ß §@">Y$^cmyk-y-~ §~">-$^Lab-b-@ §@">b$^cmyk-k-ß §@">K$^cmyk-k-~ §~">-$^Lab-x-@ §ß"> $$^§Lab §hide">^cmyk-mode §ß">$^Lab-L-ß §@">L$^Lab-L-~ §~">-$^cmyk-c-@ §@">C$^Lab-a-ß §@">a$^Lab-a-~ §~">-$^cmyk-m-@ §@">M$^Lab-b-ß §@">b$^Lab-b-~ §~">-$^cmyk-y-@ §@">Y$^Lab-x-ß §@"> $^Lab-x-~ §~">-$^cmyk-k-@ §@">K$$^§alpha">^alpha-ß §ß">A$^alpha-~ §~">-$^alpha-@ §ß">W$$^§HEX">^HEX-ß §ß">#$^HEX-~ §~">-$^HEX-@ §ß">M$$^§ctrl">^§raster">$^§cont">$^§cold">$^§col1">| $$^§col2">| $$^§bres">RESET$^§bsav">SAVE$$$^§exit">$^§resize">$^§resizer">|$$$').
+ replace(/\^/g, '
prevent showing the accelerator menu
+ // document.selection.empty();
+ // }
+ window[cancelAnimationFrame](_renderTimer);
+ removeEvent(_isIE ? document.body : window, 'mousemove', _mouseMoveAction);
+ if (_delayState) { // hapens on inputs
+ _valueType = {type: 'alpha'};
+ renderAll();
+ }
+ // this is dirty... has to do with M|W|! button
+ if (typeof _mouseMoveAction === 'function' || typeof _mouseMoveAction === 'number') {
+ delete _options.webUnsave;
+ }
+
+ _delayState = 1;
+ _mouseMoveAction = undefined;
+
+ changeClass(_nodes.slds, 'do-drag', '');
+ changeClass(_nodes.panel, '(?:start-change|do-change)', '');
+
+ _nodes.resizer.style.cssText = '';
+ _nodes.panelCover.style.cssText = '';
+
+ _nodes.memo_store.style.cssText = 'background-color: ' +
+ color2string(_colors.RND.rgb) + '; ' + getOpacityCSS(_colors.alpha);
+ _nodes.memo.className = _nodes.memo.className.replace(/\s+(?:dark|light)/, '') +
+ // (/dark/.test(_nodes.colorPicker.className) ? ' dark' : ' light');
+ (_colors['rgbaMix' + _bgTypes[_options.alphaBG]].luminance < 0.22 ? ' dark' : ' light');
+ // (_colors.rgbaMixCustom.luminance < 0.22 ? ' dark' : ' light')
+
+ _valueType = undefined;
+
+ resetCursors();
+
+ if (_options.actionCallback) {
+ _options.actionCallback(e, _action || mouseMoveAction.name || action || 'external');
+ }
+ }
+ }
+
+ function changeXYValue(e) {
+ var event = e || window.event,
+ scale = _options.scale,
+ page = getPageXY(event),
+ x = (page.X - _targetOrigin.left) * (scale === 4 ? 2 : scale),
+ y = (page.Y - _targetOrigin.top) * scale,
+ mode = _options.mode;
+
+ _colors[mode.type][mode.x] = limitValue(x / 255, 0, 1);
+ _colors[mode.type][mode.y] = 1 - limitValue(y / 255, 0, 1);
+ convertColors();
+ return preventDefault(event);
+ }
+
+ function changeZValue(e) { // make this part of changeXYValue
+ var event = e || window.event,
+ page = getPageXY(event),
+ z = (page.Y - _targetOrigin.top) * _options.scale,
+ mode = _options.mode;
+
+ _colors[mode.type][mode.z] = 1 - limitValue(z / 255, 0, 1);
+ convertColors();
+ return preventDefault(event);
+ }
+
+ function changeOpacityValue(e) {
+ var event = e || window.event,
+ page = getPageXY(event);
+
+ _newData = true;
+ _colors.alpha = limitValue(_math.round(
+ (page.X - _targetOrigin.left) / _targetOrigin.width * 100), 0, 100
+ ) / 100;
+ convertColors('alpha');
+ return preventDefault(event);
+ }
+
+ function changeInputValue(e) {
+ var event = e || window.event,
+ page = getPageXY(event),
+ delta = _startCoords.pageY - page.Y,
+ delayOffset = _options.delayOffset,
+ type = _valueType.type,
+ isAlpha = type === 'alpha',
+ ranges;
+
+ if (_delayState || _math.abs(delta) >= delayOffset) {
+ if (!_delayState) {
+ _delayState = (delta > 0 ? -delayOffset : delayOffset) +
+ (+_mainTarget.firstChild.data) * (isAlpha ? 100 : 1);
+ _startCoords.pageY += _delayState;
+ delta += _delayState;
+ _delayState = 1;
+ changeClass(_nodes.panel, 'start-change', 'do-change');
+ _nodes.panelCover.style.cssText = 'position:absolute;left:0;top:0;right:0;bottom:0';
+ // window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
+ document.activeElement.blur();
+ _renderTimer = window[requestAnimationFrame](renderAll);
+ }
+
+ if (type === 'cmyk' && _options.cmyOnly) {
+ type = 'cmy';
+ }
+
+ if (isAlpha) {
+ _newData = true;
+ _colors.alpha = limitValue(delta / 100, 0, 1);
+ } else {
+ ranges = _valueRanges[type][_valueType.z];
+ _colors[type][_valueType.z] = type === 'Lab' ? limitValue(delta, ranges[0], ranges[1]) :
+ limitValue(delta / ranges[1], 0, 1);
+ }
+ convertColors(isAlpha ? 'alpha' : type);
+ // event.returnValue is deprecated. Please use the standard event.preventDefault() instead.
+ // event.returnValue = false; // see: pauseEvent(event);
+ return preventDefault(event);
+ }
+ }
+
+ function keyControl(e) { // this is quite big for what it does...
+ var event = e || window.event,
+ keyCode = event.which || event.keyCode,
+ key = String.fromCharCode(keyCode),
+ elm = document.activeElement,
+
+ cln = elm.className.replace(_options.CSSPrefix, '').split('-'),
+ type = cln[0],
+ mode = cln[1],
+
+ isAlpha = type === 'alpha',
+ isHex = type === 'HEX',
+ arrowKey = {k40: -1, k38: 1, k34: -10, k33: 10}['k' + keyCode] / (isAlpha ? 100 : 1),
+ validKeys = {'HEX': /[0-9a-fA-F]/, 'Lab': /[\-0-9]/, 'alpha': /[\.0-9]/}[type] || /[0-9]/,
+ valueRange = _valueRanges[type][type] || _valueRanges[type][mode], // let op!
+
+ textNode = elm.firstChild, // chnge on TAB key
+ rangeData = caret(elm),
+ origValue = textNode.data, // do not change
+ value,
+ val = origValue === '0' && !isHex ? [] : origValue.split(''); // gefixt
+
+ if (/^(?:27|13)$/.test(keyCode)) { // ENTER || ESC
+ preventDefault(event);
+ elm.blur();
+ } else if (event.type === 'keydown') { // functional keys
+ if (arrowKey) { // arrow/page keys
+ value = limitValue(_math.round((+origValue + arrowKey) * 1e+6) / 1e+6, valueRange[0], valueRange[1]);
+ } else if (/^(?:8|46)$/.test(keyCode)) { // DELETE / BACKSPACE
+ if (!rangeData.range) {
+ rangeData.range++;
+ rangeData.start -= keyCode === 8 ? 1 : 0;
+ }
+ val.splice(rangeData.start, rangeData.range);
+ value = val.join('') || '0'; // never loose elm.firstChild
+ }
+
+ if (value !== undefined) { // prevent keypress
+ preventDefault(event, true);
+ }
+ } else if (event.type === 'keypress') {
+ if (!/^(?:37|39|8|46|9)$/.test(keyCode)) { // left, right,DEL, BACK, TAB for FF
+ preventDefault(event, true);
+ }
+ if (validKeys.test(key)) { // regular input
+ val.splice(rangeData.start, rangeData.range, key);
+ value = val.join('');
+ }
+ rangeData.start++;
+ }
+
+ if (keyCode === 13 && isHex) {
+ if (textNode.data.length % 3 === 0 || textNode.data === '0') { // textNode.data.length &&
+ return _colorPicker.setColor(textNode.data === '0' ? '000' : textNode.data, 'rgb', _colors.alpha, true);
+ } else {
+ preventDefault(event, true);
+ return elm.focus();
+ }
+ }
+
+ if (isHex && value !== undefined) {
+ value = /^0+/.test(value) ? value : parseInt(''+value, 16) || 0;
+ }
+
+ if (value !== undefined && value !== '' && +value >= valueRange[0] && +value <= valueRange[1]) {
+ if (isHex) {
+ value = value.toString(16).toUpperCase() || '0';
+ }
+ if (isAlpha) {
+ _colors[type] = +value;
+ } else if (!isHex) {
+ _colors[type][mode] = +value / (type === 'Lab' ? 1 : valueRange[1]);
+ }
+ convertColors(isAlpha ? 'alpha' : type);
+
+ preRenderAll(_colors);
+ _mouseMoveAction = true;
+ stopChange(e, event.type);
+
+ textNode.data = value; // if
+ caret(elm, _math.min(elm.firstChild.data.length, rangeData.start < 0 ? 0 : rangeData.start));
+ }
+ }
+
+ function buttonActions(e) {
+ var event = e || window.event,
+ target = event.target || event.srcElement,
+ targetClass = target.className,
+ parent = target.parentNode,
+ options = _options,
+ RGB = _colors.RND.rgb,
+ customBG, alphaBG,
+ mode = _options.mode,
+ newMode = '',
+ prefix = options.CSSPrefix,
+ isModeButton = /(?:hs|rgb)/.test(parent.className) && /^[HSBLRG]$/.test(
+ target.firstChild ? target.firstChild.data : ''
+ ),
+ isDblClick = /dblc/.test(event.type),
+ buttonAction = ''; // think this over again....
+
+ if (isDblClick && !isModeButton) {
+ return;
+ } else if (targetClass.indexOf('-labl ' + prefix + 'labl') !== -1) { // HSB -> HSL; CMYK -> Lab buttons
+ changeClass(_nodes[targetClass.split('-')[0]], prefix + 'hide', '');
+ changeClass(_nodes[parent.className.split('-')[1]], prefix + 'hide');
+ } else if (targetClass.indexOf(prefix + 'butt') !== -1) { // BUTTONS
+ if (isModeButton) { // set render modes
+ if (isDblClick && _options.scale === 2) {
+ newMode = /hs/.test(mode.type) ? 'rgb' : /hide/.test(_nodes.hsl.className) ? 'hsv' : 'hsl';
+ newMode = newMode + '-' + newMode[mode.type.indexOf(mode.z)];
+ }
+ _colorPicker.setMode(newMode ? newMode : targetClass.replace('-butt', '').split(' ')[0]);
+ buttonAction = 'modeChange';
+ } else if (/^[rgb]/.test(targetClass)) { // no vertical slider rendering in RGB mode
+ newMode = targetClass.split('-')[1];
+ changeClass(_nodes.colorPicker, 'no-rgb-' + newMode,
+ (options['noRGB' + newMode] = !options['noRGB' + newMode]) ? undefined : '');
+ buttonAction = 'noRGB' + newMode;
+ // preRenderAll();
+ } else if (target === _nodes.alpha_labl) { // alpha button right (background of raster)
+ customBG = options.customBG;
+ alphaBG = options.alphaBG;
+ changeClass(_nodes.colorPicker, 'alpha-bg-' + alphaBG, 'alpha-bg-' +
+ (alphaBG = options.alphaBG = e.data || (alphaBG === 'w' ? (customBG ? 'c' : 'b') :
+ alphaBG === 'c' ? 'b' : 'w')));
+ target.firstChild.data = alphaBG.toUpperCase();
+ _nodes.ctrl.style.backgroundColor = _nodes.memo.style.backgroundColor =
+ alphaBG !== 'c' ? '' : 'rgb(' + _math.round(customBG.r * 255) + ', ' +
+ _math.round(customBG.g * 255) + ', ' +
+ _math.round(customBG.b * 255) + ')';
+ _nodes.raster.style.cssText = _nodes.raster_bg.previousSibling.style.cssText =
+ alphaBG !== 'c' ? '' : getOpacityCSS(customBG.luminance < 0.22 ? 0.5 : 0.4);
+ buttonAction = 'alphaBackground';
+ } else if (target === _nodes.alpha_butt) { // alpha button left (disable alpha rendering)
+ changeClass(_nodes.colorPicker, 'mute-alpha', (options.muteAlpha = !options.muteAlpha) ? undefined : '');
+ buttonAction = 'alphaState';
+ } else if (target === _nodes.HEX_butt) { // make it on/off
+ changeClass(_nodes.colorPicker, 'no-HEX', (options.HEXState = !options.HEXState) ? undefined : '');
+ buttonAction = 'HEXState';
+ } else if (target === _nodes.HEX_labl) { // web save state change
+ var isWebSave = _colors.saveColor === 'web save';
+
+ if (_colors.saveColor !== 'web smart' && !isWebSave) {
+ options.webUnsave = copyColor(RGB);
+ _colorPicker.setColor(_colors.webSmart, 'rgb');
+ } else if (!isWebSave) {
+ if (!options.webUnsave) {
+ options.webUnsave = copyColor(RGB);
+ }
+ _colorPicker.setColor(_colors.webSave, 'rgb');
+ } else {
+ _colorPicker.setColor(options.webUnsave, 'rgb');
+ }
+ buttonAction = 'webColorState';
+ } else if (/Lab-x-labl/.test(targetClass)) { //target === _nodes.cmyk_type) {
+ // switch between CMYK and CMY
+ changeClass(_nodes.colorPicker, 'cmy-only', (options.cmyOnly = !options.cmyOnly) ? undefined : '');
+ buttonAction = 'cmykState';
+ }
+ } else if (target === _nodes.bsav) { // SAVE
+ saveAsBackground();
+ buttonAction = 'saveAsBackground';
+ } else if (target === _nodes.bres) { // RESET
+ var tmpColor = copyColor(RGB),
+ tmpAlpha = _colors.alpha;
+
+ // a bit heavy but... doesn't matter here
+ // newCol, type, alpha, forceRender
+ _colorPicker.setColor(options.color);
+ saveAsBackground();
+ _colorPicker.setColor(tmpColor, 'rgb', tmpAlpha);
+ buttonAction = 'resetColor';
+ } else if (parent === _nodes.col1) { // COLOR left
+ // _colors.hsv.h = (_colors.hsv.h + 0.5) % 1; // not acurate
+ _colors.hsv.h -= (_colors.hsv.h > 0.5 ? 0.5 : -0.5);
+ convertColors('hsv');
+ buttonAction = 'shiftColor';
+
+ } else if (parent === _nodes.col2) { // COLOR right
+ _colorPicker.setColor(target.style.backgroundColor, 'rgb', _colors.background.alpha);
+ buttonAction = 'setSavedColor';
+ } else if (parent === _nodes.memo) { // MEMORIES // revisit...
+ var resetBlink = function() {
+ if (_nodes.memos.blinker) _nodes.memos.blinker.style.cssText = _nodes.memos.cssText;
+ },
+ doBlink = function(elm) {
+ _nodes.memos.blinker = elm;
+ elm.style.cssText = 'background-color:' + (_colors.RGBLuminance > 0.22 ? '#333' : '#DDD');
+ window.setTimeout(resetBlink, 200);
+ };
+
+ if (target === _nodes.memo_cursor) { // save color in memo
+ resetBlink();
+ _nodes.memos.blinker = undefined;
+ _nodes.testNode.style.cssText = _nodes.memo_store.style.cssText;
+ _nodes.memos.cssText = _nodes.testNode.style.cssText; // ...how browser sees css
+ for (var n = _nodes.memos.length - 1; n--; ) { // check if color already exists
+ if (_nodes.memos.cssText === _nodes.memos[n].style.cssText) {
+ doBlink(_nodes.memos[n]); // sets _nodes.memos.blinker
+ break;
+ }
+ }
+ if (!_nodes.memos.blinker) { // right shift colors
+ for (var n = _nodes.memos.length - 1; n--; ) {
+ _nodes.memos[n + 1].style.cssText = _nodes.memos[n].style.cssText;
+ }
+ _nodes.memos[0].style.cssText = _nodes.memo_store.style.cssText;
+ }
+ buttonAction = 'toMemory';
+ } else { // reset color from memo
+ resetBlink();
+ _colorPicker.setColor(target.style.backgroundColor, 'rgb', target.style.opacity || 1);
+ _nodes.memos.cssText = target.style.cssText;
+ doBlink(target);
+ // this is dirty... has to do with M|W|! button
+ _mouseMoveAction = 1;
+ buttonAction = 'fromMemory';
+ }
+
+ }
+ // think this over again, does this need to be like this??
+ if (buttonAction) {
+ preRenderAll(_colors);
+ _mouseMoveAction = _mouseMoveAction || true; // !!!! search for: // this is dirty...
+ stopChange(e, buttonAction);
+ }
+ }
+
+ function resizeApp(e, size) {
+ var event = e || window.event,
+ page = event ? getPageXY(event) : {},
+ isSize = size !== undefined,
+ x = isSize ? size : page.X - _targetOrigin.left + 8,
+ y = isSize ? size : page.Y - _targetOrigin.top + 8,
+ values = [' S XS XXS', ' S XS', ' S', ''],
+ sizes = _options.sizes, // from getUISizes();
+ currentSize = isSize ? size :
+ y < sizes.XXS[1] + 25 ? 0 :
+ x < sizes.XS[0] + 25 ? 1 :
+ x < sizes.S[0] + 25 || y < sizes.S[1] + 25 ? 2 : 3,
+ value = values[currentSize],
+ isXXS = false,
+ mode,
+ tmp = '';
+
+ if (_cashedVars.resizer !== value) {
+ isXXS = /XX/.test(value);
+ mode = _options.mode;
+
+ if (isXXS && (!/hs/.test(mode.type) || mode.z === 'h')) {
+ tmp = mode.type + '-' + mode.z;
+ _colorPicker.setMode(/hs/.test(mode.type) ? mode.type + '-s': 'hsv-s');
+ _options.mode.original = tmp;
+ } else if (mode.original) {
+ // setMode(mode) creates a new object so mode.original gets deleted automatically
+ _colorPicker.setMode(mode.original);
+ }
+
+ _nodes.colorPicker.className = _nodes.colorPicker.className.replace(/\s+(?:S|XS|XXS)/g, '') + value;
+ _options.scale = isXXS ? 4 : /S/.test(value) ? 2 : 1;
+ _options.currentSize = currentSize;
+
+ _cashedVars.resizer = value;
+
+ // fix this... from this point on inside if() ... convertColors();
+ _newData = true;
+ renderAll();
+ resetCursors();
+ }
+
+ _nodes.resizer.style.cssText = 'display: block;' +
+ 'width: ' + (x > 10 ? x : 10) + 'px;' +
+ 'height: ' + (y > 10 ? y : 10) + 'px;';
+ }
+
+ // ------------------------------------------------------ //
+ // --- Colors calculation and rendering related stuff --- //
+ // -------------------------------------------------------//
+
+ function setMode(mode) {
+ var ModeMatrix = {
+ rgb_r : {x: 'b', y: 'g'},
+ rgb_g : {x: 'b', y: 'r'},
+ rgb_b : {x: 'r', y: 'g'},
+
+ hsv_h : {x: 's', y: 'v'},
+ hsv_s : {x: 'h', y: 'v'},
+ hsv_v : {x: 'h', y: 's'},
+
+ hsl_h : {x: 's', y: 'l'},
+ hsl_s : {x: 'h', y: 'l'},
+ hsl_l : {x: 'h', y: 's'}
+ },
+ key = mode.replace('-', '_'),
+ regex = '\\b(?:rg|hs)\\w\\-\\w\\b'; // \\b\\w{3}\\-\\w\\b';
+
+ // changeClass(_nodes.colorPicker, '(?:.*?)$', mode);
+ // changeClass(_nodes.colorPicker, '\\b\\w{3}\\-\\w\\b', mode);
+ // changeClass(_nodes.slds, '\\b\\w{3}\\-\\w\\b', mode);
+ changeClass(_nodes.panel, regex, mode);
+ changeClass(_nodes.slds, regex, mode);
+
+ mode = mode.split('-');
+ return _options.mode = {
+ type: mode[0],
+ x: ModeMatrix[key].x,
+ y: ModeMatrix[key].y,
+ z: mode[1]
+ };
+ }
+
+ function initSliders() { // function name...
+ var regex = /\s+(?:hue-)*(?:dark|light)/g,
+ className = 'className'; // minification
+
+ _nodes.curl[className] = _nodes.curl[className].replace(regex, ''); // .....
+ _nodes.curr[className] = _nodes.curr[className].replace(regex, ''); // .....
+ _nodes.slds[className] = _nodes.slds[className].replace(regex, '');
+ // var sldrs = ['sldr_2', 'sldr_4', 'sldl_3'];
+ // for (var n = sldrs.length; n--; ) {
+ // _nodes[sldrs[n]][className] = _options.CSSPrefix + sldrs[n].replace('_', '-');
+ // }
+ _nodes.sldr_2[className] = _options.CSSPrefix + 'sldr-2';
+ _nodes.sldr_4[className] = _options.CSSPrefix + 'sldr-4';
+ _nodes.sldl_3[className] = _options.CSSPrefix + 'sldl-3';
+
+ for (var style in _nodes.styles) {
+ if (!style.indexOf('sld')) _nodes.styles[style].cssText = '';
+ }
+ _cashedVars = {};
+ }
+
+ function resetCursors() {
+ // _renderVars.isNoRGB = undefined;
+ _nodes.styles.curr.cssText = _nodes.styles.curl.cssText; // only coordinates
+ _nodes.curl.className = _options.CSSPrefix + 'curl' + (
+ _renderVars.noRGBZ ? ' ' + _options.CSSPrefix + 'curl-' +_renderVars.noRGBZ: '');
+ _nodes.curr.className = _options.CSSPrefix + 'curr ' + _options.CSSPrefix + 'curr-' +
+ (_options.mode.z === 'h' ? _renderVars.HUEContrast : _renderVars.noRGBZ ?
+ _renderVars.noRGBZ : _renderVars.RGBLuminance);
+ }
+
+ function convertColors(type) {
+ preRenderAll(_colorInstance.setColor(undefined, type || _options.mode.type));
+ _newData = true;
+ }
+
+ function saveAsBackground(refresh) {
+ _colorInstance.saveAsBackground();
+ _nodes.styles.col2.cssText = 'background-color: ' + color2string(_colors.background.RGB) + ';' +
+ getOpacityCSS(_colors.background.alpha);
+
+ if (refresh) {
+ preRenderAll(_colors);
+ // renderAll();
+ }
+ return (_colors);
+ }
+
+ function preRenderAll(colors) {
+ var _Math = _math,
+ renderVars = _renderVars,
+ bgType = _bgTypes[_options.alphaBG];
+
+ renderVars.hueDelta = _Math.round(colors['rgbaMixBGMix' + bgType].hueDelta * 100);
+ // renderVars.RGBLuminanceDelta = _Math.round(colors.RGBLuminanceDelta * 100);
+ renderVars.luminanceDelta = _Math.round(colors['rgbaMixBGMix' + bgType].luminanceDelta * 100);
+ renderVars.RGBLuminance = colors.RGBLuminance > 0.22 ? 'light' : 'dark';
+ renderVars.HUEContrast = colors.HUELuminance > 0.22 ? 'light' : 'dark';
+ // renderVars.contrast = renderVars.RGBLuminanceDelta > renderVars.hueDelta ? 'contrast' : '';
+ renderVars.contrast = renderVars.luminanceDelta > renderVars.hueDelta ? 'contrast' : '';
+ renderVars.readabiltiy =
+ colors['rgbaMixBGMix' + bgType].WCAG2Ratio >= 7 ? 'green' :
+ colors['rgbaMixBGMix' + bgType].WCAG2Ratio >= 4.5 ? 'orange': '';
+ renderVars.noRGBZ = _options['no' + _options.mode.type.toUpperCase() + _options.mode.z] ?
+ (_options.mode.z === 'g' && colors.rgb.g < 0.59 || _options.mode.z === 'b' || _options.mode.z === 'r' ?
+ 'dark' : 'light') : undefined;
+ }
+
+ function renderAll() { // maybe render alpha seperately...
+ if (_mouseMoveAction) {
+ // _renderTimer = window[requestAnimationFrame](renderAll);
+ if (!_newData) return (_renderTimer = window[requestAnimationFrame](renderAll));
+ _newData = false;
+ }
+ // console.time('renderAll');
+ var options = _options,
+ mode = options.mode,
+ scale = options.scale,
+ prefix = options.CSSPrefix,
+ colors = _colors,
+ nodes = _nodes,
+ CSS = nodes.styles,
+ textNodes = nodes.textNodes,
+ valueRanges = _valueRanges,
+ valueType = _valueType,
+ renderVars = _renderVars,
+ cashedVars = _cashedVars,
+
+ _Math = _math,
+ _getOpacityCSS = getOpacityCSS,
+ _color2string = color2string,
+
+ a = 0,
+ b = 0,
+ x = colors[mode.type][mode.x],
+ X = _Math.round(x * 255 / (scale === 4 ? 2 : scale)),
+ y_ = colors[mode.type][mode.y],
+ y = 1 - y_,
+ Y = _Math.round(y * 255 / scale),
+ z = 1 - colors[mode.type][mode.z],
+ Z = _Math.round(z * 255 / scale),
+ coords = (1 === 1) ? [x, y_] : [0, 0], // (1 === 2) button label up
+
+ isRGB = mode.type === 'rgb',
+ isHue = mode.z === 'h',
+ isHSL = mode.type === 'hsl',
+ isHSL_S = isHSL && mode.z === 's',
+ moveXY = _mouseMoveAction === changeXYValue,
+ moveZ = _mouseMoveAction === changeZValue,
+ display, tmp, value, slider;
+
+ if (isRGB) {
+ if (coords[0] >= coords[1]) b = 1; else a = 1;
+ if (cashedVars.sliderSwap !== a) {
+ nodes.sldr_2.className = options.CSSPrefix + 'sldr-' + (3 - a);
+ cashedVars.sliderSwap = a;
+ }
+ }
+ if ((isRGB && !moveZ) || (isHue && !moveXY) || (!isHue && !moveZ)) {
+ CSS[isHue ? 'sldl_2' : 'sldr_2'][isRGB ? 'cssText' : 'backgroundColor'] =
+ isRGB ? _getOpacityCSS((coords[a] - coords[b]) / (1 - (coords[b]) || 0)) : _color2string(colors.hueRGB);
+ }
+ if (!isHue) {
+ if (!moveZ) CSS.sldr_4.cssText = _getOpacityCSS(isRGB ? coords[b] : isHSL_S ? _Math.abs(1 - y * 2) : y);
+ if (!moveXY) CSS.sldl_3.cssText = _getOpacityCSS(isHSL && mode.z === 'l' ? _Math.abs(1 - z * 2) : z);
+ if (isHSL) { // switch slider class name for black/white color half way through in HSL(S|L) mode(s)
+ slider = isHSL_S ? 'sldr_4' : 'sldl_3';
+ tmp = isHSL_S ? 'r-' : 'l-';
+ value = isHSL_S ? (y > 0.5 ? 4 : 3) : (z > 0.5 ? 3 : 4);
+
+ if (cashedVars[slider] !== value) {
+ nodes[slider].className = options.CSSPrefix + 'sld' + tmp + value;
+ cashedVars[slider] = value;
+ }
+ }
+ }
+
+ if (!moveZ) CSS.curm.cssText = 'left: ' + X + 'px; top: ' + Y + 'px;';
+ if (!moveXY) CSS.curl.top = Z + 'px';
+ if (valueType) CSS.curr.top = Z + 'px'; // && valueType.type !== mode.type
+ if ((valueType && valueType.type === 'alpha') || _mainTarget === nodes.opacity) {
+ CSS.opacity_slider.left = options.opacityPositionRelative ? (colors.alpha * (
+ (_targetOrigin.width || nodes.opacity.offsetWidth) -
+ (_targetOrigin.childWidth || nodes.opacity_slider.offsetWidth))) + 'px' :
+ (colors.alpha * 100) + '%';
+ }
+
+ CSS.col1.cssText = 'background-color: ' + _color2string(colors.RND.rgb) + '; ' +
+ (options.muteAlpha ? '' : _getOpacityCSS(colors.alpha));
+ CSS.opacity.backgroundColor = _color2string(colors.RND.rgb);
+ CSS.cold.width = renderVars.hueDelta + '%';
+ CSS.cont.width = renderVars.luminanceDelta + '%';
+
+ for (display in textNodes) {
+ tmp = display.split('_');
+ if (options.cmyOnly) {
+ tmp[0] = tmp[0].replace('k', '');
+ }
+ value = tmp[1] ? colors.RND[tmp[0]][tmp[1]] : colors.RND[tmp[0]] || colors[tmp[0]];
+ if (cashedVars[display] !== value) {
+ cashedVars[display] = value;
+ textNodes[display].data = value > 359.5 && display !== 'HEX' ? 0 : value;
+
+ if (display !== 'HEX' && !options.noRangeBackground) {
+ value = colors[tmp[0]][tmp[1]] !== undefined ? colors[tmp[0]][tmp[1]] : colors[tmp[0]];
+ if (tmp[0] === 'Lab') {
+ value = (value - valueRanges[tmp[0]][tmp[1]][0]) /
+ (valueRanges[tmp[0]][tmp[1]][1] - valueRanges[tmp[0]][tmp[1]][0]);
+ }
+ CSS[display].backgroundPosition = _Math.round((1 - value) * 100) + '% 0%';
+ }
+ }
+ }
+ // Lab out of gammut
+ tmp = colors._rgb ? [
+ colors._rgb.r !== colors.rgb.r,
+ colors._rgb.g !== colors.rgb.g,
+ colors._rgb.b !== colors.rgb.b
+ ] : [];
+ if (tmp.join('') !== cashedVars.outOfGammut) {
+ nodes.rgb_r_labl.firstChild.data = tmp[0] ? '!' : ' ';
+ nodes.rgb_g_labl.firstChild.data = tmp[1] ? '!' : ' ';
+ nodes.rgb_b_labl.firstChild.data = tmp[2] ? '!' : ' ';
+ cashedVars.outOfGammut = tmp.join('');
+ }
+ if (renderVars.noRGBZ) {
+ if (cashedVars.noRGBZ !== renderVars.noRGBZ) {
+ nodes.curl.className = prefix + 'curl ' + prefix + 'curl-' + renderVars.noRGBZ;
+
+ if (!moveZ) {
+ nodes.curr.className = prefix + 'curr ' + prefix + 'curr-' + renderVars.noRGBZ;
+ }
+ cashedVars.noRGBZ = renderVars.noRGBZ;
+ }
+ }
+ if (cashedVars.HUEContrast !== renderVars.HUEContrast && mode.z === 'h') {
+ nodes.slds.className = nodes.slds.className.replace(/\s+hue-(?:dark|light)/, '') +
+ ' hue-' + renderVars.HUEContrast;
+ if (!moveZ) {
+ nodes.curr.className = prefix + 'curr ' + prefix + 'curr-' + renderVars.HUEContrast;
+ }
+ cashedVars.HUEContrast = renderVars.HUEContrast;
+ } else if (cashedVars.RGBLuminance !== renderVars.RGBLuminance) { // test for no else
+ nodes.colorPicker.className = nodes.colorPicker.className.replace(/\s+(?:dark|light)/, '') +
+ ' ' + renderVars.RGBLuminance;
+ if (!moveZ && mode.z !== 'h' && !renderVars.noRGBZ) {
+ nodes.curr.className = prefix + 'curr ' + prefix + 'curr-' + renderVars.RGBLuminance;
+ }
+ cashedVars.RGBLuminance = renderVars.RGBLuminance;
+ }
+
+ if (cashedVars.contrast !== renderVars.contrast || cashedVars.readabiltiy !== renderVars.readabiltiy) {
+ nodes.ctrl.className = nodes.ctrl.className.replace(' contrast', '').replace(/\s*(?:orange|green)/, '') +
+ (renderVars.contrast ? ' ' + renderVars.contrast : '') +
+ (renderVars.readabiltiy ? ' ' + renderVars.readabiltiy : '');
+ cashedVars.contrast = renderVars.contrast;
+ cashedVars.readabiltiy = renderVars.readabiltiy;
+ }
+
+ if (cashedVars.saveColor !== colors.saveColor) {
+ nodes.HEX_labl.firstChild.data = !colors.saveColor ? '!' : colors.saveColor === 'web save' ? 'W' : 'M';
+ cashedVars.saveColor = colors.saveColor;
+ }
+
+ if (options.renderCallback) {
+ options.renderCallback(colors, mode); // maybe more parameters
+ }
+
+ if (_mouseMoveAction) {
+ _renderTimer = window[requestAnimationFrame](renderAll);
+ }
+
+ // console.timeEnd('renderAll')
+ }
+
+
+ // ------------------------------------------------------ //
+ // ------------------ helper functions ------------------ //
+ // -------------------------------------------------------//
+
+ function copyColor(color) {
+ var newColor = {};
+
+ for (var n in color) {
+ newColor[n] = color[n];
+ }
+ return newColor;
+ }
+
+ // function color2string(color, type) {
+ // var out = [],
+ // n = 0;
+
+ // type = type || 'rgb';
+ // while (type.charAt(n)) { // IE7 // V8 type[n] ||
+ // out.push(color[type.charAt(n)]);
+ // n++;
+ // }
+ // return type + '(' + out.join(', ') + ')';
+ // }
+
+ function color2string(color, type) { // ~2 x faster on V8
+ var out = '',
+ t = (type || 'rgb').split(''),
+ n = t.length;
+
+ for ( ; n--; ) {
+ out = ', ' + color[t[n]] + out;
+ }
+ return (type || 'rgb') + '(' + out.substr(2) + ')';
+ }
+
+
+ function limitValue(value, min, max) {
+ // return Math.max(min, Math.min(max, value)); // faster??
+ return (value > max ? max : value < min ? min : value);
+ }
+
+ function getOpacityCSS(value) {
+ if (value === undefined) value = 1;
+
+ if (_doesOpacity) {
+ return 'opacity: ' + (_math.round(value * 10000000000) / 10000000000) + ';'; // value.toFixed(16) = 99% slower
+ // some speed test:
+ // return ['opacity: ', (Math.round(value * 1e+10) / 1e+10), ';'].join('');
+ } else {
+ return 'filter: alpha(opacity=' + _math.round(value * 100) + ');';
+ }
+ }
+
+ function preventDefault(e, skip) {
+ e.preventDefault ? e.preventDefault() : e.returnValue = false;
+ if (!skip) window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
+ return false;
+ }
+
+ function changeClass(elm, cln, newCln) {
+ return !elm ? false : elm.className = (newCln !== undefined ?
+ elm.className.replace(new RegExp('\\s+?' + cln, 'g'), newCln ? ' ' + newCln : '') :
+ elm.className + ' ' + cln);
+ }
+
+ function getOrigin(elm) {
+ var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {top: 0, left: 0},
+ doc = elm && elm.ownerDocument,
+ body = doc.body,
+ win = doc.defaultView || doc.parentWindow || window,
+ docElem = doc.documentElement || body.parentNode,
+ clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
+ clientLeft = docElem.clientLeft || body.clientLeft || 0;
+
+ return {
+ left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
+ top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
+ };
+ }
+
+ function getPageXY(e) {
+ var doc = window.document;
+
+ return {
+ X: e.pageX || e.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft,
+ Y: e.pageY || e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop
+ };
+ }
+
+ function addEvent(obj, type, func) {
+ addEvent.cache = addEvent.cache || {
+ _get: function(obj, type, func, checkOnly) {
+ var cache = addEvent.cache[type] || [];
+
+ for (var n = cache.length; n--; ) {
+ if (obj === cache[n].obj && '' + func === '' + cache[n].func) {
+ func = cache[n].func;
+ if (!checkOnly) {
+ cache[n] = cache[n].obj = cache[n].func = null;
+ cache.splice(n, 1);
+ }
+ return func;
+ }
+ }
+ },
+ _set: function(obj, type, func) {
+ var cache = addEvent.cache[type] = addEvent.cache[type] || [];
+
+ if (addEvent.cache._get(obj, type, func, true)) {
+ return true;
+ } else {
+ cache.push({
+ func: func,
+ obj: obj
+ });
+ }
+ }
+ };
+
+ if (!func.name && addEvent.cache._set(obj, type, func) || typeof func !== 'function') {
+ return;
+ }
+
+ if (obj.addEventListener) obj.addEventListener(type, func, false);
+ else obj.attachEvent('on' + type, func);
+ }
+
+ function removeEvent(obj, type, func) {
+ if (typeof func !== 'function') return;
+ if (!func.name) {
+ func = addEvent.cache._get(obj, type, func) || func;
+ }
+
+ if (obj.removeEventListener) obj.removeEventListener(type, func, false);
+ else obj.detachEvent('on' + type, func);
+ }
+
+ function caret(target, pos) { // only for contenteditable
+ var out = {};
+
+ if (pos === undefined) { // get
+ if (window.getSelection) { // HTML5
+ target.focus();
+ var range1 = window.getSelection().getRangeAt(0),
+ range2 = range1.cloneRange();
+ range2.selectNodeContents(target);
+ range2.setEnd(range1.endContainer, range1.endOffset);
+ out = {
+ end: range2.toString().length,
+ range: range1.toString().length
+ };
+ } else { // IE < 9
+ target.focus();
+ var range1 = document.selection.createRange(),
+ range2 = document.body.createTextRange();
+ range2.moveToElementText(target);
+ range2.setEndPoint('EndToEnd', range1);
+ out = {
+ end: range2.text.length,
+ range: range1.text.length
+ };
+ }
+ out.start = out.end - out.range;
+ return out;
+ }
+ // set
+ if (pos == -1) pos = target['text']().length;
+
+ if (window.getSelection) { // HTML5
+ target.focus();
+ window.getSelection().collapse(target.firstChild, pos);
+ } else { // IE < 9
+ var range = document.body.createTextRange();
+ range.moveToElementText(target);
+ range.moveStart('character', pos);
+ range.collapse(true);
+ range.select();
+ }
+ return pos;
+ }
+
+ // ------------- requestAnimationFrame shim ------------- //
+ // ---------- quite optimized for minification ---------- //
+
+ for(var n = vendors.length; n-- && !window[requestAnimationFrame]; ) {
+ window[requestAnimationFrame] = window[vendors[n] + 'Request' + animationFrame];
+ window[cancelAnimationFrame] = window[vendors[n] + 'Cancel' + animationFrame] ||
+ window[vendors[n] + 'CancelRequest' + animationFrame];
+ }
+
+ window[requestAnimationFrame] = window[requestAnimationFrame] || function(callback) {
+ // this is good enough... and better than setTimeout
+ return window.setTimeout(callback, 1000 / _options.fps);
+ // return _renderTimer ? _renderTimer : window.setInterval(callback, 1000 / _options.fps);
+ };
+
+ window[cancelAnimationFrame] = window[cancelAnimationFrame] || function(id) {
+ // console.log('OFF-', id + '-' + _renderTimer)
+ window.clearTimeout(id);
+ return _renderTimer = null;
+ };
+
+})(window);
\ No newline at end of file
diff --git a/_server/colorPicker/colors.js b/_server/colorPicker/colors.js
new file mode 100644
index 00000000..e3d52f46
--- /dev/null
+++ b/_server/colorPicker/colors.js
@@ -0,0 +1,732 @@
+;(function(window, undefined){
+ "use strict"
+
+ var _valueRanges = {
+ rgb: {r: [0, 255], g: [0, 255], b: [0, 255]},
+ hsv: {h: [0, 360], s: [0, 100], v: [0, 100]},
+ hsl: {h: [0, 360], s: [0, 100], l: [0, 100]},
+ cmy: {c: [0, 100], m: [0, 100], y: [0, 100]},
+ cmyk: {c: [0, 100], m: [0, 100], y: [0, 100], k: [0, 100]},
+ Lab: {L: [0, 100], a: [-128, 127], b: [-128, 127]},
+ XYZ: {X: [0, 100], Y: [0, 100], Z: [0, 100]},
+ alpha: {alpha: [0, 1]},
+ HEX: {HEX: [0, 16777215]} // maybe we don't need this
+ },
+
+ _instance = {},
+ _colors = {},
+
+ // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html for more
+ XYZMatrix = { // Observer = 2° (CIE 1931), Illuminant = D65
+ X: [ 0.4124564, 0.3575761, 0.1804375],
+ Y: [ 0.2126729, 0.7151522, 0.0721750],
+ Z: [ 0.0193339, 0.1191920, 0.9503041],
+ R: [ 3.2404542, -1.5371385, -0.4985314],
+ G: [-0.9692660, 1.8760108, 0.0415560],
+ B: [ 0.0556434, -0.2040259, 1.0572252]
+ },
+ grey = {r: 0.298954, g: 0.586434, b: 0.114612}, // CIE-XYZ 1931
+ luminance = {r: 0.2126, g: 0.7152, b: 0.0722}, // W3C 2.0
+
+ _math = window.Math,
+ _parseint = window.parseInt,
+
+ Colors = window.Colors = function(options) {
+ this.colors = {RND: {}};
+ this.options = {
+ color: 'rgba(204, 82, 37, 0.8)', // init value(s)...
+ XYZMatrix: XYZMatrix,
+ // XYZReference: {},
+ grey: grey,
+ luminance: luminance,
+ valueRanges: _valueRanges
+ // customBG: '#808080'
+ // convertCallback: undefined,
+ // allMixDetails: false
+ };
+ initInstance(this, options || {});
+ },
+ initInstance = function(THIS, options) {
+ var matrix,
+ importColor,
+ _options = THIS.options,
+ customBG;
+
+ focusInstance(THIS);
+ for (var option in options) {
+ if (options[option] !== undefined) _options[option] = options[option];
+ }
+ matrix = _options.XYZMatrix;
+ if (!options.XYZReference) _options.XYZReference = {
+ X: matrix.X[0] + matrix.X[1] + matrix.X[2],
+ Y: matrix.Y[0] + matrix.Y[1] + matrix.Y[2],
+ Z: matrix.Z[0] + matrix.Z[1] + matrix.Z[2]
+ };
+ customBG = _options.customBG;
+ _options.customBG = (typeof customBG === 'string') ? ColorConverter.txt2color(customBG).rgb : customBG;
+ _colors = setColor(THIS.colors, _options.color, undefined, true); // THIS.colors = _colors =
+ },
+ focusInstance = function(THIS) {
+ if (_instance !== THIS) {
+ _instance = THIS;
+ _colors = THIS.colors;
+ }
+ };
+
+ Colors.prototype.setColor = function(newCol, type, alpha) {
+ focusInstance(this);
+ if (newCol) {
+ return setColor(this.colors, newCol, type, undefined, alpha);
+ } else {
+ if (alpha !== undefined) {
+ this.colors.alpha = limitValue(alpha, 0, 1);
+ }
+ return convertColors(type);
+ }
+ };
+
+ Colors.prototype.getColor = function(type) {
+ var result = this.colors, n = 0;
+
+ if (type) {
+ type = type.split('.');
+ while (result[type[n]]) {
+ result = result[type[n++]];
+ }
+ if (type.length !== n) {
+ result = undefined;
+ }
+ }
+ return result;
+ };
+
+ Colors.prototype.setCustomBackground = function(col) { // wild gues,... check again...
+ focusInstance(this); // needed???
+ this.options.customBG = (typeof col === 'string') ? ColorConverter.txt2color(col).rgb : col;
+ // return setColor(this.colors, this.options.customBG, 'rgb', true); // !!!!RGB
+ return setColor(this.colors, undefined, 'rgb'); // just recalculate existing
+ };
+
+ Colors.prototype.saveAsBackground = function() { // alpha
+ focusInstance(this); // needed???
+ // return setColor(this.colors, this.colors.RND.rgb, 'rgb', true);
+ return setColor(this.colors, undefined, 'rgb', true);
+ };
+
+ Colors.prototype.convertColor = function(color, type) {
+ var convert = ColorConverter,
+ ranges = _valueRanges,
+ types = type.split('2'),
+ fromType = types[0],
+ toType = types[1],
+ test = /(?:RG|HS|CM|LA)/,
+ normalizeFrom = test.test(fromType),
+ normalizeTo = test.test(toType),
+ exceptions = {LAB: 'Lab'},
+ normalize = function(color, type, reverse) {
+ var result = {},
+ Lab = type === 'Lab' ? 1 : 0;
+
+ for (var n in color) { // faster (but bigger) way: if/else outside 2 for loops
+ result[n] = reverse ?
+ _math.round(color[n] * (Lab || ranges[type][n][1])) :
+ color[n] / (Lab || ranges[type][n][1]);
+ }
+
+ return result;
+ };
+
+ fromType = ranges[fromType] ? fromType : exceptions[fromType] || fromType.toLowerCase();
+ toType = ranges[toType] ? toType : exceptions[toType] || toType.toLowerCase();
+
+ if (normalizeFrom && type !== 'RGB2HEX') { // from ABC to abc
+ color = normalize(color, fromType);
+ }
+ color = fromType === toType ? color : ( // same type; returns same/normalized version
+ convert[fromType + '2' + toType] ? convert[fromType + '2' + toType](color, true) : // existing converter
+ toType === 'HEX' ? convert.RGB2HEX(type === 'RGB2HEX' ? color : normalize(fromType === 'rgb' ? color :
+ convert[fromType + '2rgb'](color, true), 'rgb', true)) :
+ convert['rgb2' + toType](convert[fromType + '2rgb'](color, true), true) // not in ColorConverter
+ );
+ if (normalizeTo) { // from abc to ABC
+ color = normalize(color, toType, true);
+ }
+
+ return color;
+ };
+
+ Colors.prototype.toString = function(colorMode, forceAlpha) {
+ return ColorConverter.color2text((colorMode || 'rgb').toLowerCase(), this.colors, forceAlpha);
+ };
+
+
+ // ------------------------------------------------------ //
+ // ---------- Color calculation related stuff ---------- //
+ // -------------------------------------------------------//
+
+ function setColor(colors, color, type, save, alpha) { // color only full range
+ if (typeof color === 'string') {
+ var color = ColorConverter.txt2color(color); // new object
+ type = color.type;
+ _colors[type] = color[type];
+ alpha = alpha !== undefined ? alpha : color.alpha;
+ } else if (color) {
+ for (var n in color) {
+ colors[type][n] = type === 'Lab' ?
+ limitValue(color[n], _valueRanges[type][n][0], _valueRanges[type][n][1]) :
+ limitValue(color[n] / _valueRanges[type][n][1], 0 , 1);
+ }
+ }
+ if (alpha !== undefined) {
+ colors.alpha = limitValue(+alpha, 0, 1);
+ }
+ return convertColors(type, save ? colors : undefined);
+ }
+
+ function saveAsBackground(RGB, rgb, alpha) {
+ var grey = _instance.options.grey,
+ color = {};
+
+ color.RGB = {r: RGB.r, g: RGB.g, b: RGB.b};
+ color.rgb = {r: rgb.r, g: rgb.g, b: rgb.b};
+ color.alpha = alpha;
+ // color.RGBLuminance = getLuminance(RGB);
+ color.equivalentGrey = _math.round(grey.r * RGB.r + grey.g * RGB.g + grey.b * RGB.b);
+
+ color.rgbaMixBlack = mixColors(rgb, {r: 0, g: 0, b: 0}, alpha, 1);
+ color.rgbaMixWhite = mixColors(rgb, {r: 1, g: 1, b: 1}, alpha, 1);
+ color.rgbaMixBlack.luminance = getLuminance(color.rgbaMixBlack, true);
+ color.rgbaMixWhite.luminance = getLuminance(color.rgbaMixWhite, true);
+
+ if (_instance.options.customBG) {
+ color.rgbaMixCustom = mixColors(rgb, _instance.options.customBG, alpha, 1);
+ color.rgbaMixCustom.luminance = getLuminance(color.rgbaMixCustom, true);
+ _instance.options.customBG.luminance = getLuminance(_instance.options.customBG, true);
+ }
+
+ return color;
+ }
+
+ function convertColors(type, colorObj) {
+ // console.time('convertColors');
+ var _Math = _math,
+ colors = colorObj || _colors,
+ convert = ColorConverter,
+ options = _instance.options,
+ ranges = _valueRanges,
+ RND = colors.RND,
+ // type = colorType, // || _mode.type,
+ modes, mode = '', from = '', // value = '',
+ exceptions = {hsl: 'hsv', cmyk: 'cmy', rgb: type},
+ RGB = RND.rgb, SAVE, SMART;
+
+ if (type !== 'alpha') {
+ for (var typ in ranges) {
+ if (!ranges[typ][typ]) { // no alpha|HEX
+ if (type !== typ && typ !== 'XYZ') {
+ from = exceptions[typ] || 'rgb';
+ colors[typ] = convert[from + '2' + typ](colors[from]);
+ }
+
+ if (!RND[typ]) RND[typ] = {};
+ modes = colors[typ];
+ for(mode in modes) {
+ RND[typ][mode] = _Math.round(modes[mode] * (typ === 'Lab' ? 1 : ranges[typ][mode][1]));
+ }
+ }
+ }
+ if (type !== 'Lab') {
+ delete colors._rgb;
+ }
+
+ RGB = RND.rgb;
+ colors.HEX = convert.RGB2HEX(RGB);
+ colors.equivalentGrey =
+ options.grey.r * colors.rgb.r +
+ options.grey.g * colors.rgb.g +
+ options.grey.b * colors.rgb.b;
+ colors.webSave = SAVE = getClosestWebColor(RGB, 51);
+ // colors.webSave.HEX = convert.RGB2HEX(colors.webSave);
+ colors.webSmart = SMART = getClosestWebColor(RGB, 17);
+ // colors.webSmart.HEX = convert.RGB2HEX(colors.webSmart);
+ colors.saveColor =
+ RGB.r === SAVE.r && RGB.g === SAVE.g && RGB.b === SAVE.b ? 'web save' :
+ RGB.r === SMART.r && RGB.g === SMART.g && RGB.b === SMART.b ? 'web smart' : '';
+ colors.hueRGB = convert.hue2RGB(colors.hsv.h);
+
+ if (colorObj) {
+ colors.background = saveAsBackground(RGB, colors.rgb, colors.alpha);
+ }
+ } // else RGB = RND.rgb;
+
+ var rgb = colors.rgb, // for better minification...
+ alpha = colors.alpha,
+ luminance = 'luminance',
+ background = colors.background,
+ rgbaMixBlack, rgbaMixWhite, rgbaMixCustom,
+ rgbaMixBG, rgbaMixBGMixBlack, rgbaMixBGMixWhite, rgbaMixBGMixCustom,
+ _mixColors = mixColors,
+ _getLuminance = getLuminance,
+ _getWCAG2Ratio = getWCAG2Ratio,
+ _getHueDelta = getHueDelta;
+
+ rgbaMixBlack = _mixColors(rgb, {r: 0, g: 0, b: 0}, alpha, 1);
+ rgbaMixBlack[luminance] = _getLuminance(rgbaMixBlack, true);
+ colors.rgbaMixBlack = rgbaMixBlack;
+
+ rgbaMixWhite = _mixColors(rgb, {r: 1, g: 1, b: 1}, alpha, 1);
+ rgbaMixWhite[luminance] = _getLuminance(rgbaMixWhite, true);
+ colors.rgbaMixWhite = rgbaMixWhite;
+
+ if (options.allMixDetails) {
+ rgbaMixBlack.WCAG2Ratio = _getWCAG2Ratio(rgbaMixBlack[luminance], 0);
+ rgbaMixWhite.WCAG2Ratio = _getWCAG2Ratio(rgbaMixWhite[luminance], 1);
+
+ if (options.customBG) {
+ rgbaMixCustom = _mixColors(rgb, options.customBG, alpha, 1);
+ rgbaMixCustom[luminance] = _getLuminance(rgbaMixCustom, true);
+ rgbaMixCustom.WCAG2Ratio = _getWCAG2Ratio(rgbaMixCustom[luminance], options.customBG[luminance]);
+ colors.rgbaMixCustom = rgbaMixCustom;
+ }
+
+ rgbaMixBG = _mixColors(rgb, background.rgb, alpha, background.alpha);
+ rgbaMixBG[luminance] = _getLuminance(rgbaMixBG, true); // ?? do we need this?
+ colors.rgbaMixBG = rgbaMixBG;
+
+ rgbaMixBGMixBlack = _mixColors(rgb, background.rgbaMixBlack, alpha, 1);
+ rgbaMixBGMixBlack[luminance] = _getLuminance(rgbaMixBGMixBlack, true);
+ rgbaMixBGMixBlack.WCAG2Ratio = _getWCAG2Ratio(rgbaMixBGMixBlack[luminance],
+ background.rgbaMixBlack[luminance]);
+ /* ------ */
+ rgbaMixBGMixBlack.luminanceDelta = _Math.abs(
+ rgbaMixBGMixBlack[luminance] - background.rgbaMixBlack[luminance]);
+ rgbaMixBGMixBlack.hueDelta = _getHueDelta(background.rgbaMixBlack, rgbaMixBGMixBlack, true);
+ /* ------ */
+ colors.rgbaMixBGMixBlack = rgbaMixBGMixBlack;
+
+ rgbaMixBGMixWhite = _mixColors(rgb, background.rgbaMixWhite, alpha, 1);
+ rgbaMixBGMixWhite[luminance] = _getLuminance(rgbaMixBGMixWhite, true);
+ rgbaMixBGMixWhite.WCAG2Ratio = _getWCAG2Ratio(rgbaMixBGMixWhite[luminance],
+ background.rgbaMixWhite[luminance]);
+ /* ------ */
+ rgbaMixBGMixWhite.luminanceDelta = _Math.abs(
+ rgbaMixBGMixWhite[luminance] - background.rgbaMixWhite[luminance]);
+ rgbaMixBGMixWhite.hueDelta = _getHueDelta(background.rgbaMixWhite, rgbaMixBGMixWhite, true);
+ /* ------ */
+ colors.rgbaMixBGMixWhite = rgbaMixBGMixWhite;
+ }
+
+ if (options.customBG) {
+ rgbaMixBGMixCustom = _mixColors(rgb, background.rgbaMixCustom, alpha, 1);
+ rgbaMixBGMixCustom[luminance] = _getLuminance(rgbaMixBGMixCustom, true);
+ rgbaMixBGMixCustom.WCAG2Ratio = _getWCAG2Ratio(rgbaMixBGMixCustom[luminance],
+ background.rgbaMixCustom[luminance]);
+ colors.rgbaMixBGMixCustom = rgbaMixBGMixCustom;
+ /* ------ */
+ rgbaMixBGMixCustom.luminanceDelta = _Math.abs(
+ rgbaMixBGMixCustom[luminance] - background.rgbaMixCustom[luminance]);
+ rgbaMixBGMixCustom.hueDelta = _getHueDelta(background.rgbaMixCustom, rgbaMixBGMixCustom, true);
+ /* ------ */
+ }
+
+ colors.RGBLuminance = _getLuminance(RGB);
+ colors.HUELuminance = _getLuminance(colors.hueRGB);
+
+ // renderVars.readyToRender = true;
+ if (options.convertCallback) {
+ options.convertCallback(colors, type); //, convert); //, _mode);
+ }
+
+ // console.timeEnd('convertColors')
+ // if (colorObj)
+ return colors;
+ }
+
+
+ // ------------------------------------------------------ //
+ // ------------------ color conversion ------------------ //
+ // -------------------------------------------------------//
+
+ var ColorConverter = {
+ txt2color: function(txt) {
+ var color = {},
+ parts = txt.replace(/(?:#|\)|%)/g, '').split('('),
+ values = (parts[1] || '').split(/,\s*/),
+ type = parts[1] ? parts[0].substr(0, 3) : 'rgb',
+ m = '';
+
+ color.type = type;
+ color[type] = {};
+ if (parts[1]) {
+ for (var n = 3; n--; ) {
+ m = type[n] || type.charAt(n); // IE7
+ color[type][m] = +values[n] / _valueRanges[type][m][1];
+ }
+ } else {
+ color.rgb = ColorConverter.HEX2rgb(parts[0]);
+ }
+ // color.color = color[type];
+ color.alpha = values[3] ? +values[3] : 1;
+
+ return color;
+ },
+
+ color2text: function(colorMode, colors, forceAlpha) {
+ var alpha = forceAlpha !== false && _math.round(colors.alpha * 100) / 100,
+ hasAlpha = typeof alpha === 'number' &&
+ forceAlpha !== false && (forceAlpha || alpha !== 1),
+ RGB = colors.RND.rgb,
+ HSL = colors.RND.hsl,
+ shouldBeHex = colorMode === 'hex' && hasAlpha,
+ isHex = colorMode === 'hex' && !shouldBeHex,
+ isRgb = colorMode === 'rgb' || shouldBeHex,
+ innerText = isRgb ? RGB.r + ', ' + RGB.g + ', ' + RGB.b :
+ !isHex ? HSL.h + ', ' + HSL.s + '%, ' + HSL.l + '%' :
+ '#' + colors.HEX;
+
+ return isHex ? innerText : (shouldBeHex ? 'rgb' : colorMode) +
+ (hasAlpha ? 'a' : '') + '(' + innerText + (hasAlpha ? ', ' + alpha : '') + ')';
+ },
+
+ RGB2HEX: function(RGB) {
+ return (
+ (RGB.r < 16 ? '0' : '') + RGB.r.toString(16) +
+ (RGB.g < 16 ? '0' : '') + RGB.g.toString(16) +
+ (RGB.b < 16 ? '0' : '') + RGB.b.toString(16)
+ ).toUpperCase();
+ },
+
+ HEX2rgb: function(HEX) {
+ HEX = HEX.split(''); // IE7
+ return {
+ r: +('0x' + HEX[0] + HEX[HEX[3] ? 1 : 0]) / 255,
+ g: +('0x' + HEX[HEX[3] ? 2 : 1] + (HEX[3] || HEX[1])) / 255,
+ b: +('0x' + (HEX[4] || HEX[2]) + (HEX[5] || HEX[2])) / 255
+ };
+ },
+
+ hue2RGB: function(hue) {
+ var _Math = _math,
+ h = hue * 6,
+ mod = ~~h % 6, // Math.floor(h) -> faster in most browsers
+ i = h === 6 ? 0 : (h - mod);
+
+ return {
+ r: _Math.round([1, 1 - i, 0, 0, i, 1][mod] * 255),
+ g: _Math.round([i, 1, 1, 1 - i, 0, 0][mod] * 255),
+ b: _Math.round([0, 0, i, 1, 1, 1 - i][mod] * 255)
+ };
+ },
+
+ // ------------------------ HSV ------------------------ //
+
+ rgb2hsv: function(rgb) { // faster
+ var _Math = _math,
+ r = rgb.r,
+ g = rgb.g,
+ b = rgb.b,
+ k = 0, chroma, min, s;
+
+ if (g < b) {
+ g = b + (b = g, 0);
+ k = -1;
+ }
+ min = b;
+ if (r < g) {
+ r = g + (g = r, 0);
+ k = -2 / 6 - k;
+ min = _Math.min(g, b); // g < b ? g : b; ???
+ }
+ chroma = r - min;
+ s = r ? (chroma / r) : 0;
+ return {
+ h: s < 1e-15 ? ((_colors && _colors.hsl && _colors.hsl.h) || 0) :
+ chroma ? _Math.abs(k + (g - b) / (6 * chroma)) : 0,
+ s: r ? (chroma / r) : ((_colors && _colors.hsv && _colors.hsv.s) || 0), // ??_colors.hsv.s || 0
+ v: r
+ };
+ },
+
+ hsv2rgb: function(hsv) {
+ var h = hsv.h * 6,
+ s = hsv.s,
+ v = hsv.v,
+ i = ~~h, // Math.floor(h) -> faster in most browsers
+ f = h - i,
+ p = v * (1 - s),
+ q = v * (1 - f * s),
+ t = v * (1 - (1 - f) * s),
+ mod = i % 6;
+
+ return {
+ r: [v, q, p, p, t, v][mod],
+ g: [t, v, v, q, p, p][mod],
+ b: [p, p, t, v, v, q][mod]
+ };
+ },
+
+ // ------------------------ HSL ------------------------ //
+
+ hsv2hsl: function(hsv) {
+ var l = (2 - hsv.s) * hsv.v,
+ s = hsv.s * hsv.v;
+
+ s = !hsv.s ? 0 : l < 1 ? (l ? s / l : 0) : s / (2 - l);
+
+ return {
+ h: hsv.h,
+ s: !hsv.v && !s ? ((_colors && _colors.hsl && _colors.hsl.s) || 0) : s, // ???
+ l: l / 2
+ };
+ },
+
+ rgb2hsl: function(rgb, dependent) { // not used in Color
+ var hsv = ColorConverter.rgb2hsv(rgb);
+
+ return ColorConverter.hsv2hsl(dependent ? hsv : (_colors.hsv = hsv));
+ },
+
+ hsl2rgb: function(hsl) {
+ var h = hsl.h * 6,
+ s = hsl.s,
+ l = hsl.l,
+ v = l < 0.5 ? l * (1 + s) : (l + s) - (s * l),
+ m = l + l - v,
+ sv = v ? ((v - m) / v) : 0,
+ sextant = ~~h, // Math.floor(h) -> faster in most browsers
+ fract = h - sextant,
+ vsf = v * sv * fract,
+ t = m + vsf,
+ q = v - vsf,
+ mod = sextant % 6;
+
+ return {
+ r: [v, q, m, m, t, v][mod],
+ g: [t, v, v, q, m, m][mod],
+ b: [m, m, t, v, v, q][mod]
+ };
+ },
+
+ // ------------------------ CMYK ------------------------ //
+ // Quote from Wikipedia:
+ // "Since RGB and CMYK spaces are both device-dependent spaces, there is no
+ // simple or general conversion formula that converts between them.
+ // Conversions are generally done through color management systems, using
+ // color profiles that describe the spaces being converted. Nevertheless, the
+ // conversions cannot be exact, since these spaces have very different gamuts."
+ // Translation: the following are just simple RGB to CMY(K) and visa versa conversion functions.
+
+ rgb2cmy: function(rgb) {
+ return {
+ c: 1 - rgb.r,
+ m: 1 - rgb.g,
+ y: 1 - rgb.b
+ };
+ },
+
+ cmy2cmyk: function(cmy) {
+ var _Math = _math,
+ k = _Math.min(_Math.min(cmy.c, cmy.m), cmy.y),
+ t = 1 - k || 1e-20;
+
+ return { // regular
+ c: (cmy.c - k) / t,
+ m: (cmy.m - k) / t,
+ y: (cmy.y - k) / t,
+ k: k
+ };
+ },
+
+ cmyk2cmy: function(cmyk) {
+ var k = cmyk.k;
+
+ return { // regular
+ c: cmyk.c * (1 - k) + k,
+ m: cmyk.m * (1 - k) + k,
+ y: cmyk.y * (1 - k) + k
+ };
+ },
+
+ cmy2rgb: function(cmy) {
+ return {
+ r: 1 - cmy.c,
+ g: 1 - cmy.m,
+ b: 1 - cmy.y
+ };
+ },
+
+ rgb2cmyk: function(rgb, dependent) {
+ var cmy = ColorConverter.rgb2cmy(rgb); // doppelt??
+
+ return ColorConverter.cmy2cmyk(dependent ? cmy : (_colors.cmy = cmy));
+ },
+
+ cmyk2rgb: function(cmyk, dependent) {
+ var cmy = ColorConverter.cmyk2cmy(cmyk); // doppelt??
+
+ return ColorConverter.cmy2rgb(dependent ? cmy : (_colors.cmy = cmy));
+ },
+
+ // ------------------------ LAB ------------------------ //
+
+ XYZ2rgb: function(XYZ, skip) {
+ var _Math = _math,
+ M = _instance.options.XYZMatrix,
+ X = XYZ.X,
+ Y = XYZ.Y,
+ Z = XYZ.Z,
+ r = X * M.R[0] + Y * M.R[1] + Z * M.R[2],
+ g = X * M.G[0] + Y * M.G[1] + Z * M.G[2],
+ b = X * M.B[0] + Y * M.B[1] + Z * M.B[2],
+ N = 1 / 2.4;
+
+ M = 0.0031308;
+
+ r = (r > M ? 1.055 * _Math.pow(r, N) - 0.055 : 12.92 * r);
+ g = (g > M ? 1.055 * _Math.pow(g, N) - 0.055 : 12.92 * g);
+ b = (b > M ? 1.055 * _Math.pow(b, N) - 0.055 : 12.92 * b);
+
+ if (!skip) { // out of gammut
+ _colors._rgb = {r: r, g: g, b: b};
+ }
+
+ return {
+ r: limitValue(r, 0, 1),
+ g: limitValue(g, 0, 1),
+ b: limitValue(b, 0, 1)
+ };
+ },
+
+ rgb2XYZ: function(rgb) {
+ var _Math = _math,
+ M = _instance.options.XYZMatrix,
+ r = rgb.r,
+ g = rgb.g,
+ b = rgb.b,
+ N = 0.04045;
+
+ r = (r > N ? _Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92);
+ g = (g > N ? _Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92);
+ b = (b > N ? _Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92);
+
+ return {
+ X: r * M.X[0] + g * M.X[1] + b * M.X[2],
+ Y: r * M.Y[0] + g * M.Y[1] + b * M.Y[2],
+ Z: r * M.Z[0] + g * M.Z[1] + b * M.Z[2]
+ };
+ },
+
+ XYZ2Lab: function(XYZ) {
+ var _Math = _math,
+ R = _instance.options.XYZReference,
+ X = XYZ.X / R.X,
+ Y = XYZ.Y / R.Y,
+ Z = XYZ.Z / R.Z,
+ N = 16 / 116, M = 1 / 3, K = 0.008856, L = 7.787037;
+
+ X = X > K ? _Math.pow(X, M) : (L * X) + N;
+ Y = Y > K ? _Math.pow(Y, M) : (L * Y) + N;
+ Z = Z > K ? _Math.pow(Z, M) : (L * Z) + N;
+
+ return {
+ L: (116 * Y) - 16,
+ a: 500 * (X - Y),
+ b: 200 * (Y - Z)
+ };
+ },
+
+ Lab2XYZ: function(Lab) {
+ var _Math = _math,
+ R = _instance.options.XYZReference,
+ Y = (Lab.L + 16) / 116,
+ X = Lab.a / 500 + Y,
+ Z = Y - Lab.b / 200,
+ X3 = _Math.pow(X, 3),
+ Y3 = _Math.pow(Y, 3),
+ Z3 = _Math.pow(Z, 3),
+ N = 16 / 116, K = 0.008856, L = 7.787037;
+
+ return {
+ X: (X3 > K ? X3 : (X - N) / L) * R.X,
+ Y: (Y3 > K ? Y3 : (Y - N) / L) * R.Y,
+ Z: (Z3 > K ? Z3 : (Z - N) / L) * R.Z
+ };
+ },
+
+ rgb2Lab: function(rgb, dependent) {
+ var XYZ = ColorConverter.rgb2XYZ(rgb);
+
+ return ColorConverter.XYZ2Lab(dependent ? XYZ : (_colors.XYZ = XYZ));
+ },
+
+ Lab2rgb: function(Lab, dependent) {
+ var XYZ = ColorConverter.Lab2XYZ(Lab);
+
+ return ColorConverter.XYZ2rgb(dependent ? XYZ : (_colors.XYZ = XYZ), dependent);
+ }
+ };
+
+ // ------------------------------------------------------ //
+ // ------------------ helper functions ------------------ //
+ // -------------------------------------------------------//
+
+ function getClosestWebColor(RGB, val) {
+ var out = {},
+ tmp = 0,
+ half = val / 2;
+
+ for (var n in RGB) {
+ tmp = RGB[n] % val; // 51 = 'web save', 17 = 'web smart'
+ out[n] = RGB[n] + (tmp > half ? val - tmp : -tmp);
+ }
+ return out;
+ }
+
+ function getHueDelta(rgb1, rgb2, nominal) {
+ var _Math = _math;
+
+ return (_Math.max(rgb1.r - rgb2.r, rgb2.r - rgb1.r) +
+ _Math.max(rgb1.g - rgb2.g, rgb2.g - rgb1.g) +
+ _Math.max(rgb1.b - rgb2.b, rgb2.b - rgb1.b)) * (nominal ? 255 : 1) / 765;
+ }
+
+ function getLuminance(rgb, normalized) {
+ var div = normalized ? 1 : 255,
+ RGB = [rgb.r / div, rgb.g / div, rgb.b / div],
+ luminance = _instance.options.luminance;
+
+ for (var i = RGB.length; i--; ) {
+ RGB[i] = RGB[i] <= 0.03928 ? RGB[i] / 12.92 : _math.pow(((RGB[i] + 0.055) / 1.055), 2.4);
+ }
+ return ((luminance.r * RGB[0]) + (luminance.g * RGB[1]) + (luminance.b * RGB[2]));
+ }
+
+ function mixColors(topColor, bottomColor, topAlpha, bottomAlpha) {
+ var newColor = {},
+ alphaTop = (topAlpha !== undefined ? topAlpha : 1),
+ alphaBottom = (bottomAlpha !== undefined ? bottomAlpha : 1),
+ alpha = alphaTop + alphaBottom * (1 - alphaTop); // 1 - (1 - alphaTop) * (1 - alphaBottom);
+
+ for(var n in topColor) {
+ newColor[n] = (topColor[n] * alphaTop + bottomColor[n] * alphaBottom * (1 - alphaTop)) / alpha;
+ }
+ newColor.a = alpha;
+ return newColor;
+ }
+
+ function getWCAG2Ratio(lum1, lum2) {
+ var ratio = 1;
+
+ if (lum1 >= lum2) {
+ ratio = (lum1 + 0.05) / (lum2 + 0.05);
+ } else {
+ ratio = (lum2 + 0.05) / (lum1 + 0.05);
+ }
+ return _math.round(ratio * 100) / 100;
+ }
+
+ function limitValue(value, min, max) {
+ // return Math.max(min, Math.min(max, value)); // faster??
+ return (value > max ? max : value < min ? min : value);
+ }
+})(window);
diff --git a/_server/colorPicker/jsColor.js b/_server/colorPicker/jsColor.js
new file mode 100644
index 00000000..a5eaa50b
--- /dev/null
+++ b/_server/colorPicker/jsColor.js
@@ -0,0 +1,258 @@
+(function (window) {
+ window.jsColorPicker = function(selectors, config) {
+ var renderCallback = function(colors, mode) {
+ var options = this,
+ input = options.input,
+ patch = options.patch,
+ RGB = colors.RND.rgb,
+ HSL = colors.RND.hsl,
+ AHEX = options.isIE8 ? (colors.alpha < 0.16 ? '0' : '') +
+ (Math.round(colors.alpha * 100)).toString(16).toUpperCase() + colors.HEX : '',
+ RGBInnerText = RGB.r + ', ' + RGB.g + ', ' + RGB.b,
+ RGBAText = RGBInnerText + ', ' + colors.alpha,
+ isAlpha = colors.alpha !== 1 && !options.isIE8,
+ colorMode = input.getAttribute('data-colorMode');
+
+ patch.style.cssText =
+ 'color:' + (colors.rgbaMixCustom.luminance > 0.22 ? '#222' : '#ddd') + ';' + // Black...???
+ 'background-color: rgba(' + RGBAText + ');' +
+ 'filter:' + (options.isIE8 ? 'progid:DXImageTransform.Microsoft.gradient(' + // IE<9
+ 'startColorstr=#' + AHEX + ',' + 'endColorstr=#' + AHEX + ')' : '');
+
+ input.value = RGBAText;
+
+ if (options.displayCallback) {
+ options.displayCallback(colors, mode, options);
+ }
+ },
+ extractValue = function(elm) {
+ return "rgba("+elm.value+")" || "rgba("+elm.getAttribute('value')+")" || elm.style.backgroundColor || 'rgba(0, 0, 0, 1)';
+ },
+ actionCallback = function(event, action) {
+ var options = this,
+ colorPicker = colorPickers.current;
+
+ if (action === 'toMemory') {
+ var memos = colorPicker.nodes.memos,
+ backgroundColor = '',
+ opacity = 0,
+ cookieTXT = [];
+
+ for (var n = 0, m = memos.length; n < m; n++) {
+ backgroundColor = memos[n].style.backgroundColor;
+ opacity = memos[n].style.opacity;
+ opacity = Math.round((opacity === '' ? 1 : opacity) * 100) / 100;
+ cookieTXT.push(backgroundColor.
+ replace(/, /g, ',').
+ replace('rgb(', 'rgba(').
+ replace(')', ',' + opacity + ')')
+ );
+ }
+ cookieTXT = '\'' + cookieTXT.join('\',\'') + '\'';
+ ColorPicker.docCookies('colorPickerMemos' + (options.noAlpha ? 'NoAlpha' : ''), cookieTXT);
+ } else if (action === 'resizeApp') {
+ ColorPicker.docCookies('colorPickerSize', colorPicker.color.options.currentSize);
+ } else if (action === 'modeChange') {
+ var mode = colorPicker.color.options.mode;
+
+ ColorPicker.docCookies('colorPickerMode', mode.type + '-' + mode.z);
+ }
+ },
+ createInstance = function(elm, config) {
+ var initConfig = {
+ klass: window.ColorPicker,
+ input: elm,
+ patch: elm,
+ isIE8: !!document.all && !document.addEventListener, // Opera???
+ // *** animationSpeed: 200,
+ // *** draggable: true,
+ margin: {left: -1, top: 2},
+ customBG: '#FFFFFF',
+ // displayCallback: displayCallback,
+ /* --- regular colorPicker options from this point --- */
+ color: extractValue(elm),
+ initStyle: 'display: none',
+ mode: ColorPicker.docCookies('colorPickerMode') || 'hsv-h',
+ // memoryColors: (function(colors, config) {
+ // return config.noAlpha ?
+ // colors.replace(/\,\d*\.*\d*\)/g, ',1)') : colors;
+ // })($.docCookies('colorPickerMemos'), config || {}),
+ memoryColors: ColorPicker.docCookies('colorPickerMemos' +
+ ((config || {}).noAlpha ? 'NoAlpha' : '')),
+ size: ColorPicker.docCookies('colorPickerSize') || 1,
+ renderCallback: renderCallback,
+ actionCallback: actionCallback
+ };
+
+ for (var n in config) {
+ initConfig[n] = config[n];
+ }
+ return new initConfig.klass(initConfig);
+ },
+ doEventListeners = function(elm, multiple, off) {
+ var onOff = off ? 'removeEventListener' : 'addEventListener',
+ inputListener = function(e) {
+ var index = multiple ? Array.prototype.indexOf.call(elms, this) : 0,
+ colorPicker = colorPickers[index] ||
+ (colorPickers[index] = createInstance(this, config)),
+ options = colorPicker.color.options;
+
+ options.color = extractValue(elm); // brings color to default on reset
+ //检查颜色合法性
+ if (options.color == options.color.match(/rgba\([0-9 ]+,[0-9 ]+,[0-9 ]+,[0-9. ]+\)/)[0]) {
+ var chec = options.color.match(/[0-9.]+/g);
+ if (chec.length != 4)
+ return;
+ for (var i = 0; i < 3; i++) {
+ if (chec[i] != chec[i].match(/\d+/)[0] || +chec[i] < 0 || +chec[i] > 255)
+ return;
+ }
+ if (chec[3] != chec[3].match(/\d+(\.\d+)?/)[0] || parseFloat(chec[3]) > 1 || parseFloat(chec[3] < 0))
+ return;
+ if (!multiple) {
+ colorPicker.setColor(extractValue(elm), undefined, undefined, true);
+ colorPicker.saveAsBackground();
+ }
+ colorPickers.current = colorPickers[index];
+ }
+ }
+ focusListener = function(e) {
+ elm = document.getElementById("colorPicker");
+ var input = elm,
+ position = window.ColorPicker.getOrigin(input),
+ index = multiple ? Array.prototype.indexOf.call(elms, elm) : 0,
+ colorPicker = colorPickers[index] ||
+ (colorPickers[index] = createInstance(elm, config)),
+ options = colorPicker.color.options,
+ colorPickerUI = colorPicker.nodes.colorPicker,
+ appendTo = (options.appendTo || document.body),
+ isStatic = /static/.test(window.getComputedStyle(appendTo).position),
+ atrect = isStatic ? {left: 0, top: 0} : appendTo.getBoundingClientRect(),
+ waitTimer = 0;
+
+ options.color = extractValue(elm); // brings color to default on reset
+ colorPickerUI.style.cssText =
+ 'position: absolute;' + (!colorPickers[index].cssIsReady ? 'display: none;' : '') +
+ 'left:' + (position.left + options.margin.left - atrect.left) + 'px;' +
+ 'top:' + (position.top + +input.offsetHeight + options.margin.top - atrect.top) + 'px;';
+
+ if (!multiple) {
+ options.input = elm;
+ options.patch = elm; // check again???
+ colorPicker.setColor(extractValue(elm), undefined, undefined, true);
+ colorPicker.saveAsBackground();
+ }
+ colorPickers.current = colorPickers[index];
+ appendTo.appendChild(colorPickerUI);
+ waitTimer = setInterval(function() { // compensating late style on onload in colorPicker
+ if (colorPickers.current.cssIsReady) {
+ waitTimer = clearInterval(waitTimer);
+ colorPickerUI.style.display = 'block';
+ }
+ }, 10);
+ },
+ mousDownListener = function(e) {
+ var colorPicker = colorPickers.current,
+ colorPickerUI = (colorPicker ? colorPicker.nodes.colorPicker : undefined),
+ animationSpeed = colorPicker ? colorPicker.color.options.animationSpeed : 0,
+ isColorPicker = colorPicker && (function(elm) {
+ while (elm) {
+ if ((elm.className || '').indexOf('cpPanel') !== -1) return elm;
+ elm = elm.parentNode;
+ }
+ return false;
+ })(e.target),
+ inputIndex = Array.prototype.indexOf.call(elms, e.target);
+
+ if (isColorPicker && Array.prototype.indexOf.call(colorPickers, isColorPicker)) {
+ if (e.target === colorPicker.nodes.exit) {
+ colorPickerUI.parentNode.style.display = 'none';
+ document.activeElement.blur();
+ } else {
+ // ...
+ }
+ } else if (inputIndex !== -1) {
+ // ...
+ } else if (colorPickerUI) {
+ colorPickerUI.parentNode.style.display = 'none';
+ }
+ };
+ button = document.getElementById("colorSwitch");
+ button[onOff]('click', focusListener);
+ elm[onOff]('input', inputListener);
+
+ if (!colorPickers.evt || off) {
+ colorPickers.evt = true; // prevent new eventListener for window
+
+ window[onOff]('mousedown', mousDownListener);
+ }
+ },
+ // this is a way to prevent data binding on HTMLElements
+ colorPickers = window.jsColorPicker.colorPickers || [],
+ elms = document.querySelectorAll(selectors),
+ testColors = new window.Colors({customBG: config.customBG, allMixDetails: true});
+
+ window.jsColorPicker.colorPickers = colorPickers;
+
+ for (var n = 0, m = elms.length; n < m; n++) {
+ var elm = elms[n];
+
+ if (config === 'destroy') {
+ doEventListeners(elm, (config && config.multipleInstances), true);
+ if (colorPickers[n]) {
+ colorPickers[n].destroyAll();
+ }
+ } else {
+ var color = extractValue(elm);
+ var value = color.split('(');
+
+ testColors.setColor(color);
+ if (config && config.init) {
+ config.init(elm, testColors.colors);
+ }
+ elm.setAttribute('data-colorMode', value[1] ? value[0].substr(0, 3) : 'HEX');
+ doEventListeners(elm, (config && config.multipleInstances), false);
+ if (config && config.readOnly) {
+ elm.readOnly = true;
+ }
+ }
+ };
+
+ return window.jsColorPicker.colorPickers;
+ };
+
+ window.ColorPicker.docCookies = function(key, val, options) {
+ var encode = encodeURIComponent, decode = decodeURIComponent,
+ cookies, n, tmp, cache = {},
+ days;
+
+ if (val === undefined) { // all about reading cookies
+ cookies = document.cookie.split(/;\s*/) || [];
+ for (n = cookies.length; n--; ) {
+ tmp = cookies[n].split('=');
+ if (tmp[0]) cache[decode(tmp.shift())] = decode(tmp.join('=')); // there might be '='s in the value...
+ }
+
+ if (!key) return cache; // return Json for easy access to all cookies
+ else return cache[key]; // easy access to cookies from here
+ } else { // write/delete cookie
+ options = options || {};
+
+ if (val === '' || options.expires < 0) { // prepare deleteing the cookie
+ options.expires = -1;
+ // options.path = options.domain = options.secure = undefined; // to make shure the cookie gets deleted...
+ }
+
+ if (options.expires !== undefined) { // prepare date if any
+ days = new Date();
+ days.setDate(days.getDate() + options.expires);
+ }
+
+ document.cookie = encode(key) + '=' + encode(val) +
+ (days ? '; expires=' + days.toUTCString() : '') +
+ (options.path ? '; path=' + options.path : '') +
+ (options.domain ? '; domain=' + options.domain : '') +
+ (options.secure ? '; secure' : '');
+ }
+ };
+})(this);
\ No newline at end of file
diff --git a/_server/css/editor.css b/_server/css/editor.css
index ebd4b009..17649905 100644
--- a/_server/css/editor.css
+++ b/_server/css/editor.css
@@ -18,6 +18,29 @@ body {
margin: 0 auto;
}
+.cp-app {
+ z-index: 250;
+}
+
+#colorPanel {
+ position: absolute;
+ left: 110px;
+ top: 36px;
+ width: 168px;
+ height: 205px;
+ z-index: 240;
+ padding: 4px 6px;
+ background-color: #F5F5F5;
+ box-sizing: border-box;
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
+}
+
+#colorPicker {
+ margin: 2px 0;
+ border-radius: 3px;
+ width: 104px;
+}
+
#left, #mid, #right {
border-radius: 2px;
box-sizing: border-box;
diff --git a/editor.html b/editor.html
index bd022f4f..b82418e1 100644
--- a/editor.html
+++ b/editor.html
@@ -181,6 +181,11 @@
@@ -494,6 +499,38 @@ if (location.protocol.indexOf("http")!=0) {
+
+
+
+
+
+