diff --git a/.eslintignore b/.eslintignore
index a710e413..f1fc323f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
vendor/
-vendor-overwrites/
+vendor-overwrites/*
+!vendor-overwrites/colorpicker
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index fb0236c7..d7f0fa2a 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -127,6 +127,10 @@
"message": "Autocomplete on typing",
"description": "Label for the checkbox in the style editor."
},
+ "cm_colorpicker": {
+ "message": "Colorpickers for CSS colors",
+ "description": "Label for the checkbox controlling colorpicker option for the style editor."
+ },
"cm_indentWithTabs": {
"message": "Use tabs with smart indentation",
"description": "Label for the checkbox controlling tabs with smart indentation option for the style editor."
@@ -171,6 +175,14 @@
"message": "Theme",
"description": "Label for the style editor's CSS theme."
},
+ "colorpickerSwitchFormatTooltip": {
+ "message": "Switch formats: HEX -> RGB -> HSL",
+ "description": "Tooltip for the switch button in the color picker popup in the style editor."
+ },
+ "colorpickerTooltip": {
+ "message": "Open color picker",
+ "description": "Tooltip for the colored squares shown before CSS colors in the style editor."
+ },
"dysfunctional": {
"message": "Stylus cannot function in private windows because Firefox disallows direct connection to the internal background page context of the extension.",
"description": "Displayed in Firefox when its settings make Stylus dysfunctional"
diff --git a/edit.html b/edit.html
index 6e20b003..34e99fd6 100644
--- a/edit.html
+++ b/edit.html
@@ -190,6 +190,10 @@
+
+
+
+
diff --git a/edit/edit.js b/edit/edit.js
index 14c88382..0775ede5 100644
--- a/edit/edit.js
+++ b/edit/edit.js
@@ -7,6 +7,12 @@
/* global closeCurrentTab regExpTester messageBox */
'use strict';
+onDOMready()
+ .then(() => Promise.all([
+ onColorpickerReady(),
+ ]))
+ .then(init);
+
let styleId = null;
// only the actually dirty items here
let dirty = {};
@@ -362,6 +368,8 @@ function acmeEventListener(event) {
}
option = 'highlightSelectionMatches';
break;
+ case 'colorpicker':
+ return;
}
CodeMirror.setOption(option, value);
}
@@ -1298,8 +1306,6 @@ function beautify(event) {
}
}
-onDOMready().then(init);
-
function init() {
initCodeMirror();
getStyle().then(style => {
@@ -2065,3 +2071,37 @@ function setGlobalProgress(done, total) {
progressElement.remove();
}
}
+
+function onColorpickerReady() {
+ const scripts = [
+ '/vendor-overwrites/colorpicker/colorpicker.css',
+ '/vendor-overwrites/colorpicker/colorpicker.js',
+ '/vendor-overwrites/colorpicker/colorview.js',
+ ];
+ prefs.subscribe(['editor.colorpicker'], colorpickerOnDemand);
+ return prefs.get('editor.colorpicker') && colorpickerOnDemand(null, true);
+
+ function colorpickerOnDemand(id, enabled) {
+ return loadScript(enabled && scripts)
+ .then(() => setColorpickerOption(id, enabled));
+ }
+
+ function setColorpickerOption(id, enabled) {
+ CodeMirror.defaults.colorpicker = enabled && {
+ forceUpdate: editors.length > 0,
+ tooltip: t('colorpickerTooltip'),
+ popupOptions: {
+ tooltipForSwitcher: t('colorpickerSwitchFormatTooltip'),
+ hexUppercase: prefs.get('editor.colorpicker.hexUppercase'),
+ hideDelay: 5000,
+ embedderCallback: state => {
+ if (state && state.hexUppercase !== prefs.get('editor.colorpicker.hexUppercase')) {
+ prefs.set('editor.colorpicker.hexUppercase', state.hexUppercase);
+ }
+ },
+ },
+ };
+ // on page load runs before CodeMirror.setOption is defined
+ editors.forEach(cm => cm.setOption('colorpicker', CodeMirror.defaults.colorpicker));
+ }
+}
diff --git a/js/prefs.js b/js/prefs.js
index 20903389..1c93a06c 100644
--- a/js/prefs.js
+++ b/js/prefs.js
@@ -56,6 +56,11 @@ var prefs = new function Prefs() {
'editor.appliesToLineWidget': true, // show applies-to line widget on the editor
+ // show CSS colors as clickable colored rectangles
+ 'editor.colorpicker': true,
+ // #DEAD or #beef
+ 'editor.colorpicker.hexUppercase': false,
+
'iconset': 0, // 0 = dark-themed icon
// 1 = light-themed icon
diff --git a/vendor-overwrites/colorpicker/colorpicker.css b/vendor-overwrites/colorpicker/colorpicker.css
index f80b45c2..532a6a07 100644
--- a/vendor-overwrites/colorpicker/colorpicker.css
+++ b/vendor-overwrites/colorpicker/colorpicker.css
@@ -1,57 +1,151 @@
-
/* codemirror colorview */
-.codemirror-colorview {
- border : 1px solid #8e8e8e;
- position: relative;
- display : inline-block;
- box-sizing : border-box;
- margin : 0px 2px;
- width : 10px;
- height : 10px;
- cursor: pointer;
- background-image : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC");
- background-repeat: repeat;
-}
-
-.codemirror-colorview .codemirror-colorview-background {
- content: "";
- position: absolute;
- left:0px;
- right:0px;
- bottom:0px;
- top:0px;
-}
-
-.codemirror-colorview:hover {
- border-color: #494949;
-}
-
-
-/* codemirror-colorpicker */
-
-.codemirror-colorpicker {
+.cm-colorview {
position: relative;
- width: 226px;
- z-index: 1000;
+ white-space: nowrap;
}
-.codemirror-colorpicker > .color {
+
+.cm-colorview::before {
+ content: "";
+ position: relative;
+ display: inline-block;
+ box-sizing: content-box;
+ margin: 0 3px;
+ width: 8px;
+ height: 8px;
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC");
+ background-repeat: repeat;
+}
+
+.cm-colorview + .cm-colorview.cm-overlay::before,
+.cm-colorview.cm-overlay + .cm-colorview::before {
+ content: none;
+}
+
+.codemirror-colorview-background {
+ position: absolute;
+ left: 2px;
+ top: 2px;
+ width: 10px;
+ height: 10px;
+ box-sizing: border-box;
+ border: 1px solid #8e8e8e;
+ content: "";
+ cursor: pointer;
+}
+
+.codemirror-colorview-background:hover {
+ border-color: #494949;
+}
+
+/* colorpicker */
+
+.colorpicker-theme-light {
+ --main-background-color: #fff;
+ --main-border-color: #ccc;
+
+ --label-color: #666;
+ --label-color-hover: #000;
+
+ --input-background-color: #fff;
+ --input-background-color-hover: #ddd;
+ --input-background-color-focus: #fff;
+
+ --input-color: #444;
+ --input-color-focus: #000;
+
+ --input-border-color: #bbb;
+ --input-border-color-focus: #888;
+ --input-border-color-hover: #444;
+
+ --invalid-border-color: hsl(0, 100%, 50%);
+ --invalid-background-color: hsla(0, 100%, 50%, 0.15);
+ --invalid-color: hsl(0, 100%, 40%);
+}
+
+.colorpicker-theme-dark {
+ --main-background-color: #242424;
+ --main-border-color: #888;
+
+ --label-color: #aaa;
+ --label-color-hover: #eee;
+
+ --input-background-color: #222;
+ --input-background-color-hover: #222;
+ --input-background-color-focus: #383838;
+
+ --input-color: #ddd;
+ --input-color-focus: #fff;
+
+ --input-border-color: #505050;
+ --input-border-color-focus: #777;
+ --input-border-color-hover: #888;
+
+ --invalid-border-color: hsl(0, 100%, 27%);
+ --invalid-background-color: hsla(0, 100%, 50%, 0.3);
+ --invalid-color: hsl(0, 100%, 75%);
+}
+
+.colorpicker-popup {
+ --switcher-width: 30px;
+ position: relative;
+ width: 350px;
+ z-index: 1000;
+ transition: opacity .5s;
+ color: var(--label-color);
+ border: 1px solid var(--main-border-color);
+ background-color: var(--main-background-color);
+ box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.12);
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+.colorpicker-popup[data-fading="1"] {
+ opacity: .75;
+}
+
+.colorpicker-popup[data-fading="2"] {
+ opacity: 0;
+}
+
+.colorpicker-saturation-container {
position: relative;
height: 120px;
overflow: hidden;
cursor: pointer;
}
-.codemirror-colorpicker > .color > .saturation {
+
+.colorpicker-opacity-bar {
+ position: absolute;
+ display: block;
+ content: "";
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ background: linear-gradient(to right, rgba(232, 232, 232, 0), rgba(232, 232, 232, 1));
+}
+
+.colorpicker-saturation {
position: relative;
width: 100%;
height: 100%;
+ background-color: rgba(204, 154, 129, 0);
+ background-image: linear-gradient(to right, #FFF, rgba(204, 154, 129, 0));
+ background-repeat: repeat-x;
}
-.codemirror-colorpicker > .color > .saturation > .value {
+
+.colorpicker-value {
position: relative;
width: 100%;
height: 100%;
+ background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0));
}
-.codemirror-colorpicker > .color > .saturation > .value > .drag-pointer {
+
+.colorpicker-drag-pointer {
position: absolute;
width: 10px;
height: 10px;
@@ -60,21 +154,25 @@
border-radius: 50%;
left: -5px;
top: -5px;
+ border: 1px solid #fff;
+ box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05);
}
-.codemirror-colorpicker > .control {
+
+.colorpicker-sliders {
position: relative;
- padding: 18px 0px 14px 0px;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -o-user-select: none;
- user-select: none;
+ padding: 10px 0 6px 0;
+ border-top: 1px solid transparent;
}
-.codemirror-colorpicker > .control > .color,
-.codemirror-colorpicker > .control > .empty {
+
+.colorpicker-theme-dark .colorpicker-sliders {
+ border-color: var(--input-border-color);
+}
+
+.colorpicker-swatch,
+.colorpicker-empty {
position: absolute;
left: 11px;
- top: 24px;
+ top: 17px;
width: 30px;
height: 30px;
-webkit-border-radius: 50%;
@@ -84,33 +182,41 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.codemirror-colorpicker > .control > .hue {
+
+.colorpicker-empty {
+ background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat;
+}
+
+.colorpicker-hue {
position: relative;
padding: 6px 12px;
- margin: 0px 0px 0px 45px;
+ margin: 0 0 0 45px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
- cursor: pointer;
}
-.codemirror-colorpicker > .control > .hue > .hue-container {
+
+.colorpicker-hue-container {
position: relative;
width: 100%;
height: 10px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
+ cursor: pointer;
+ background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
}
-.codemirror-colorpicker > .control > .opacity {
+
+.colorpicker-opacity {
position: relative;
padding: 3px 12px;
- margin: 0px 0px 0px 45px;
+ margin: 0 0 0 45px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
- cursor: pointer;
}
-.codemirror-colorpicker > .control > .opacity > .opacity-container {
+
+.colorpicker-opacity-container {
position: relative;
width: 100%;
height: 10px;
@@ -118,10 +224,13 @@
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
+ cursor: pointer;
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC");
+ background-repeat: repeat;
}
-.codemirror-colorpicker > .control .drag-bar,
-.codemirror-colorpicker > .control .drag-bar2 {
+.colorpicker-hue-knob,
+.colorpicker-opacity-knob {
position: absolute;
cursor: pointer;
top: 50% !important;
@@ -132,179 +241,148 @@
-webkit-border-radius: 50px;
-moz-border-radius: 50px;
border-radius: 50px;
+ border: 1px solid rgba(0, 0, 0, 0.5);
+ box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
+ background-color: #fff;
}
-.codemirror-colorpicker > .information {
+
+.colorpicker-input-container {
position: relative;
-webkit-box-sizing: padding-box;
-moz-box-sizing: padding-box;
box-sizing: padding-box;
}
-.codemirror-colorpicker > .information.hex > .information-item.hex {
- display: flex;
-}
-
-.codemirror-colorpicker > .information.rgb > .information-item.rgb {
- display: flex;
-}
-
-.codemirror-colorpicker > .information.hsl > .information-item.hsl {
- display: flex;
-}
-
-.codemirror-colorpicker > .information > .information-item {
- display:none;
+.colorpicker-input-group {
+ display: none;
position: relative;
- padding: 0px 5px;
+ padding: 0 5px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
- margin-right:40px;
+ margin-right: calc(var(--switcher-width) - 10px);
}
-.codemirror-colorpicker > .information > .information-change {
- position:absolute;
- display:block;
- width:40px;
- top:0px;
- right:0px;
- bottom:0px;
+.colorpicker-input-group[data-active] {
+ display: flex;
}
-.codemirror-colorpicker > .information > .information-change > .format-change-button {
- width:100%;
- height:100%;
- background:transparent;
- border:0px;
- cursor:pointer;
- outline:none;
-}
-
-.codemirror-colorpicker > .information > .information-item > .input-field {
- display:block;
- flex:1;
+.colorpicker-input-field {
+ display: block;
+ position: relative;
+ flex: 1;
padding: 5px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.codemirror-colorpicker > .information > .information-item > .input-field > input {
- text-align: center;
- width:100%;
- padding:3px 5px;
- font-size:11px;
- color: #333;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- -webkit-user-select: text;
- -moz-user-select: text;
- -ms-user-select: text;
- -o-user-select: text;
- user-select: text;
- border: 1px solid #cbcbcb;
+.colorpicker-input-field[class$="-a"] {
+ flex-grow: 1.5;
}
-.codemirror-colorpicker > .information > .information-item > .input-field > .title {
- text-align:center;
- font-size:12px;
- color:#a9a9a9;
-}
-
-.codemirror-colorpicker > .information > input {
+.colorpicker-hsl-h::before {
+ content: "\b0"; /* degree */
position: absolute;
+ right: -2px;
+ top: 8px;
+}
+
+.colorpicker-hsl-s::before,
+.colorpicker-hsl-l::before {
+ content: "%";
+ position: absolute;
+ right: -1ex;
+ top: 8px;
font-size: 10px;
- height: 20px;
- bottom: 20px;
- padding: 0 0 0 2px;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
+}
+
+.colorpicker-input {
+ text-align: center;
+ width: 100%;
+ padding: 3px 5px;
+ font-size: 11px;
+ font-weight: bold;
box-sizing: border-box;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
-o-user-select: text;
user-select: text;
+ border: 1px solid var(--input-border-color);
+ background-color: var(--input-background-color);
+ color: var(--input-color);
}
-
-.codemirror-colorpicker {
- border: 1px solid #ececec;
- background-color: #fff;
- -webkit-box-shadow: 0 0px 10px 0px rgba(0, 0, 0, 0.12);
- -moz-box-shadow: 0 0px 10px 0px rgba(0, 0, 0, 0.12);
- box-shadow: 0 0px 10px 0px rgba(0, 0, 0, 0.12);
-}
-.codemirror-colorpicker > .color > .saturation {
- background-color: rgba(204, 154, 129, 0);
- background-image: -moz-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
- background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0)));
- background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
- background-image: -o-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
- background-image: linear-gradient(to right, #FFF, rgba(204, 154, 129, 0));
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#00cc9a81', GradientType=1);
-}
-.codemirror-colorpicker > .color > .saturation > .value {
- background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0)));
- background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
- background-image: -moz-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
- background-image: -o-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
- background-image: -ms-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
- background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0));
-}
-.codemirror-colorpicker > .color > .saturation > .value > .drag-pointer {
- border: 1px solid #fff;
- -webkit-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05);
- -moz-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05);
- box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05);
-}
-.codemirror-colorpicker > .control > .hue > .hue-container {
- background: -moz-linear-gradient(left, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
- background: -ms-linear-gradient(left, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
- background: -o-linear-gradient(left, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
- background: -webkit-gradient(linear, left top, right top, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000));
- background: -webkit-linear-gradient(left, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
- background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
-}
-.codemirror-colorpicker > .control > .opacity > .opacity-container > .color-bar {
- position:absolute;
- display:block;
- content:"";
- left:0px;
- right:0px;
- bottom:0px;
- top:0px;
- background: -moz-linear-gradient(left, rgba(232, 232, 232, 0), rgba(232, 232, 232, 1));
- background: -ms-linear-gradient(left, rgba(232, 232, 232, 0), rgba(232, 232, 232, 1));
- background: -o-linear-gradient(left, rgba(232, 232, 232, 0), rgba(232, 232, 232, 1));
- background: -webkit-gradient(linear, left top, right top, from(rgba(232, 232, 232, 0)), to(rgba(232, 232, 232, 1)));
- background: -webkit-linear-gradient(left, rgba(232, 232, 232, 0), rgba(232, 232, 232, 1));
- background: linear-gradient(to right, rgba(232, 232, 232, 0) , rgba(232, 232, 232, 1) );
-}
-.codemirror-colorpicker > .control > .opacity > .opacity-container {
- background-image : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC");
- background-repeat: repeat;
+.colorpicker-theme-dark .colorpicker-input::-webkit-inner-spin-button {
+ -webkit-filter: invert(1);
+ filter: invert(1);
}
-.codemirror-colorpicker > .control > .empty {
- background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat;
+.colorpicker-input:hover {
+ border-color: var(--input-border-color-hover);
}
-.codemirror-colorpicker > .control .drag-bar,
-.codemirror-colorpicker > .control .drag-bar2 {
- border: 1px solid rgba(0, 0, 0, 0.5);
- -webkit-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
- -moz-box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
- box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
- background-color: #FFFFFF;
+
+.colorpicker-input:focus {
+ color: var(--input-color-focus);
+ border-color: var(--input-border-color-focus);
+ background-color: var(--input-background-color-focus);
}
-.codemirror-colorpicker > .information {
- /*border-top: 1px solid #e8e8e8;*/
+
+.colorpicker-theme-dark input:focus {
+ outline: none !important;
}
-.codemirror-colorpicker > .information > .title {
- color: #a3a3a3;
+
+.colorpicker-input:invalid {
+ border-color: var(--invalid-border-color);
+ background-color: var(--invalid-background-color);
+ color: var(--invalid-color);
+}
+
+.colorpicker-title {
+ text-align: center;
+ font-size: 12px;
+ font-family: monospace;
+ display: flex;
+ justify-content: center;
+ color: var(--label-color);
+}
+
+.colorpicker-title-action {
+ cursor: pointer;
+}
+
+.colorpicker-title-action[data-active] {
+ font-weight: bold;
+ color: var(--input-color);
+ cursor: default;
+ pointer-events: none;
+}
+
+.colorpicker-format-change {
+ position: absolute;
+ display: block;
+ width: var(--switcher-width);
+ top: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+}
+
+.colorpicker-format-change-button {
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ border: 0;
+ cursor: pointer;
+ outline: none;
+ font-family: monospace !important;
+ font-size: var(--switcher-width) !important;
+ margin-top: -5px;
+ color: var(--label-color);
+ text-align: center;
+}
+
+.colorpicker-format-change-button:hover {
+ color: var(--label-color-hover);
}
-.codemirror-colorpicker > .information > .input {
- color: #333;
-}
\ No newline at end of file
diff --git a/vendor-overwrites/colorpicker/colorpicker.js b/vendor-overwrites/colorpicker/colorpicker.js
index 25fc8741..c430d5cc 100644
--- a/vendor-overwrites/colorpicker/colorpicker.js
+++ b/vendor-overwrites/colorpicker/colorpicker.js
@@ -1,1369 +1,869 @@
-(function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
- mod(require("codemirror"));
- else if (typeof define == "function" && define.amd) // AMD
- define(["codemirror" ], mod);
- else // Plain browser env
- mod(CodeMirror);
-})(function(CodeMirror) {
-
- CodeMirror.defineExtension("colorpicker", function () {
-
- var cm = this;
-
- var color = {
-
- trim : function (str) {
- return str.replace(/^\s+|\s+$/g, '');
- },
-
- /**
- * @method format
- *
- * convert color to format string
- *
- * // hex
- * color.format({ r : 255, g : 255, b : 255 }, 'hex') // #FFFFFF
- *
- * // rgb
- * color.format({ r : 255, g : 255, b : 255 }, 'rgb') // rgba(255, 255, 255, 0.5);
- *
- * // rgba
- * color.format({ r : 255, g : 255, b : 255, a : 0.5 }, 'rgb') // rgba(255, 255, 255, 0.5);
- *
- * @param {Object} obj obj has r, g, b and a attributes
- * @param {"hex"/"rgb"} type format string type
- * @returns {*}
- */
- format : function(obj, type) {
- if (type == 'hex') {
- var r = obj.r.toString(16);
- if (obj.r < 16) r = "0" + r;
-
- var g = obj.g.toString(16);
- if (obj.g < 16) g = "0" + g;
-
- var b = obj.b.toString(16);
- if (obj.b < 16) b = "0" + b;
-
- return "#" + [r, g, b].join("");
- } else if (type == 'rgb') {
- if (typeof obj.a == 'undefined') {
- return "rgb(" + [obj.r, obj.g, obj.b].join(",") + ")";
- } else {
- return "rgba(" + [obj.r, obj.g, obj.b, obj.a].join(",") + ")";
- }
- } else if (type == 'hsl') {
- if (typeof obj.a == 'undefined') {
- return "hsl(" + [obj.h, obj.s + '%', obj.l + '%'].join(",") + ")";
- } else {
- return "hsla(" + [obj.h, obj.s + '%', obj.l + '%', obj.a].join(",") + ")";
- }
- }
-
- return obj;
- },
-
- /**
- * @method rgb
- *
- * parse string to rgb color
- *
- * color.rgb("#FF0000") === { r : 255, g : 0, b : 0 }
- *
- * color.rgb("rgb(255, 0, 0)") == { r : 255, g : 0, b : }
- *
- * @param {String} str color string
- * @returns {Object} rgb object
- */
- parse : function (str) {
- if (typeof str == 'string') {
- if (str.indexOf("rgb(") > -1) {
- var arr = str.replace("rgb(", "").replace(")","").split(",");
-
- for(var i = 0, len = arr.length; i < len; i++) {
- arr[i] = parseInt(color.trim(arr[i]), 10);
- }
-
- return { type : 'rgb', r : arr[0], g : arr[1], b : arr[2], a : 1 };
- } else if (str.indexOf("rgba(") > -1) {
- var arr = str.replace("rgba(", "").replace(")", "").split(",");
-
- for (var i = 0, len = arr.length; i < len; i++) {
-
- if (len - 1 == i) {
- arr[i] = parseFloat(color.trim(arr[i]));
- } else {
- arr[i] = parseInt(color.trim(arr[i]), 10);
- }
- }
-
- return {type: 'rgb', r: arr[0], g: arr[1], b: arr[2], a: arr[3]};
- } else if (str.indexOf("hsl(") > -1) {
- var arr = str.replace("hsl(", "").replace(")","").split(",");
-
- for(var i = 0, len = arr.length; i < len; i++) {
- arr[i] = parseInt(color.trim(arr[i]), 10);
- }
-
- var obj = { type : 'hsl', h : arr[0], s : arr[1], l : arr[2], a : 1 };
-
- var temp = color.HSLtoRGB(obj.h, obj.s, obj.l);
-
- obj.r = temp.r;
- obj.g = temp.g;
- obj.b = temp.b;
-
- return obj;
- } else if (str.indexOf("hsla(") > -1) {
- var arr = str.replace("hsla(", "").replace(")", "").split(",");
-
- for (var i = 0, len = arr.length; i < len; i++) {
-
- if (len - 1 == i) {
- arr[i] = parseFloat(color.trim(arr[i]));
- } else {
- arr[i] = parseInt(color.trim(arr[i]), 10);
- }
- }
-
- var obj = {type: 'hsl', h: arr[0], s: arr[1], l: arr[2], a: arr[3]};
-
- var temp = color.HSLtoRGB(obj.h, obj.s, obj.l);
-
- obj.r = temp.r;
- obj.g = temp.g;
- obj.b = temp.b;
-
- return obj;
- } else if (str.indexOf("#") == 0) {
-
- str = str.replace("#", "");
-
- var arr = [];
- if (str.length == 3) {
- for(var i = 0, len = str.length; i < len; i++) {
- var char = str.substr(i, 1);
- arr.push(parseInt(char+char, 16));
- }
- } else {
- for(var i = 0, len = str.length; i < len; i+=2) {
- arr.push(parseInt(str.substr(i, 2), 16));
- }
- }
-
- return { type : 'hex', r : arr[0], g : arr[1], b : arr[2], a : 1 };
- }
- }
-
- return str;
-
- },
-
- /**
- * @method HSVtoRGB
- *
- * convert hsv to rgb
- *
- * color.HSVtoRGB(0,0,1) === #FFFFF === { r : 255, g : 0, b : 0 }
- *
- * @param {Number} H hue color number (min : 0, max : 360)
- * @param {Number} S Saturation number (min : 0, max : 1)
- * @param {Number} V Value number (min : 0, max : 1 )
- * @returns {Object}
- */
- HSVtoRGB : function (H, S, V) {
-
- if (H == 360) {
- H = 0;
- }
-
- var C = S * V;
- var X = C * (1 - Math.abs((H/60) % 2 -1) );
- var m = V - C;
-
- var temp = [];
-
- if (0 <= H && H < 60) { temp = [C, X, 0]; }
- else if (60 <= H && H < 120) { temp = [X, C, 0]; }
- else if (120 <= H && H < 180) { temp = [0, C, X]; }
- else if (180 <= H && H < 240) { temp = [0, X, C]; }
- else if (240 <= H && H < 300) { temp = [X, 0, C]; }
- else if (300 <= H && H < 360) { temp = [C, 0, X]; }
-
- return {
- r : Math.ceil((temp[0] + m) * 255),
- g : Math.ceil((temp[1] + m) * 255),
- b : Math.ceil((temp[2] + m) * 255)
- };
- },
-
- /**
- * @method RGBtoHSV
- *
- * convert rgb to hsv
- *
- * color.RGBtoHSV(0, 0, 255) === { h : 240, s : 1, v : 1 } === '#FFFF00'
- *
- * @param {Number} R red color value
- * @param {Number} G green color value
- * @param {Number} B blue color value
- * @return {Object} hsv color code
- */
- RGBtoHSV : function (R, G, B) {
-
- var R1 = R / 255;
- var G1 = G / 255;
- var B1 = B / 255;
-
- var MaxC = Math.max(R1, G1, B1);
- var MinC = Math.min(R1, G1, B1);
-
- var DeltaC = MaxC - MinC;
-
- var H = 0;
-
- if (DeltaC == 0) { H = 0; }
- else if (MaxC == R1) {
- H = 60 * (( (G1 - B1) / DeltaC) % 6);
- } else if (MaxC == G1) {
- H = 60 * (( (B1 - R1) / DeltaC) + 2);
- } else if (MaxC == B1) {
- H = 60 * (( (R1 - G1) / DeltaC) + 4);
- }
-
- if (H < 0) {
- H = 360 + H;
- }
-
- var S = 0;
-
- if (MaxC == 0) S = 0;
- else S = DeltaC / MaxC;
-
- var V = MaxC;
-
- return { h : H, s : S, v : V };
- },
-
- RGBtoHSL : function (r, g, b) {
- r /= 255, g /= 255, b /= 255;
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
- var h, s, l = (max + min) / 2;
-
- if(max == min){
- h = s = 0; // achromatic
- }else{
- var d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
- switch(max){
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h /= 6;
- }
-
- return { h : Math.round(h * 360) , s : Math.round(s * 100), l : Math.round(l * 100)};
- },
-
- HUEtoRGB : function (p, q, t) {
- if(t < 0) t += 1;
- if(t > 1) t -= 1;
- if(t < 1/6) return p + (q - p) * 6 * t;
- if(t < 1/2) return q;
- if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
- return p;
- },
-
- HSLtoRGB : function (h, s, l) {
- var r, g, b;
-
- h /= 360;
- s /= 100;
- l /= 100;
-
- if(s == 0){
- r = g = b = l; // achromatic
- }else{
- var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- var p = 2 * l - q;
- r = this.HUEtoRGB(p, q, h + 1/3);
- g = this.HUEtoRGB(p, q, h);
- b = this.HUEtoRGB(p, q, h - 1/3);
- }
-
- return { r : r * 255, g : g * 255, b : b * 255 };
- }
- };
-
- var hue_color = [
- { rgb : '#ff0000', start : .0 },
- { rgb : '#ffff00', start : .17 },
- { rgb : '#00ff00', start : .33 },
- { rgb : '#00ffff', start : .50 },
- { rgb : '#0000ff', start : .67 },
- { rgb : '#ff00ff', start : .83 },
- { rgb : '#ff0000', start : 1 }
- ];
-
- var $body, $root, $hue, $color, $value, $saturation, $drag_pointer, $drag_bar,
- $control, $controlPattern, $controlColor, $hueContainer, $opacity, $opacityContainer, $opacityColorBar, $formatChangeButton,
- $opacity_drag_bar, $information, $informationChange;
-
- var currentA, currentH, currentS, currentV;
- var $hexCode;
- var $rgb_r, $rgb_g, $rgb_b, $rgb_a;
- var $hsl_h, $hsl_s, $hsl_l, $hsl_a;
- var cssPrefix = getCssValuePrefix();
-
- var colorpickerCallback = function () {};
- var counter = 0;
- var cached = {};
- var isColorPickerShow = false;
- var isShortCut = false;
- var hideDelay = 2000;
-
- function dom(tag, className, attr) {
-
- if (typeof tag != 'string') {
- this.el = tag;
- } else {
-
- var el = document.createElement(tag);
-
- this.uniqId = counter++;
-
- el.className = className;
-
- attr = attr || {};
-
- for(var k in attr) {
- el.setAttribute(k, attr[k]);
- }
-
- this.el = el;
- }
- }
-
- dom.prototype.closest = function (cls) {
-
- var temp = this;
- var checkCls = false;
-
- while(!(checkCls = temp.hasClass(cls))) {
- if (temp.el.parentNode) {
- temp = new dom(temp.el.parentNode);
- } else {
- return null;
- }
- }
-
- if (checkCls) {
- return temp;
- }
-
- return null;
- }
-
- dom.prototype.removeClass = function (cls) {
- this.el.className = color.trim((" " + this.el.className + " ").replace(' ' + cls + ' ', ' '));
- }
-
- dom.prototype.hasClass = function (cls) {
- if (!this.el.className)
- {
- return false;
- } else {
- var newClass = ' ' + this.el.className + ' ';
- return newClass.indexOf(' ' + cls + ' ') > -1;
- }
- }
-
- dom.prototype.addClass = function (cls) {
- if (!this.hasClass(cls)) {
- this.el.className = this.el.className + " " + cls;
- }
-
- }
-
- dom.prototype.html = function (html) {
- this.el.innerHTML = html;
-
- return this;
- }
-
- dom.prototype.empty = function () {
- return this.html('');
- }
-
- dom.prototype.append = function (el) {
-
- if (typeof el == 'string') {
- this.el.appendChild(document.createTextNode(el));
- } else {
- this.el.appendChild(el.el || el);
- }
-
- return this;
- }
-
- dom.prototype.appendTo = function (target) {
- var t = target.el ? target.el : target;
-
- t.appendChild(this.el);
-
- return this;
- }
-
- dom.prototype.remove = function () {
- if (this.el.parentNode) {
- this.el.parentNode.removeChild(this.el);
- }
-
- return this;
- }
-
- dom.prototype.text = function () {
- return this.el.textContent;
- }
-
- dom.prototype.css = function (key, value) {
- if (arguments.length == 2) {
- this.el.style[key] = value;
- } else if (arguments.length == 1) {
-
- if (typeof key == 'string') {
- return getComputedStyle(this.el)[key];
- } else {
- var keys = key || {};
- for(var k in keys) {
- this.el.style[k] = keys[k];
- }
- }
-
- }
-
- return this;
- }
-
- dom.prototype.offset = function () {
- var rect = this.el.getBoundingClientRect();
-
- return {
- top: rect.top + document.body.scrollTop,
- left: rect.left + document.body.scrollLeft
- };
- }
-
- dom.prototype.position = function () {
- return {
- top: parseFloat(this.el.style.top),
- left: parseFloat(this.el.style.left)
- };
- }
-
- dom.prototype.width = function () {
- return this.el.offsetWidth;
- }
-
- dom.prototype.height = function () {
- return this.el.offsetHeight;
- }
-
- dom.prototype.dataKey = function (key) {
- return this.uniqId + '.' + key;
- }
-
- dom.prototype.data = function (key, value) {
- if (arguments.length == 2) {
- cached[this.dataKey(key)] = value;
- } else if (arguments.length == 1) {
- return cached[this.dataKey(key)];
- } else {
- var keys = Object.keys(cached);
-
- var uniqId = this.uniqId + ".";
- return keys.filter(function (key) {
- if (key.indexOf(uniqId) == 0) {
- return true;
- }
-
- return false;
- }).map(function (value) {
- return cached[value];
- })
- }
-
- return this;
- }
-
- dom.prototype.val = function (value) {
- if (arguments.length == 0) {
- return this.el.value;
- } else if (arguments.length == 1) {
- this.el.value = value;
- }
-
- return this;
- }
-
- dom.prototype.int = function () {
- return parseInt(this.val(), 10);
- }
-
- dom.prototype.show = function () {
- return this.css('display', 'block');
- }
-
- dom.prototype.hide = function () {
- return this.css('display', 'none');
- }
-
- function setRGBInput(r, g, b) {
- $rgb_r.val(r);
- $rgb_g.val(g);
- $rgb_b.val(b);
- $rgb_a.val(currentA);
- }
-
- function setHSLInput(h, s, l) {
- $hsl_h.val(h);
- $hsl_s.val(s + '%');
- $hsl_l.val(l + '%');
- $hsl_a.val(currentA);
- }
-
- function getHexFormat() {
- return color.format({
- r : $rgb_r.int(),
- g : $rgb_g.int(),
- b : $rgb_b.int()
- }, 'hex');
- }
-
- function convertRGB() {
- return color.HSVtoRGB(currentH, currentS, currentV);
- }
-
- function convertHEX() {
- return color.format(convertRGB(), 'hex');
- }
-
- function convertHSL() {
- var rgb = color.HSVtoRGB(currentH, currentS, currentV);
- return color.RGBtoHSL(rgb.r, rgb.g, rgb.b);
- }
-
- function getFormattedColor (format) {
- format = format || 'hex';
-
- if (format == 'rgb') {
- var rgb = convertRGB();
- rgb.a = currentA == 1 ? undefined : currentA;
- return color.format(rgb, 'rgb');
- } else if (format == 'hsl') {
- var hsl = convertHSL();
- hsl.a = currentA == 1 ? undefined : currentA;
- return color.format(hsl, 'hsl');
- } else {
- var rgb = convertRGB();
- return color.format(rgb, 'hex');
- }
- }
-
- function setControlColor (color) {
- $controlColor.css('background-color', color);
- }
-
- function setInputColor() {
-
- var format = $information.data('format') || 'hex';
-
- var rgb = null;
- if (format == 'hex') {
- $hexCode.val(convertHEX());
- } else if (format == 'rgb') {
- var rgb = convertRGB();
- setRGBInput(rgb.r, rgb.g, rgb.b);
- } else if (format == 'hsl') {
- var hsl = convertHSL();
- setHSLInput(hsl.h, hsl.s, hsl.l);
- }
-
- // set background
- setControlColor(getFormattedColor('rgb'));
-
- var rgb = convertRGB();
- var colorString = color.format(rgb, 'rgb');
- setOpacityColorBar(colorString);
-
- if (typeof colorpickerCallback == 'function') {
-
- if (!isNaN(currentA)) {
- colorpickerCallback(getFormattedColor(format));
- }
-
- }
- }
-
- function setMainColor(e) {
- e.preventDefault();
- var pos = $root.position(); // position for screen
- var w = $color.width();
- var h = $color.height();
-
- var x = e.clientX - pos.left;
- var y = e.clientY - pos.top;
-
- if (x < 0) x = 0;
- else if (x > w) x = w;
-
- if (y < 0) y = 0;
- else if (y > h) y = h;
-
- $drag_pointer.css({
- left: (x - 5) + 'px',
- top: (y - 5) + 'px'
- });
-
- $drag_pointer.data('pos', { x: x, y : y});
-
- caculateHSV()
- setInputColor();
- }
-
- function scale (startColor, endColor, t) {
- var obj = {
- r : parseInt(startColor.r + (endColor.r - startColor.r) * t, 10) ,
- g : parseInt(startColor.g + (endColor.g - startColor.g) * t, 10),
- b : parseInt(startColor.b + (endColor.b - startColor.b) * t, 10)
- };
-
- return color.format(obj, 'hex');
-
- }
-
- function checkHueColor(p) {
- var startColor, endColor;
-
- for(var i = 0; i < hue_color.length;i++) {
- if (hue_color[i].start >= p) {
- startColor = hue_color[i-1];
- endColor = hue_color[i];
- break;
- }
- }
-
- if (startColor && endColor) {
- return scale(startColor, endColor, (p - startColor.start)/(endColor.start - startColor.start));
- }
-
- return hue_color[0].rgb;
- }
-
- function setBackgroundColor (color) {
- $color.css("background-color", color);
- }
-
- function setCurrentH (h) {
- currentH = h;
- }
-
- function setHueColor(e) {
- var min = $hueContainer.offset().left;
- var max = min + $hueContainer.width();
- var current = e ? pos(e).clientX : min + (max - min) * (currentH / 360);
-
- var dist;
- if (current < min) {
- dist = 0;
- } else if (current > max) {
- dist = 100;
- } else {
- dist = (current - min) / (max - min) * 100;
- }
-
- var x = ($hueContainer.width() * (dist/100));
-
- $drag_bar.css({
- left: (x -Math.ceil($drag_bar.width()/2)) + 'px'
- });
-
- $drag_bar.data('pos', { x : x});
-
- var hueColor = checkHueColor(dist/100);
-
- setBackgroundColor(hueColor);
- setCurrentH((dist/100) * 360);
- setInputColor();
- }
-
- function getCssValuePrefix()
- {
- var rtrnVal = '';//default to standard syntax
- var prefixes = ['', '-o-', '-ms-', '-moz-', '-webkit-'];
-
- // Create a temporary DOM object for testing
- var dom = document.createElement('div');
-
- for (var i = 0; i < prefixes.length; i++)
- {
- // Attempt to set the style
- dom.style.background = prefixes[i] + 'linear-gradient(#000000, #ffffff)';
-
- // Detect if the style was successfully set
- if (dom.style.background)
- {
- rtrnVal = prefixes[i];
- }
- }
-
- dom = null;
- delete dom;
-
- return rtrnVal;
- }
-
- function setOpacityColorBar(hueColor) {
- var rgb = color.parse(hueColor);
-
- rgb.a = 0;
- var start = color.format(rgb, 'rgb');
-
- rgb.a = 1;
- var end = color.format(rgb, 'rgb');
-
- var prefix = cssPrefix;
- $opacityColorBar.css('background', 'linear-gradient(to right, ' + start + ', ' + end + ')');
- }
-
- function setOpacity(e) {
- var min = $opacityContainer.offset().left;
- var max = min + $opacityContainer.width();
- var current = pos(e).clientX;
- var dist;
-
- if (current < min) {
- dist = 0;
- } else if (current > max) {
- dist = 100;
- } else {
- dist = (current - min) / (max - min) * 100;
- }
-
- var x = ($opacityContainer.width() * (dist/100));
-
- $opacity_drag_bar.css({
- left: (x -Math.ceil($opacity_drag_bar.width()/2)) + 'px'
- });
-
- $opacity_drag_bar.data('pos', { x : x });
-
- caculateOpacity();
- currentFormat();
- setInputColor();
- }
-
- function caculateOpacity() {
- var opacityPos = $opacity_drag_bar.data('pos') || { x : 0 };
- var a = Math.round((opacityPos.x / $opacityContainer.width()) * 100) / 100;
-
- currentA = isNaN(a) ? 1 : a;
- }
-
- function caculateHSV() {
- var pos = $drag_pointer.data('pos') || { x : 0, y : 0 };
- var huePos = $drag_bar.data('pos') || { x : 0 };
-
- var width = $color.width();
- var height = $color.height();
-
- var h = (huePos.x / $hueContainer.width()) * 360;
- var s = (pos.x / width);
- var v = ((height - pos.y) / height);
-
- if (width == 0) {
- h = 0;
- s = 0;
- v = 0;
- }
-
- currentH = h;
- currentS = s;
- currentV = v;
- }
-
- function pos(e) {
- if (e.touches && e.touches[0]) {
- return e.touches[0];
- }
-
- return e;
- }
-
- function checkNumberKey(e) {
- var code = e.which,
- isExcept = false;
-
- if(code == 37 || code == 39 || code == 8 || code == 46 || code == 9)
- isExcept = true;
-
- if(!isExcept && (code < 48 || code > 57))
- return false;
-
- return true;
- }
-
- function setRGBtoHexColor(e) {
- var r = $rgb_r.val(),
- g = $rgb_g.val(),
- b = $rgb_b.val();
-
- if(r == "" || g == "" || b == "") return;
-
- if(parseInt(r) > 255) $rgb_r.val(255);
- else $rgb_r.val(parseInt(r));
-
- if(parseInt(g) > 255) $rgb_g.val(255);
- else $rgb_g.val(parseInt(g));
-
- if(parseInt(b) > 255) $rgb_b.val(255);
- else $rgb_b.val(parseInt(b));
-
- initColor(getHexFormat());
- }
-
- function setColorUI() {
- var x = $color.width() * currentS, y = $color.height() * ( 1 - currentV );
-
- $drag_pointer.css({
- left : (x - 5) + "px",
- top : (y - 5) + "px"
- });
-
- $drag_pointer.data('pos', { x : x, y : y });
-
- var hueX = $hueContainer.width() * (currentH / 360);
-
- $drag_bar.css({
- left : (hueX - 7.5) + 'px'
- });
-
- $drag_bar.data('pos', { x : hueX });
-
- var opacityX = $opacityContainer.width() * (currentA || 0);
-
- $opacity_drag_bar.css({
- left : (opacityX - 7.5) + 'px'
- });
-
- $opacity_drag_bar.data('pos', { x : opacityX });
- }
-
- function setCurrentHSV (h, s, v, a) {
- currentA = a;
- currentH = h;
- currentS = s;
- currentV = v;
- }
-
- function setCurrentFormat (format) {
- $information.data('format', format);
- initFormat();
- }
-
-
-
- function initColor(newColor) {
- var c = newColor || "#FF0000", colorObj = color.parse(c);
-
- setCurrentFormat(colorObj.type);
- setBackgroundColor(c);
-
- var hsv = color.RGBtoHSV(colorObj.r, colorObj.g, colorObj.b);
-
- setCurrentHSV(hsv.h, hsv.s, hsv.v, colorObj.a);
- setColorUI();
- setHueColor();
- setInputColor();
- }
-
- function addEvent (dom, eventName, callback) {
- dom.addEventListener(eventName, callback);
- }
-
- function removeEvent(dom, eventName, callback) {
- dom.removeEventListener(eventName, callback);
- }
-
- function EventColorMouseDown(e) {
- $color.data('isDown', true);
- setMainColor(e);
- }
-
- function EventColorMouseUp(e) {
- $color.data('isDown', false);
- }
-
- function EventDragBarMouseDown (e) {
- e.preventDefault();
- $hue.data('isDown', true);
- }
-
- function EventOpacityDragBarMouseDown(e) {
- e.preventDefault();
- $opacity.data('isDown', true);
- }
-
- function EventHueMouseDown (e) {
- $hue.data('isDown', true);
- setHueColor(e);
- }
-
- function EventOpacityMouseDown (e) {
- $opacity.data('isDown', true);
- setOpacity(e);
- }
-
- function EventHexCodeKeyDown(e) {
- if(e.which < 65 || e.which > 70) {
- return checkNumberKey(e);
- }
- }
-
- function EventHexCodeKeyUp (e) {
- var code = $hexCode.val();
-
- if(code.charAt(0) == '#' && code.length == 7) {
- initColor(code);
- }
- }
-
- function EventFormatChangeClick(e) {
- nextFormat();
- }
-
- function initEvent() {
- addEvent($color.el, 'mousedown', EventColorMouseDown);
- addEvent($color.el, 'mouseup', EventColorMouseUp);
- addEvent($drag_bar.el, 'mousedown', EventDragBarMouseDown);
- addEvent($opacity_drag_bar.el, 'mousedown', EventOpacityDragBarMouseDown);
- addEvent($hueContainer.el, 'mousedown', EventHueMouseDown);
- addEvent($opacityContainer.el, 'mousedown', EventOpacityMouseDown);
- addEvent($hexCode.el, 'keydown', EventHexCodeKeyDown);
- addEvent($hexCode.el, 'keyup', EventHexCodeKeyUp);
-
- addEvent($rgb_r.el, 'keydown', checkNumberKey);
- addEvent($rgb_r.el, 'keyup', setRGBtoHexColor);
- addEvent($rgb_g.el, 'keydown', checkNumberKey);
- addEvent($rgb_g.el, 'keyup', setRGBtoHexColor);
- addEvent($rgb_b.el, 'keydown', checkNumberKey);
- addEvent($rgb_b.el, 'keyup', setRGBtoHexColor);
-
- addEvent(document, 'mouseup', EventDocumentMouseUp);
- addEvent(document, 'mousemove', EventDocumentMouseMove);
-
- addEvent($formatChangeButton.el, 'click', EventFormatChangeClick)
- }
-
- function checkColorPickerClass(el) {
- var hasColorView = new dom(el).closest('codemirror-colorview');
- var hasColorPicker = new dom(el).closest('codemirror-colorpicker');
- var hasCodeMirror = new dom(el).closest('CodeMirror');
- var IsInHtml = el.nodeName == 'HTML';
-
- return !!(hasColorPicker || hasColorView || hasCodeMirror);
- }
-
- function checkInHtml (el) {
- var IsInHtml = el.nodeName == 'HTML';
-
- return IsInHtml;
- }
-
- function EventDocumentMouseUp (e) {
- $color.data('isDown', false);
- $hue.data('isDown', false);
- $opacity.data('isDown', false);
-
- // when color picker clicked in outside
- if (checkInHtml(e.target)) {
- //setHideDelay(hideDelay);
- } else if (checkColorPickerClass(e.target) == false ) {
- hide();
- }
-
- }
-
- function EventDocumentMouseMove(e) {
- if ($color.data('isDown')) {
- setMainColor(e);
- }
-
- if ($hue.data('isDown')) {
- setHueColor(e);
- }
-
- if ($opacity.data('isDown')) {
- setOpacity(e);
- }
- }
-
- function destroy() {
- removeEvent($color.el, 'mousedown', EventColorMouseDown);
- removeEvent($color.el, 'mouseup', EventColorMouseUp);
- removeEvent($drag_bar.el, 'mousedown', EventDragBarMouseDown);
- removeEvent($opacity_drag_bar.el, 'mousedown', EventOpacityDragBarMouseDown);
- removeEvent($hueContainer.el, 'mousedown', EventHueMouseDown);
- removeEvent($opacityContainer.el, 'mousedown', EventOpacityMouseDown);
- removeEvent($hexCode.el, 'keydown', EventHexCodeKeyDown);
- removeEvent($hexCode.el, 'keyup', EventHexCodeKeyUp);
- removeEvent($rgb_r.el, 'keydown', checkNumberKey);
- removeEvent($rgb_r.el, 'keyup', setRGBtoHexColor);
- removeEvent($rgb_g.el, 'keydown', checkNumberKey);
- removeEvent($rgb_g.el, 'keyup', setRGBtoHexColor);
- removeEvent($rgb_b.el, 'keydown', checkNumberKey);
- removeEvent($rgb_b.el, 'keyup', setRGBtoHexColor);
- removeEvent(document, 'mouseup', EventDocumentMouseUp);
- removeEvent(document, 'mousemove', EventDocumentMouseMove);
- removeEvent($formatChangeButton.el, 'click', EventFormatChangeClick);
-
- // remove color picker callback
- colorpickerCallback = undefined;
- }
-
- function currentFormat () {
- var current_format = $information.data('format') || 'hex';
- if (currentA < 1 && current_format == 'hex' ) {
- var next_format = 'rgb';
- $information.removeClass(current_format);
- $information.addClass(next_format);
- $information.data('format', next_format);
-
- setInputColor();
- }
- }
-
- function initFormat () {
- var current_format = $information.data('format') || 'hex';
-
- $information.removeClass('hex');
- $information.removeClass('rgb');
- $information.removeClass('hsl');
- $information.addClass(current_format);
- }
-
- function nextFormat() {
- var current_format = $information.data('format') || 'hex';
-
- var next_format = 'hex';
- if (current_format == 'hex') {
- next_format = 'rgb';
- } else if (current_format == 'rgb') {
- next_format = 'hsl';
- } else if (current_format == 'hsl') {
- if (currentA == 1) {
- next_format = 'hex';
- } else {
- next_format = 'rgb';
- }
- }
-
- $information.removeClass(current_format);
- $information.addClass(next_format);
- $information.data('format', next_format);
-
- setInputColor();
- }
-
- function makeInputField(type) {
- var item = new dom('div', 'information-item '+ type);
-
- if (type == 'hex') {
- var field = new dom('div', 'input-field hex');
-
- $hexCode = new dom('input', 'input', { type : 'text' });
-
- field.append($hexCode);
- field.append(new dom('div', 'title').html('HEX'));
-
- item.append(field);
-
- } else if (type == 'rgb') {
- var field = new dom('div', 'input-field rgb-r');
- $rgb_r = new dom('input', 'input', { type : 'text' });
-
- field.append($rgb_r);
- field.append(new dom('div', 'title').html('R'));
-
- item.append(field);
-
- field = new dom('div', 'input-field rgb-g');
- $rgb_g = new dom('input', 'input', { type : 'text' });
-
- field.append($rgb_g);
- field.append(new dom('div', 'title').html('G'));
-
- item.append(field);
-
- field = new dom('div', 'input-field rgb-b');
- $rgb_b = new dom('input', 'input', { type : 'text' });
-
- field.append($rgb_b);
- field.append(new dom('div', 'title').html('B'));
-
- item.append(field);
-
- // rgba
- field = new dom('div', 'input-field rgb-a');
- $rgb_a = new dom('input', 'input', { type : 'text' });
-
- field.append($rgb_a);
- field.append(new dom('div', 'title').html('A'));
-
- item.append(field);
-
- } else if (type == 'hsl') {
- var field = new dom('div', 'input-field hsl-h');
- $hsl_h = new dom('input', 'input', { type : 'text' });
-
- field.append($hsl_h);
- field.append(new dom('div', 'title').html('H'));
-
- item.append(field);
-
- field = new dom('div', 'input-field hsl-s');
- $hsl_s = new dom('input', 'input', { type : 'text' });
-
- field.append($hsl_s);
- field.append(new dom('div', 'title').html('S'));
-
- item.append(field);
-
- field = new dom('div', 'input-field hsl-l');
- $hsl_l = new dom('input', 'input', { type : 'text' });
-
- field.append($hsl_l);
- field.append(new dom('div', 'title').html('L'));
-
- item.append(field);
-
- // rgba
- field = new dom('div', 'input-field hsl-a');
- $hsl_a = new dom('input', 'input', { type : 'text' });
-
- field.append($hsl_a);
- field.append(new dom('div', 'title').html('A'));
-
- item.append(field);
- }
-
- return item;
- }
-
- function init() {
- $body = new dom(document.body);
-
- $root = new dom('div', 'codemirror-colorpicker');
- $color = new dom('div', 'color');
- $drag_pointer = new dom('div', 'drag-pointer' );
- $value = new dom( 'div', 'value' );
- $saturation = new dom('div', 'saturation' );
-
- $control = new dom('div', 'control' );
- $controlPattern = new dom('div', 'empty' );
- $controlColor = new dom('div', 'color' );
- $hue = new dom('div', 'hue' );
- $hueContainer = new dom('div', 'hue-container' );
- $drag_bar = new dom('div', 'drag-bar' );
- $opacity = new dom('div', 'opacity' );
- $opacityContainer = new dom('div', 'opacity-container' );
- $opacityColorBar = new dom('div', 'color-bar' );
-
- $opacity_drag_bar = new dom('div', 'drag-bar2' );
-
- $information = new dom('div', 'information hex' );
-
- $informationChange = new dom('div', 'information-change');
-
- $formatChangeButton = new dom('button', 'format-change-button', { type : 'button'}).html('↔');
- $informationChange.append($formatChangeButton);
-
-
- $information.append(makeInputField('hex'));
- $information.append(makeInputField('rgb'));
- $information.append(makeInputField('hsl'));
- $information.append($informationChange);
-
-
- $value.append($drag_pointer);
- $saturation.append($value);
- $color.append($saturation);
-
- $hueContainer.append($drag_bar);
- $hue.append($hueContainer);
-
- $opacityContainer.append($opacityColorBar);
- $opacityContainer.append($opacity_drag_bar);
- $opacity.append($opacityContainer);
-
- $control.append($hue);
- $control.append($opacity);
- $control.append($controlPattern);
- $control.append($controlColor);
-
- $root.append($color);
- $root.append($control);
- $root.append($information);
-
- initHueColors();
- //initEvent();
- initColor();
- };
-
- function initHueColors () {
- for(var i = 0, len = hue_color.length; i < len; i++) {
- var hue = hue_color[i];
-
- var obj = color.parse(hue.rgb);
-
- hue.r = obj.r;
- hue.g = obj.g;
- hue.b = obj.b;
- }
- }
-
- /**
- * public methods
- */
- function setColor(value) {
- if(typeof(value) == "object") {
- if(!value.r || !value.g || !value.b)
- return;
-
- initColor(color.format(value, "hex"));
- } else if(typeof(value) == "string") {
- if(value.charAt(0) != "#")
- return;
-
- initColor(value);
- }
- }
-
- function getColor(type) {
- caculateHSV();
- var rgb = convertRGB();
-
- if (type) {
- return color.format(rgb, type);
- }
-
- return rgb;
- }
-
- function definePostion (opt) {
-
- var width = $root.width();
- var height = $root.height();
-
- // set left position for color picker
- var elementScreenLeft = opt.left - $body.el.scrollLeft ;
- if (width + elementScreenLeft > window.innerWidth) {
- elementScreenLeft -= (width + elementScreenLeft) - window.innerWidth;
- }
- if (elementScreenLeft < 0) { elementScreenLeft = 0; }
-
- // set top position for color picker
- var elementScreenTop = opt.top - $body.el.scrollTop ;
- if (height + elementScreenTop > window.innerHeight) {
- elementScreenTop -= (height + elementScreenTop) - window.innerHeight;
- }
- if (elementScreenTop < 0) { elementScreenTop = 0; }
-
- // set position
- $root.css({
- left : elementScreenLeft + 'px',
- top : elementScreenTop + 'px'
- });
- }
-
- function show (opt, color, callback) {
- destroy();
- initEvent();
- $root.appendTo(document.body);
-
- $root.css({
- position: 'fixed', // color picker has fixed position
- left : '-10000px',
- top : '-10000px'
- });
-
- $root.show();
-
- definePostion(opt);
-
- isColorPickerShow = true;
-
- isShortCut = opt.isShortCut || false;
-
- initColor(color);
-
- // define colorpicker callback
- colorpickerCallback = function (colorString) {
- callback(colorString);
- }
-
- // define hide delay
- hideDelay = opt.hideDelay || 2000;
- if (hideDelay > 0) {
- setHideDelay(hideDelay);
- }
-
- }
-
-
- var timerCloseColorPicker;
- function setHideDelay (delayTime) {
- delayTime = delayTime || 0;
- removeEvent($root.el, 'mouseenter');
- removeEvent($root.el, 'mouseleave');
-
- addEvent($root.el, 'mouseenter', function () {
- clearTimeout(timerCloseColorPicker);
- });
-
- addEvent($root.el, 'mouseleave', function () {
- clearTimeout(timerCloseColorPicker);
- timerCloseColorPicker = setTimeout(hide, delayTime);
- });
-
- clearTimeout(timerCloseColorPicker);
- timerCloseColorPicker = setTimeout(hide, delayTime);
- }
-
- function hide () {
- if (isColorPickerShow) {
- destroy();
- $root.hide();
- $root.remove();
- isColorPickerShow = false;
- }
-
- }
-
+/* global CodeMirror */
+'use strict';
+
+CodeMirror.defineExtension('colorpicker', function () {
+ const cm = this;
+ const CSS_PREFIX = 'colorpicker-';
+ const HUE_COLORS = [
+ {hex: '#ff0000', start: .0},
+ {hex: '#ffff00', start: .17},
+ {hex: '#00ff00', start: .33},
+ {hex: '#00ffff', start: .50},
+ {hex: '#0000ff', start: .67},
+ {hex: '#ff00ff', start: .83},
+ {hex: '#ff0000', start: 1}
+ ];
+
+ let HSV = {};
+ let currentFormat;
+
+ let initialized = false;
+ let shown = false;
+ let options = {};
+
+ let $root;
+ let $sat, $satPointer;
+ let $hue, $hueKnob;
+ let $opacity, $opacityBar, $opacityKnob;
+ let $swatch;
+ let $formatChangeButton;
+ let $hexCode;
+ const $inputGroups = {};
+ const $inputs = {};
+ const $rgb = {};
+ const $hsl = {};
+ const $hexLettercase = {};
+
+ const dragging = {
+ saturationPointerPos: {x: 0, y: 0},
+ hueKnobPos: 0,
+ saturation: false,
+ hue: false,
+ opacity: false,
+ };
+
+ let prevFocusedElement;
+ let lastOutputColor;
+ let userActivity;
+
+ let timerCloseColorPicker;
+ let timerFadeColorPicker;
+
+ const PUBLIC_API = {
+ $root,
+ show,
+ hide,
+ setColor,
+ getColor,
+ options,
+ };
+ return PUBLIC_API;
+
+ //region DOM
+
+ function init() {
+ // simplified createElement
+ function $(a, b) {
+ const cls = typeof a === 'string' || Array.isArray(a) ? a : '';
+ const props = b || a;
+ const {tag = 'div', children} = props || {};
+ const el = document.createElement(tag);
+ el.className = (Array.isArray(cls) ? cls : [cls])
+ .map(c => (c ? CSS_PREFIX + c : ''))
+ .join(' ');
+ if (!props) {
+ return el;
+ }
+ for (const child of Array.isArray(children) ? children : [children]) {
+ if (child) {
+ el.appendChild(child instanceof Node ? child : document.createTextNode(child));
+ }
+ }
+ delete props.tag;
+ delete props.children;
+ return Object.assign(el, props);
+ }
+ const alphaPattern = /^\s*(0+\.?|0*\.\d+|0*1\.?|0*1\.0*)?\s*$/.source;
+ $root = $('popup', {children: [
+ $sat = $('saturation-container', {children: [
+ $('saturation', {children: [
+ $('value', {children: [
+ $satPointer = $('drag-pointer'),
+ ]}),
+ ]}),
+ ]}),
+ $('sliders', {children: [
+ $('hue', {children: [
+ $hue = $('hue-container', {children: [
+ $hueKnob = $('hue-knob'),
+ ]}),
+ ]}),
+ $('opacity', {children: [
+ $opacity = $('opacity-container', {children: [
+ $opacityBar = $('opacity-bar'),
+ $opacityKnob = $('opacity-knob'),
+ ]}),
+ ]}),
+ $('empty'),
+ $swatch = $('swatch'),
+ ]}),
+ $(['input-container', 'hex'], {children: [
+ $inputGroups.hex = $(['input-group', 'hex'], {children: [
+ $(['input-field', 'hex'], {children: [
+ $hexCode = $('input', {tag: 'input', type: 'text', spellcheck: false,
+ pattern: /^\s*#([a-fA-F\d]{3}([a-fA-F\d]([a-fA-F\d]{2}([a-fA-F\d]{2})?)?)?)\s*$/.source
+ }),
+ $('title', {children: [
+ $hexLettercase.true = $('title-action', {textContent: 'HEX'}),
+ '\xA0/\xA0',
+ $hexLettercase.false = $('title-action', {textContent: 'hex'}),
+ ]}),
+ ]}),
+ ]}),
+ $inputGroups.rgb = $(['input-group', 'rgb'], {children: [
+ $(['input-field', 'rgb-r'], {children: [
+ $rgb.r = $('input', {tag: 'input', type: 'number', min: 0, max: 255, step: 1}),
+ $('title', {textContent: 'R'}),
+ ]}),
+ $(['input-field', 'rgb-g'], {children: [
+ $rgb.g = $('input', {tag: 'input', type: 'number', min: 0, max: 255, step: 1}),
+ $('title', {textContent: 'G'}),
+ ]}),
+ $(['input-field', 'rgb-b'], {children: [
+ $rgb.b = $('input', {tag: 'input', type: 'number', min: 0, max: 255, step: 1}),
+ $('title', {textContent: 'B'}),
+ ]}),
+ $(['input-field', 'rgb-a'], {children: [
+ $rgb.a = $('input', {tag: 'input', type: 'text', pattern: alphaPattern, spellcheck: false}),
+ $('title', {textContent: 'A'}),
+ ]}),
+ ]}),
+ $inputGroups.hsl = $(['input-group', 'hsl'], {children: [
+ $(['input-field', 'hsl-h'], {children: [
+ $hsl.h = $('input', {tag: 'input', type: 'number', step: 1}),
+ $('title', {textContent: 'H'}),
+ ]}),
+ $(['input-field', 'hsl-s'], {children: [
+ $hsl.s = $('input', {tag: 'input', type: 'number', min: 0, max: 100, step: 1}),
+ $('title', {textContent: 'S'}),
+ ]}),
+ $(['input-field', 'hsl-l'], {children: [
+ $hsl.l = $('input', {tag: 'input', type: 'number', min: 0, max: 100, step: 1}),
+ $('title', {textContent: 'L'}),
+ ]}),
+ $(['input-field', 'hsl-a'], {children: [
+ $hsl.a = $('input', {tag: 'input', type: 'text', pattern: alphaPattern, spellcheck: false}),
+ $('title', {textContent: 'A'}),
+ ]}),
+ ]}),
+ $('format-change', {children: [
+ $formatChangeButton = $('format-change-button', {textContent: '↔'}),
+ ]}),
+ ]}),
+ ]});
+
+ $inputs.hex = [$hexCode];
+ $inputs.rgb = [$rgb.r, $rgb.g, $rgb.b, $rgb.a];
+ $inputs.hsl = [$hsl.h, $hsl.s, $hsl.l, $hsl.a];
+ const inputsToArray = inputs => inputs.map(el => parseFloat(el.value));
+ const inputsToHexString = () => $hexCode.value.trim();
+ const inputsToRGB = ([r, g, b, a] = inputsToArray($inputs.rgb)) => ({r, g, b, a, type: 'rgb'});
+ const inputsToHSL = ([h, s, l, a] = inputsToArray($inputs.hsl)) => ({h, s, l, a, type: 'hsl'});
+ Object.defineProperty($inputs.hex, 'color', {get: inputsToHexString});
+ Object.defineProperty($inputs.rgb, 'color', {get: inputsToRGB});
+ Object.defineProperty($inputs.hsl, 'color', {get: inputsToHSL});
+ Object.defineProperty($inputs, 'color', {get: () => $inputs[currentFormat].color});
+
+ HUE_COLORS.forEach(color => Object.assign(color, stringToColor(color.hex)));
+
+ initialized = true;
+ }
+
+ //endregion
+ //region Public API
+
+ function show(opt) {
+ if (!initialized) {
+ init();
+ }
+ $root.style = `
+ display: block;
+ position: fixed;
+ left: -10000px;
+ top: -10000px;
+ `.replace(/;/g, '!important;');
+ $root.classList.add(CSS_PREFIX + 'theme-' +
+ (opt.theme === 'dark' || opt.theme === 'light' ? opt.theme : guessTheme()));
+ document.body.appendChild($root);
+
+ shown = true;
+
+ HSV = {};
+ currentFormat = '';
+ options = PUBLIC_API.options = opt;
+ prevFocusedElement = document.activeElement;
+ userActivity = 0;
+ lastOutputColor = opt.color;
+ $formatChangeButton.title = opt.tooltipForSwitcher || '';
+ opt.hideDelay = Math.max(0, opt.hideDelay) || 2000;
+
+ registerEvents();
+ reposition();
+ setFromColor(opt.color);
+ setFromHexLettercaseElement();
+ $inputs[currentFormat][0].focus();
+ }
+
+ function hide() {
+ if (shown) {
+ unregisterEvents();
+ focusNoScroll(prevFocusedElement);
+ $root.remove();
+ shown = false;
+ }
+ }
+
+ function setColor(color) {
+ switch (typeof color) {
+ case 'string':
+ color = stringToColor(color);
+ break;
+ case 'object': {
+ const {r, g, b, a} = color;
+ if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
+ color = {r, g, b, a, type: 'rgb'};
+ break;
+ }
+ const {h, s, l} = color;
+ if (!isNaN(h) && !isNaN(s) && !isNaN(l)) {
+ color = {h, s, l, a, type: 'hsl'};
+ break;
+ }
+ }
+ // fallthrough
+ default:
+ return false;
+ }
+ if (color) {
+ if (!initialized) {
init();
+ }
+ setFromColor(color);
+ }
+ return Boolean(color);
+ }
- return {
- isShortCut : function () {
- return isShortCut;
- },
- $root: $root,
- show: show,
- hide: hide,
- setColor: setColor,
- getColor: getColor
- }
- })
+ function getColor(type) {
+ if (!initialized) {
+ return;
+ }
+ readCurrentColorFromRamps();
+ const color = type === 'hsl' ? HSVtoHSL(HSV) : HSVtoRGB(HSV);
+ return type ? colorToString(color, type) : color;
+ }
+ //endregion
+ //region DOM-to-state
+
+ function readCurrentColorFromRamps() {
+ if ($sat.offsetWidth === 0) {
+ HSV.h = HSV.s = HSV.v = 0;
+ } else {
+ const {x, y} = dragging.saturationPointerPos;
+ HSV.h = snapToInt((dragging.hueKnobPos / $hue.offsetWidth) * 360);
+ HSV.s = x / $sat.offsetWidth;
+ HSV.v = ($sat.offsetHeight - y) / $sat.offsetHeight;
+ }
+ }
+
+ function setFromSaturationElement(event) {
+ event.preventDefault();
+ const w = $sat.offsetWidth;
+ const h = $sat.offsetHeight;
+ const deltaX = event.clientX - parseFloat($root.style.left);
+ const deltaY = event.clientY - parseFloat($root.style.top);
+ const x = dragging.saturationPointerPos.x = constrain(0, w, deltaX);
+ const y = dragging.saturationPointerPos.y = constrain(0, h, deltaY);
+
+ $satPointer.style.left = `${x - 5}px`;
+ $satPointer.style.top = `${y - 5}px`;
+
+ readCurrentColorFromRamps();
+ renderInputs();
+ }
+
+ function setFromHueElement(event) {
+ const {left, width} = getScreenBounds($hue);
+ const currentX = event ? getTouchPosition(event).clientX : left + width * (HSV.h / 360);
+ const normalizedH = constrain(0, 1, (currentX - left) / width);
+ const x = dragging.hueKnobPos = width * normalizedH;
+ $hueKnob.style.left = (x - Math.round($hueKnob.offsetWidth / 2)) + 'px';
+ $sat.style.backgroundColor = hueDistanceToColorString(normalizedH);
+ HSV.h = event ? Math.round(normalizedH * 360) : HSV.h;
+ renderInputs();
+ }
+
+ function setFromOpacityElement(event) {
+ const {left, width} = getScreenBounds($opacity);
+ const normalized = constrain(0, 1, (getTouchPosition(event).clientX - left) / width);
+ const x = width * normalized;
+ $opacityKnob.style.left = (x - Math.ceil($opacityKnob.offsetWidth / 2)) + 'px';
+ HSV.a = Math.round(normalized * 100) / 100;
+ renderInputs();
+ }
+
+ function setFromFormatElement() {
+ userActivity = performance.now();
+ const nextFormat = {hex: 'rgb', rgb: 'hsl', hsl: 'hex'}[currentFormat];
+ HSV.a = isNaN(HSV.a) ? 1 : HSV.a;
+ switchInputGroup(nextFormat);
+ renderInputs();
+ }
+
+ function setFromHexLettercaseElement() {
+ const isUpper = Boolean(options.hexUppercase);
+ $hexLettercase[isUpper].dataset.active = '';
+ delete $hexLettercase[!isUpper].dataset.active;
+ const value = $hexCode.value;
+ $hexCode.value = isUpper ? value.toUpperCase() : value.toLowerCase();
+ setFromInputs();
+ }
+
+ function setFromInputs() {
+ userActivity = performance.now();
+ if ($inputs[currentFormat].every(validateInput)) {
+ setFromColor($inputs.color);
+ }
+ }
+
+ function validateInput(el) {
+ const isAlpha = el.type === 'text';
+ let isValid = (isAlpha || el.value.trim()) && el.checkValidity();
+ if (!isAlpha && !isValid && currentFormat === 'rgb') {
+ isValid = parseAs(el, parseInt);
+ } else if (isAlpha && !isValid) {
+ isValid = parseAs(el, parseFloat);
+ }
+ if (isAlpha && isValid) {
+ isValid = lastOutputColor !== colorToString($inputs.color);
+ }
+ return isValid;
+ }
+ //endregion
+ //region State-to-DOM
+
+ function setFromColor(color = '#FF0000') {
+ color = typeof color === 'string' ? stringToColor(color) : color;
+ const newHSV = color.type === 'hsl' ? HSLtoHSV(color) : RGBtoHSV(color);
+ if (Object.keys(newHSV).every(k => Math.abs(newHSV[k] - HSV[k]) < 1e-3)) {
+ return;
+ }
+ HSV = newHSV;
+ renderKnobs(color);
+ switchInputGroup(color.type);
+ setFromHueElement();
+ }
+
+ function switchInputGroup(format) {
+ if (currentFormat === format) {
+ return;
+ }
+ if (currentFormat) {
+ delete $inputGroups[currentFormat].dataset.active;
+ } else {
+ for (const format in $inputGroups) {
+ delete $inputGroups[format].dataset.active;
+ }
+ }
+ $inputGroups[format].dataset.active = '';
+ currentFormat = format;
+ }
+
+ function renderKnobs(color) {
+ const x = $sat.offsetWidth * HSV.s;
+ const y = $sat.offsetHeight * (1 - HSV.v);
+ $satPointer.style.left = (x - 5) + 'px';
+ $satPointer.style.top = (y - 5) + 'px';
+ dragging.saturationPointerPos = {x, y};
+
+ const hueX = $hue.offsetWidth * (HSV.h / 360);
+ $hueKnob.style.left = (hueX - 7.5) + 'px';
+ dragging.hueKnobPos = hueX;
+
+ const opacityX = $opacity.offsetWidth * (isNaN(HSV.a) ? 1 : HSV.a);
+ $opacityKnob.style.left = (opacityX - 7.5) + 'px';
+
+ $sat.style.backgroundColor = color;
+ }
+
+ function renderInputs() {
+ const rgb = HSVtoRGB(HSV);
+ switch (currentFormat) {
+ case 'hex':
+ $hexCode.value = colorToString(rgb, 'hex');
+ break;
+ case 'rgb': {
+ $rgb.r.value = rgb.r;
+ $rgb.g.value = rgb.g;
+ $rgb.b.value = rgb.b;
+ $rgb.a.value = alphaToString() || 1;
+ break;
+ }
+ case 'hsl': {
+ const {h, s, l} = HSVtoHSL(HSV);
+ $hsl.h.value = h;
+ $hsl.s.value = s;
+ $hsl.l.value = l;
+ $hsl.a.value = alphaToString() || 1;
+ }
+ }
+ $swatch.style.backgroundColor = colorToString(rgb, 'rgb');
+ $opacityBar.style.background = 'linear-gradient(to right,' +
+ colorToString(Object.assign(rgb, {a: 0}), 'rgb') + ',' +
+ colorToString(Object.assign(rgb, {a: 1}), 'rgb') + ')';
+ colorpickerCallback();
+ }
+
+ //endregion
+ //region Event listeners
+
+ function onHexLettercaseClicked() {
+ options.hexUppercase = !options.hexUppercase;
+ setFromHexLettercaseElement();
+ }
+
+ function onSaturationMouseDown(event) {
+ if (event.button === 0) {
+ setFromSaturationElement(event);
+ dragging.saturation = true;
+ captureMouse();
+ }
+ }
+
+ function onSaturationMouseUp() {
+ if (event.button === 0) {
+ dragging.saturation = false;
+ releaseMouse();
+ }
+ }
+
+ function onHueKnobMouseDown(event) {
+ if (event.button === 0) {
+ dragging.hue = true;
+ captureMouse();
+ }
+ }
+
+ function onOpacityKnobMouseDown() {
+ if (event.button === 0) {
+ dragging.opacity = true;
+ captureMouse();
+ }
+ }
+
+ function onHueMouseDown(event) {
+ if (event.button === 0) {
+ dragging.hue = true;
+ setFromHueElement(event);
+ captureMouse();
+ }
+ }
+
+ function onOpacityMouseDown(event) {
+ if (event.button === 0) {
+ dragging.opacity = true;
+ setFromOpacityElement(event);
+ captureMouse();
+ }
+ }
+
+ function onMouseUp(event) {
+ if (event.button === 0) {
+ releaseMouse();
+ dragging.saturation = dragging.hue = dragging.opacity = false;
+ if (!event.target.closest('.codemirror-colorview, .colorpicker-popup, .CodeMirror')) {
+ hide();
+ }
+ }
+ }
+
+ function onMouseMove(event) {
+ if (event.button !== 0) {
+ return;
+ }
+ if (dragging.saturation) {
+ setFromSaturationElement(event);
+ } else if (dragging.hue) {
+ setFromHueElement(event);
+ } else if (dragging.opacity) {
+ setFromOpacityElement(event);
+ }
+ }
+
+ function stopSnoozing() {
+ clearTimeout(timerCloseColorPicker);
+ clearTimeout(timerFadeColorPicker);
+ if ($root.dataset.fading) {
+ delete $root.dataset.fading;
+ }
+ }
+
+ function snooze() {
+ clearTimeout(timerFadeColorPicker);
+ timerFadeColorPicker = setTimeout(fade, options.hideDelay / 2);
+ }
+
+ function onKeyDown(e) {
+ if (!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
+ switch (e.which) {
+ case 13:
+ colorpickerCallback();
+ // fallthrough to 27
+ case 27:
+ e.preventDefault();
+ e.stopPropagation();
+ hide();
+ break;
+ }
+ }
+ }
+
+ function onCloseRequest(event) {
+ if (event.detail !== PUBLIC_API) {
+ hide();
+ }
+ }
+
+ //endregion
+ //region Event utilities
+
+ function colorpickerCallback(colorString = currentColorToString()) {
+ if (
+ userActivity &&
+ $inputs[currentFormat].every(el => el.checkValidity()) &&
+ typeof options.callback === 'function'
+ ) {
+ lastOutputColor = colorString.replace(/\b0\./g, '.');
+ options.callback(lastOutputColor);
+ }
+ }
+
+ function captureMouse() {
+ document.addEventListener('mouseup', onMouseUp);
+ document.addEventListener('mousemove', onMouseMove);
+ userActivity = performance.now();
+ }
+
+ function releaseMouse() {
+ document.removeEventListener('mouseup', onMouseUp);
+ document.removeEventListener('mousemove', onMouseMove);
+ userActivity = performance.now();
+ }
+
+ function getTouchPosition(event) {
+ return event.touches && event.touches[0] || event;
+ }
+
+ function registerEvents() {
+ window.addEventListener('keydown', onKeyDown, true);
+ window.addEventListener('close-colorpicker-popup', onCloseRequest, true);
+ $root.addEventListener('mouseleave', snooze);
+ $root.addEventListener('mouseenter', stopSnoozing);
+ $root.addEventListener('input', setFromInputs);
+ $formatChangeButton.addEventListener('click', setFromFormatElement);
+ $sat.addEventListener('mousedown', onSaturationMouseDown);
+ $sat.addEventListener('mouseup', onSaturationMouseUp);
+ $hueKnob.addEventListener('mousedown', onHueKnobMouseDown);
+ $opacityKnob.addEventListener('mousedown', onOpacityKnobMouseDown);
+ $hue.addEventListener('mousedown', onHueMouseDown);
+ $opacity.addEventListener('mousedown', onOpacityMouseDown);
+ $hexLettercase.true.addEventListener('click', onHexLettercaseClicked);
+ $hexLettercase.false.addEventListener('click', onHexLettercaseClicked);
+
+ stopSnoozing();
+ timerFadeColorPicker = setTimeout(fade, options.hideDelay / 2);
+ }
+
+ function unregisterEvents() {
+ window.removeEventListener('keydown', onKeyDown, true);
+ window.removeEventListener('close-colorpicker-popup', hide, true);
+ $root.removeEventListener('mouseleave', snooze);
+ $root.removeEventListener('mouseenter', stopSnoozing);
+ $root.removeEventListener('input', setFromInputs);
+ $formatChangeButton.removeEventListener('click', setFromFormatElement);
+ $sat.removeEventListener('mousedown', onSaturationMouseDown);
+ $sat.removeEventListener('mouseup', onSaturationMouseUp);
+ $hueKnob.removeEventListener('mousedown', onHueKnobMouseDown);
+ $opacityKnob.removeEventListener('mousedown', onOpacityKnobMouseDown);
+ $hue.removeEventListener('mousedown', onHueMouseDown);
+ $opacity.removeEventListener('mousedown', onOpacityMouseDown);
+ $hexLettercase.true.removeEventListener('click', onHexLettercaseClicked);
+ $hexLettercase.false.removeEventListener('click', onHexLettercaseClicked);
+ releaseMouse();
+ stopSnoozing();
+ }
+
+ //endregion
+ //region Color conversion utilities
+
+ function colorToString({r, g, b, h, s, l, a}, type = currentFormat) {
+ a = alphaToString(a);
+ const hasA = Boolean(a);
+ switch (type) {
+ case 'hex': {
+ const rgbStr = (0x1000000 + (r << 16) + (g << 8) + (b | 0)).toString(16).slice(1);
+ const aStr = hasA ? (0x100 + Math.round(a * 255)).toString(16).slice(1) : '';
+ const hexStr = `#${rgbStr + aStr}`.replace(/^#(.)\1(.)\2(.)\3(?:(.)\4)?$/, '#$1$2$3$4');
+ return options.hexUppercase ? hexStr.toUpperCase() : hexStr.toLowerCase();
+ }
+ case 'rgb':
+ return hasA ?
+ `rgba(${r}, ${g}, ${b}, ${a})` :
+ `rgb(${r}, ${g}, ${b})`;
+ case 'hsl':
+ return hasA ?
+ `hsla(${h}, ${s}%, ${l}%, ${a})` :
+ `hsl(${h}, ${s}%, ${l}%)`;
+ }
+ }
+
+ function stringToColor(str) {
+ if (typeof str !== 'string') {
+ return;
+ }
+ str = str.trim();
+ if (str.startsWith('rgb')) {
+ const [r, g, b, a = 1] = str.replace(/rgba?\(|\)/g, '').split(',').map(parseFloat);
+ return {type: 'rgb', r, g, b, a};
+ }
+ if (str.startsWith('hsl')) {
+ const [h, s, l, a = 1] = str.replace(/hsla?\(|\)/g, '').split(',').map(parseFloat);
+ return {type: 'hsl', h, s, l, a};
+ }
+ if (str.startsWith('#')) {
+ str = str.slice(1);
+ const [r, g, b, a = 255] = str.length <= 4 ?
+ str.match(/(.)/g).map(c => parseInt(c + c, 16)) :
+ str.match(/(..)/g).map(c => parseInt(c, 16));
+ return {type: 'hex', r, g, b, a: a === 255 ? undefined : a / 255};
+ }
+ return;
+ }
+
+ function RGBtoHSV({r, g, b, a}) {
+ r /= 255;
+ g /= 255;
+ b /= 255;
+ const MaxC = Math.max(r, g, b);
+ const MinC = Math.min(r, g, b);
+ const DeltaC = MaxC - MinC;
+
+ let h =
+ DeltaC === 0 ? 0 :
+ MaxC === r ? 60 * (((g - b) / DeltaC) % 6) :
+ MaxC === g ? 60 * (((b - r) / DeltaC) + 2) :
+ MaxC === b ? 60 * (((r - g) / DeltaC) + 4) :
+ 0;
+ h =
+ h < 0 ? h % 360 + 360 :
+ h > 360 ? h % 360 :
+ h;
+ return {
+ h,
+ s: MaxC === 0 ? 0 : DeltaC / MaxC,
+ v: MaxC,
+ a,
+ };
+ }
+
+ function HSVtoRGB({h, s, v}) {
+ if (h === 360) {
+ h = 0;
+ }
+ const C = s * v;
+ const X = C * (1 - Math.abs((h / 60) % 2 - 1));
+ const m = v - C;
+ const [r, g, b] =
+ h >= 0 && h < 60 ? [C, X, 0] :
+ h >= 60 && h < 120 ? [X, C, 0] :
+ h >= 120 && h < 180 ? [0, C, X] :
+ h >= 180 && h < 240 ? [0, X, C] :
+ h >= 240 && h < 300 ? [X, 0, C] :
+ h >= 300 && h < 360 ? [C, 0, X] : [];
+ return {
+ r: snapToInt(Math.round((r + m) * 255)),
+ g: snapToInt(Math.round((g + m) * 255)),
+ b: snapToInt(Math.round((b + m) * 255)),
+ };
+ }
+
+ function HSLtoHSV({h, s, l, a}) {
+ const t = s * (l < 50 ? l : 100 - l) / 100;
+ return {
+ h,
+ s: t + l ? 200 * t / (t + l) / 100 : 0,
+ v: (t + l) / 100,
+ a,
+ };
+ }
+
+ function HSVtoHSL({h, s, v}) {
+ const l = (2 - s) * v / 2;
+ const t = l < .5 ? l * 2 : 2 - l * 2;
+ return {
+ h: Math.round(h),
+ s: Math.round(t ? s * v / t * 100 : 0),
+ l: Math.round(l * 100),
+ };
+ }
+
+ function currentColorToString(format = currentFormat, alpha = HSV.a) {
+ const converted = format === 'hsl' ? HSVtoHSL(HSV) : HSVtoRGB(HSV);
+ converted.a = isNaN(alpha) || alpha === 1 ? undefined : alpha;
+ return colorToString(converted, format);
+ }
+
+ function mixColorToString(start, end, amount) {
+ const obj = {
+ r: start.r + (end.r - start.r) * amount,
+ g: start.g + (end.g - start.g) * amount,
+ b: start.b + (end.b - start.b) * amount,
+ a: 1,
+ };
+ return colorToString(obj, 'hex');
+ }
+
+ function hueDistanceToColorString(hueRatio) {
+ let prevColor;
+ for (const color of HUE_COLORS) {
+ if (prevColor && color.start >= hueRatio) {
+ return mixColorToString(prevColor, color,
+ (hueRatio - prevColor.start) / (color.start - prevColor.start));
+ }
+ prevColor = color;
+ }
+ return HUE_COLORS[0].hex;
+ }
+
+ function alphaToString(a = HSV.a) {
+ return isNaN(a) ? '' :
+ a.toString().slice(0, 8)
+ .replace(/(\.[^0]*)0+$/, '$1')
+ .replace(/^1$/, '');
+ }
+
+ //endregion
+ //region Miscellaneous utilities
+
+ function reposition() {
+ const width = $root.offsetWidth;
+ const height = $root.offsetHeight;
+
+ // set left position for color picker
+ let elementScreenLeft = options.left - document.scrollingElement.scrollLeft;
+ const bodyWidth = document.scrollingElement.scrollWidth;
+ if (width + elementScreenLeft > bodyWidth) {
+ elementScreenLeft -= (width + elementScreenLeft) - bodyWidth;
+ }
+ if (elementScreenLeft < 0) {
+ elementScreenLeft = 0;
+ }
+
+ // set top position for color picker
+ let elementScreenTop = options.top - document.scrollingElement.scrollTop;
+ if (height + elementScreenTop > window.innerHeight) {
+ elementScreenTop = window.innerHeight - height;
+ }
+ if (elementScreenTop < options.top) {
+ elementScreenTop = options.top - height - 20;
+ }
+ if (elementScreenTop < 0) {
+ elementScreenTop = 0;
+ }
+
+ // set position
+ $root.style.left = elementScreenLeft + 'px';
+ $root.style.top = elementScreenTop + 'px';
+ }
+
+ function fade({fadingStage = 1} = {}) {
+ const timeInactive = performance.now() - userActivity;
+ const delay = options.hideDelay / 2;
+ if (userActivity && timeInactive < delay) {
+ timerFadeColorPicker = setTimeout(fade, delay - timeInactive, 2);
+ clearTimeout(timerCloseColorPicker);
+ delete $root.dataset.fading;
+ return;
+ }
+ $root.dataset.fading = fadingStage;
+ if (fadingStage === 1) {
+ timerFadeColorPicker = setTimeout(fade, Math.max(0, delay - 500), {fadingStage: 2});
+ } else {
+ timerCloseColorPicker = setTimeout(hide, 500);
+ }
+ }
+
+ function focusNoScroll(el) {
+ if (el) {
+ const {scrollY: y, scrollX: x} = window;
+ el.focus({preventScroll: true});
+ el = null;
+ if (window.scrollY !== y || window.scrollX !== x) {
+ window.scrollTo(x, y);
+ }
+ }
+ }
+
+ function getScreenBounds(el) {
+ const bounds = el.getBoundingClientRect();
+ const {scrollTop, scrollLeft} = document.scrollingElement;
+ return {
+ top: bounds.top + scrollTop,
+ left: bounds.left + scrollLeft,
+ width: bounds.width,
+ height: bounds.height,
+ };
+ }
+
+ function guessTheme() {
+ const realColor = {r: 255, g: 255, b: 255, a: 1};
+ const start = ((cm.display.renderedView || [])[0] || {}).text || cm.display.lineDiv;
+ for (let el = start; el; el = el.parentElement) {
+ const bgColor = getComputedStyle(el).backgroundColor;
+ const [r, g, b, a = 255] = bgColor.match(/\d+/g).map(Number);
+ if (!a) {
+ continue;
+ }
+ const mixedA = 1 - (1 - a / 255) * (1 - realColor.a);
+ const q1 = a / 255 / mixedA;
+ const q2 = realColor.a * (1 - mixedA) / mixedA;
+ realColor.r = Math.round(r * q1 + realColor.r * q2);
+ realColor.g = Math.round(g * q1 + realColor.g * q2);
+ realColor.b = Math.round(b * q1 + realColor.b * q2);
+ realColor.a = mixedA;
+ }
+ // https://www.w3.org/TR/AERT#color-contrast
+ const {r, g, b} = realColor;
+ const brightness = r * .299 + g * .587 + b * .114;
+ return brightness < 128 ? 'dark' : 'light';
+ }
+
+ function constrain(min, max, value) {
+ return value < min ? min : value > max ? max : value;
+ }
+
+ function snapToInt(num) {
+ const int = Math.round(num);
+ return Math.abs(int - num) < 1e-3 ? int : num;
+ }
+
+ function parseAs(el, parser) {
+ const num = parser(el.value);
+ if (!isNaN(num)) {
+ el.value = num;
+ return true;
+ }
+ }
+
+ //endregion
});
diff --git a/vendor-overwrites/colorpicker/colorview.js b/vendor-overwrites/colorpicker/colorview.js
index b53fec3e..7086926b 100644
--- a/vendor-overwrites/colorpicker/colorview.js
+++ b/vendor-overwrites/colorpicker/colorview.js
@@ -1,434 +1,457 @@
-(function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
- mod(require("codemirror"));
- else if (typeof define == "function" && define.amd) // AMD
- define(["codemirror"], mod);
- else // Plain browser env
- mod(CodeMirror);
-})(function(CodeMirror) {
- "use strict";
+/* global CodeMirror */
+'use strict';
- // color names
- var color_names={aliceblue:"rgb(240, 248, 255)",antiquewhite:"rgb(250, 235, 215)",aqua:"rgb(0, 255, 255)",aquamarine:"rgb(127, 255, 212)",azure:"rgb(240, 255, 255)",beige:"rgb(245, 245, 220)",bisque:"rgb(255, 228, 196)",black:"rgb(0, 0, 0)",blanchedalmond:"rgb(255, 235, 205)",blue:"rgb(0, 0, 255)",blueviolet:"rgb(138, 43, 226)",brown:"rgb(165, 42, 42)",burlywood:"rgb(222, 184, 135)",cadetblue:"rgb(95, 158, 160)",chartreuse:"rgb(127, 255, 0)",chocolate:"rgb(210, 105, 30)",coral:"rgb(255, 127, 80)",cornflowerblue:"rgb(100, 149, 237)",cornsilk:"rgb(255, 248, 220)",crimson:"rgb(237, 20, 61)",cyan:"rgb(0, 255, 255)",darkblue:"rgb(0, 0, 139)",darkcyan:"rgb(0, 139, 139)",darkgoldenrod:"rgb(184, 134, 11)",darkgray:"rgb(169, 169, 169)",darkgrey:"rgb(169, 169, 169)",darkgreen:"rgb(0, 100, 0)",darkkhaki:"rgb(189, 183, 107)",darkmagenta:"rgb(139, 0, 139)",darkolivegreen:"rgb(85, 107, 47)",darkorange:"rgb(255, 140, 0)",darkorchid:"rgb(153, 50, 204)",darkred:"rgb(139, 0, 0)",darksalmon:"rgb(233, 150, 122)",darkseagreen:"rgb(143, 188, 143)",darkslateblue:"rgb(72, 61, 139)",darkslategray:"rgb(47, 79, 79)",darkslategrey:"rgb(47, 79, 79)",darkturquoise:"rgb(0, 206, 209)",darkviolet:"rgb(148, 0, 211)",deeppink:"rgb(255, 20, 147)",deepskyblue:"rgb(0, 191, 255)",dimgray:"rgb(105, 105, 105)",dimgrey:"rgb(105, 105, 105)",dodgerblue:"rgb(30, 144, 255)",firebrick:"rgb(178, 34, 34)",floralwhite:"rgb(255, 250, 240)",forestgreen:"rgb(34, 139, 34)",fuchsia:"rgb(255, 0, 255)",gainsboro:"rgb(220, 220, 220)",ghostwhite:"rgb(248, 248, 255)",gold:"rgb(255, 215, 0)",goldenrod:"rgb(218, 165, 32)",gray:"rgb(128, 128, 128)",grey:"rgb(128, 128, 128)",green:"rgb(0, 128, 0)",greenyellow:"rgb(173, 255, 47)",honeydew:"rgb(240, 255, 240)",hotpink:"rgb(255, 105, 180)",indianred:"rgb(205, 92, 92)",indigo:"rgb(75, 0, 130)",ivory:"rgb(255, 255, 240)",khaki:"rgb(240, 230, 140)",lavender:"rgb(230, 230, 250)",lavenderblush:"rgb(255, 240, 245)",lawngreen:"rgb(124, 252, 0)",lemonchiffon:"rgb(255, 250, 205)",lightblue:"rgb(173, 216, 230)",lightcoral:"rgb(240, 128, 128)",lightcyan:"rgb(224, 255, 255)",lightgoldenrodyellow:"rgb(250, 250, 210)",lightgreen:"rgb(144, 238, 144)",lightgray:"rgb(211, 211, 211)",lightgrey:"rgb(211, 211, 211)",lightpink:"rgb(255, 182, 193)",lightsalmon:"rgb(255, 160, 122)",lightseagreen:"rgb(32, 178, 170)",lightskyblue:"rgb(135, 206, 250)",lightslategray:"rgb(119, 136, 153)",lightslategrey:"rgb(119, 136, 153)",lightsteelblue:"rgb(176, 196, 222)",lightyellow:"rgb(255, 255, 224)",lime:"rgb(0, 255, 0)",limegreen:"rgb(50, 205, 50)",linen:"rgb(250, 240, 230)",magenta:"rgb(255, 0, 255)",maroon:"rgb(128, 0, 0)",mediumaquamarine:"rgb(102, 205, 170)",mediumblue:"rgb(0, 0, 205)",mediumorchid:"rgb(186, 85, 211)",mediumpurple:"rgb(147, 112, 219)",mediumseagreen:"rgb(60, 179, 113)",mediumslateblue:"rgb(123, 104, 238)",mediumspringgreen:"rgb(0, 250, 154)",mediumturquoise:"rgb(72, 209, 204)",mediumvioletred:"rgb(199, 21, 133)",midnightblue:"rgb(25, 25, 112)",mintcream:"rgb(245, 255, 250)",mistyrose:"rgb(255, 228, 225)",moccasin:"rgb(255, 228, 181)",navajowhite:"rgb(255, 222, 173)",navy:"rgb(0, 0, 128)",oldlace:"rgb(253, 245, 230)",olive:"rgb(128, 128, 0)",olivedrab:"rgb(107, 142, 35)",orange:"rgb(255, 165, 0)",orangered:"rgb(255, 69, 0)",orchid:"rgb(218, 112, 214)",palegoldenrod:"rgb(238, 232, 170)",palegreen:"rgb(152, 251, 152)",paleturquoise:"rgb(175, 238, 238)",palevioletred:"rgb(219, 112, 147)",papayawhip:"rgb(255, 239, 213)",peachpuff:"rgb(255, 218, 185)",peru:"rgb(205, 133, 63)",pink:"rgb(255, 192, 203)",plum:"rgb(221, 160, 221)",powderblue:"rgb(176, 224, 230)",purple:"rgb(128, 0, 128)",rebeccapurple:"rgb(102, 51, 153)",red:"rgb(255, 0, 0)",rosybrown:"rgb(188, 143, 143)",royalblue:"rgb(65, 105, 225)",saddlebrown:"rgb(139, 69, 19)",salmon:"rgb(250, 128, 114)",sandybrown:"rgb(244, 164, 96)",seagreen:"rgb(46, 139, 87)",seashell:"rgb(255, 245, 238)",sienna:"rgb(160, 82, 45)",silver:"rgb(192, 192, 192)",skyblue:"rgb(135, 206, 235)",slateblue:"rgb(106, 90, 205)",slategray:"rgb(112, 128, 144)",slategrey:"rgb(112, 128, 144)",snow:"rgb(255, 250, 250)",springgreen:"rgb(0, 255, 127)",steelblue:"rgb(70, 130, 180)",tan:"rgb(210, 180, 140)",teal:"rgb(0, 128, 128)",thistle:"rgb(216, 191, 216)",tomato:"rgb(255, 99, 71)",turquoise:"rgb(64, 224, 208)",violet:"rgb(238, 130, 238)",wheat:"rgb(245, 222, 179)",white:"rgb(255, 255, 255)",whitesmoke:"rgb(245, 245, 245)",yellow:"rgb(255, 255, 0)",yellowgreen:"rgb(154, 205, 50)",transparent:"rgba(0, 0, 0, 0)"};
+(() => {
+ const OWN_TOKEN_NAME = 'colorview';
+ const OWN_DOM_CLASS = 'cm-' + OWN_TOKEN_NAME;
+ const OWN_BACKGROUND_CLASS = 'codemirror-colorview-background';
+ const HOOKED_TOKEN = new Map([
+ ['atom', colorizeAtom],
+ ['keyword', colorizeKeyword],
+ ].map(([name, fn]) => [name, {override: name + ' ' + OWN_TOKEN_NAME, process: fn}]));
- var colorpicker_class = 'codemirror-colorview';
- var colorpicker_background_class = 'codemirror-colorview-background';
+ const NAMED_COLORS = getNamedColorsMap();
+ const TRANSPARENT = {
+ color: 'transparent',
+ colorValue: 'rgba(0, 0, 0, 0)', // as per the CSS spec
+ };
+ const RX_COLOR = {
+ hex: /#(?:[a-f\d]{3,4}|[a-f\d]{6}|[a-f\d]{8})\b/yi,
+ rgb: /rgb\((?:\s*\d{1,3}\s*,\s*){2}\d{1,3}\s*\)/yi,
+ rgba: /rgba\((?:\s*\d{1,3}\s*,\s*){3}\d*\.?\d+\s*\)/yi,
+ hsl: /hsl\(\s*(?:-?\d+|-?\d*\.\d+)\s*(?:,\s*(?:-?\d+|-?\d*\.\d+)%\s*){2}\)/yi,
+ hsla: /hsla\(\s*(?:-?\d+|-?\d*\.\d+)\s*(?:,\s*(?:-?\d+|-?\d*\.\d+)%\s*){2},\s*(?:-?\d+|-?\d*\.\d+)\s*\)/yi,
+ named: new RegExp([...NAMED_COLORS.keys()].join('|'), 'i'),
+ };
- // Excluded tokens do not show color views..
- var excluded_token = ['comment'];
+ const CodeMirrorEvents = {
+ update(cm) {
+ if (cm.state.colorpicker.cache.size) {
+ renderVisibleTokens(cm);
+ }
+ },
+ keyup(cm) {
+ const popup = cm.state.colorpicker.popup;
+ if (popup && popup.options.isShortCut === false) {
+ popup.hide();
+ }
+ },
+ mousedown(cm, event) {
+ const self = cm.state.colorpicker;
+ const isMarker = event.button === 0 && event.target.classList.contains(OWN_BACKGROUND_CLASS);
+ window.dispatchEvent(new CustomEvent('close-colorpicker-popup', {detail: isMarker && self.popup}));
+ if (isMarker) {
+ event.preventDefault();
+ self.openPopupForToken(event.target.parentNode);
+ }
+ },
+ };
- CodeMirror.defineOption("colorpicker", false, function (cm, val, old) {
+ function registerEvents(cm) {
+ Object.keys(CodeMirrorEvents).forEach(name => cm.on(name, CodeMirrorEvents[name]));
+ }
- if (old && old != CodeMirror.Init) {
+ function unregisterEvents(cm) {
+ Object.keys(CodeMirrorEvents).forEach(name => cm.off(name, CodeMirrorEvents[name]));
+ }
- if (cm.state.colorpicker)
- {
- cm.state.colorpicker.destroy();
- cm.state.colorpicker = null;
+ function registerHooks() {
+ const mx = CodeMirror.modeExtensions.css;
+ if (!mx || mx.token !== colorizeToken) {
+ CodeMirror.extendMode('css', {
+ token: colorizeToken,
+ });
+ }
+ }
- }
- // remove event listener
+ function unregisterHooks() {
+ const mx = CodeMirror.modeExtensions.css;
+ if (mx && mx.token === colorizeToken) {
+ delete mx.token;
+ }
+ }
+
+ function resetMode(cm) {
+ cm.setOption('mode', cm.getMode().name);
+ }
+
+ function colorizeToken(stream, state) {
+ const token = this._token.apply(this, arguments);
+ const hookedToken = token && HOOKED_TOKEN.get(token);
+ if (!token || !hookedToken) {
+ return token;
+ }
+ const data = state.colorpicker = (state.colorpicker || {});
+ const cache = data.cache = (data.cache || stream.lineOracle.doc.cm.state.colorpicker.cache);
+ const string = stream.string;
+ const sameString = string === data.lastString;
+
+ data.lastString = string;
+
+ let lineCache = data.lineCache = (sameString ? data.lineCache : cache.get(string));
+ if (lineCache && lineCache.get(stream.start)) {
+ return hookedToken.override;
+ }
+
+ const color = hookedToken.process(stream);
+ if (color) {
+ if (!lineCache) {
+ lineCache = data.lineCache = new Map();
+ cache.set(string, lineCache);
+ }
+ lineCache.set(stream.start, color);
+ lineCache.set('lastAccessTime', performance.now());
+ return hookedToken.override;
+ }
+
+ return token;
+ }
+
+ function colorizeAtom(stream) {
+ const {start, pos, string} = stream;
+ const c1 = string.charAt(start);
+ if ((c1 === 't' || c1 === 'T') && string.slice(start, pos).toLowerCase() === 'transparent') {
+ return TRANSPARENT;
+ }
+ const maybeHex = c1 === '#';
+ const s = !maybeHex && string.charAt(pos) === '(' && string.slice(start, pos).toLowerCase();
+ if (maybeHex || (s === 'rgb' || s === 'rgba' || s === 'hsl' || s === 'hsla')) {
+ const rx = maybeHex ? RX_COLOR.hex : RX_COLOR[s];
+ rx.lastIndex = start;
+ const match = rx.exec(string);
+ return match && {color: match[0]};
+ }
+ }
+
+ function colorizeKeyword(stream) {
+ const {start, pos, string} = stream;
+ if (string.charAt(start) !== '!') {
+ const color = string.slice(start, pos);
+ const colorValue = NAMED_COLORS.get(color.toLowerCase());
+ return colorValue && {color, colorValue};
+ }
+ }
+
+ function renderVisibleTokens(cm) {
+ const {cache, options} = cm.state.colorpicker;
+ let line = cm.display.viewFrom - 1;
+ for (const {line: lineHandle, text} of cm.display.renderedView) {
+ if (!lineHandle.parent) {
+ continue;
+ }
+ line++;
+ const styles = lineHandle.styles;
+ if (!styles) {
+ continue;
+ }
+ const lineCache = cache.get(lineHandle.text);
+ if (!lineCache) {
+ continue;
+ }
+ let lineCacheAlive = false;
+ let elementIndex = 0;
+ let elements;
+ for (let i = 1; i < styles.length; i += 2) {
+ const token = styles[i + 1];
+ if (!token || !token.includes(OWN_TOKEN_NAME)) {
+ continue;
}
-
- if (val)
- {
- cm.state.colorpicker = new codemirror_colorpicker(cm, val);
+ const start = styles[i - 2] || 0;
+ const data = lineCache.get(start);
+ if (!data) {
+ continue;
}
- });
-
- function onChange(cm, evt) {
- if (evt.origin == 'setValue') { // if content is changed by setValue method, it initialize markers
- cm.state.colorpicker.close_color_picker();
- cm.state.colorpicker.init_color_update();
- cm.state.colorpicker.style_color_update();
- } else {
- cm.state.colorpicker.style_color_update(cm.getCursor().line);
+ elements = elements || text.getElementsByClassName(OWN_DOM_CLASS);
+ const el = elements[elementIndex++];
+ if (el.colorpickerData && el.colorpickerData.color === data.color) {
+ continue;
}
-
- }
-
- function onUpdate(cm, evt) {
- if (!cm.state.colorpicker.isUpdate) {
- cm.state.colorpicker.isUpdate = true;
- cm.state.colorpicker.close_color_picker();
- cm.state.colorpicker.init_color_update();
- cm.state.colorpicker.style_color_update();
+ el.colorpickerData = Object.assign({line, ch: start}, data);
+ let bg = el.firstElementChild;
+ if (!bg) {
+ bg = document.createElement('div');
+ bg.className = OWN_BACKGROUND_CLASS;
+ bg.title = options.tooltip;
+ el.appendChild(bg);
}
+ bg.style.setProperty('background-color', data.color, 'important');
+ lineCacheAlive = true;
+ }
+ if (lineCacheAlive) {
+ lineCache.set('lastAccessTime', performance.now());
+ }
+ }
+ trimCache(cm);
+ }
+
+ function trimCache(cm, debounced) {
+ if (!debounced) {
+ clearTimeout(trimCache.timer);
+ trimCache.timer = setTimeout(trimCache, 20e3, cm, true);
+ return;
+ }
+ const cutoff = performance.now() - 60e3;
+ const {cache} = cm.state.colorpicker;
+ const textToKeep = new Set();
+ cm.doc.iter(({text}) => textToKeep.add(text));
+ for (const [text, lineCache] of cache.entries()) {
+ if (lineCache.get('lastAccessTime') < cutoff && !textToKeep.has(text)) {
+ cache.delete(text);
+ }
+ }
+ }
+
+ function getNamedColorsMap() {
+ return new Map([
+ ['aliceblue', '#f0f8ff'],
+ ['antiquewhite', '#faebd7'],
+ ['aqua', '#00ffff'],
+ ['aquamarine', '#7fffd4'],
+ ['azure', '#f0ffff'],
+ ['beige', '#f5f5dc'],
+ ['bisque', '#ffe4c4'],
+ ['black', '#000000'],
+ ['blanchedalmond', '#ffebcd'],
+ ['blue', '#0000ff'],
+ ['blueviolet', '#8a2be2'],
+ ['brown', '#a52a2a'],
+ ['burlywood', '#deb887'],
+ ['cadetblue', '#5f9ea0'],
+ ['chartreuse', '#7fff00'],
+ ['chocolate', '#d2691e'],
+ ['coral', '#ff7f50'],
+ ['cornflowerblue', '#6495ed'],
+ ['cornsilk', '#fff8dc'],
+ ['crimson', '#dc143c'],
+ ['cyan', '#00ffff'],
+ ['darkblue', '#00008b'],
+ ['darkcyan', '#008b8b'],
+ ['darkgoldenrod', '#b8860b'],
+ ['darkgray', '#a9a9a9'],
+ ['darkgreen', '#006400'],
+ ['darkgrey', '#a9a9a9'],
+ ['darkkhaki', '#bdb76b'],
+ ['darkmagenta', '#8b008b'],
+ ['darkolivegreen', '#556b2f'],
+ ['darkorange', '#ff8c00'],
+ ['darkorchid', '#9932cc'],
+ ['darkred', '#8b0000'],
+ ['darksalmon', '#e9967a'],
+ ['darkseagreen', '#8fbc8f'],
+ ['darkslateblue', '#483d8b'],
+ ['darkslategray', '#2f4f4f'],
+ ['darkslategrey', '#2f4f4f'],
+ ['darkturquoise', '#00ced1'],
+ ['darkviolet', '#9400d3'],
+ ['deeppink', '#ff1493'],
+ ['deepskyblue', '#00bfff'],
+ ['dimgray', '#696969'],
+ ['dimgrey', '#696969'],
+ ['dodgerblue', '#1e90ff'],
+ ['firebrick', '#b22222'],
+ ['floralwhite', '#fffaf0'],
+ ['forestgreen', '#228b22'],
+ ['fuchsia', '#ff00ff'],
+ ['gainsboro', '#dcdcdc'],
+ ['ghostwhite', '#f8f8ff'],
+ ['gold', '#ffd700'],
+ ['goldenrod', '#daa520'],
+ ['gray', '#808080'],
+ ['green', '#008000'],
+ ['greenyellow', '#adff2f'],
+ ['grey', '#808080'],
+ ['honeydew', '#f0fff0'],
+ ['hotpink', '#ff69b4'],
+ ['indianred', '#cd5c5c'],
+ ['indigo', '#4b0082'],
+ ['ivory', '#fffff0'],
+ ['khaki', '#f0e68c'],
+ ['lavender', '#e6e6fa'],
+ ['lavenderblush', '#fff0f5'],
+ ['lawngreen', '#7cfc00'],
+ ['lemonchiffon', '#fffacd'],
+ ['lightblue', '#add8e6'],
+ ['lightcoral', '#f08080'],
+ ['lightcyan', '#e0ffff'],
+ ['lightgoldenrodyellow', '#fafad2'],
+ ['lightgray', '#d3d3d3'],
+ ['lightgreen', '#90ee90'],
+ ['lightgrey', '#d3d3d3'],
+ ['lightpink', '#ffb6c1'],
+ ['lightsalmon', '#ffa07a'],
+ ['lightseagreen', '#20b2aa'],
+ ['lightskyblue', '#87cefa'],
+ ['lightslategray', '#778899'],
+ ['lightslategrey', '#778899'],
+ ['lightsteelblue', '#b0c4de'],
+ ['lightyellow', '#ffffe0'],
+ ['lime', '#00ff00'],
+ ['limegreen', '#32cd32'],
+ ['linen', '#faf0e6'],
+ ['magenta', '#ff00ff'],
+ ['maroon', '#800000'],
+ ['mediumaquamarine', '#66cdaa'],
+ ['mediumblue', '#0000cd'],
+ ['mediumorchid', '#ba55d3'],
+ ['mediumpurple', '#9370db'],
+ ['mediumseagreen', '#3cb371'],
+ ['mediumslateblue', '#7b68ee'],
+ ['mediumspringgreen', '#00fa9a'],
+ ['mediumturquoise', '#48d1cc'],
+ ['mediumvioletred', '#c71585'],
+ ['midnightblue', '#191970'],
+ ['mintcream', '#f5fffa'],
+ ['mistyrose', '#ffe4e1'],
+ ['moccasin', '#ffe4b5'],
+ ['navajowhite', '#ffdead'],
+ ['navy', '#000080'],
+ ['oldlace', '#fdf5e6'],
+ ['olive', '#808000'],
+ ['olivedrab', '#6b8e23'],
+ ['orange', '#ffa500'],
+ ['orangered', '#ff4500'],
+ ['orchid', '#da70d6'],
+ ['palegoldenrod', '#eee8aa'],
+ ['palegreen', '#98fb98'],
+ ['paleturquoise', '#afeeee'],
+ ['palevioletred', '#db7093'],
+ ['papayawhip', '#ffefd5'],
+ ['peachpuff', '#ffdab9'],
+ ['peru', '#cd853f'],
+ ['pink', '#ffc0cb'],
+ ['plum', '#dda0dd'],
+ ['powderblue', '#b0e0e6'],
+ ['purple', '#800080'],
+ ['rebeccapurple', '#663399'],
+ ['red', '#ff0000'],
+ ['rosybrown', '#bc8f8f'],
+ ['royalblue', '#4169e1'],
+ ['saddlebrown', '#8b4513'],
+ ['salmon', '#fa8072'],
+ ['sandybrown', '#f4a460'],
+ ['seagreen', '#2e8b57'],
+ ['seashell', '#fff5ee'],
+ ['sienna', '#a0522d'],
+ ['silver', '#c0c0c0'],
+ ['skyblue', '#87ceeb'],
+ ['slateblue', '#6a5acd'],
+ ['slategray', '#708090'],
+ ['slategrey', '#708090'],
+ ['snow', '#fffafa'],
+ ['springgreen', '#00ff7f'],
+ ['steelblue', '#4682b4'],
+ ['tan', '#d2b48c'],
+ ['teal', '#008080'],
+ ['thistle', '#d8bfd8'],
+ ['tomato', '#ff6347'],
+ ['turquoise', '#40e0d0'],
+ ['violet', '#ee82ee'],
+ ['wheat', '#f5deb3'],
+ ['white', '#ffffff'],
+ ['whitesmoke', '#f5f5f5'],
+ ['yellow', '#ffff00'],
+ ['yellowgreen', '#9acd32'],
+ ]);
+ }
+
+ class ColorMarker {
+ constructor(cm, {
+ tooltip = 'Open color picker',
+ popupOptions = {},
+ colorpicker,
+ forceUpdate,
+ } = {}) {
+ this.cm = cm;
+ this.options = {
+ tooltip,
+ popup: Object.assign({
+ hideDelay: 2000,
+ hexUppercase: false,
+ tooltipForSwitcher: 'Switch formats: HEX -> RGB -> HSL',
+ }, popupOptions),
+ };
+ this.popup = cm.colorpicker ? cm.colorpicker() : colorpicker;
+ this.cache = new Map();
+ registerHooks(cm);
+ registerEvents(cm);
+ if (forceUpdate) {
+ resetMode(cm);
+ }
}
- function onRefresh(cm, evt) {
- onChange(cm, { origin : 'setValue'});
+ destroy() {
+ unregisterHooks(this.cm);
+ unregisterEvents(this.cm);
+ resetMode(this.cm);
+ this.cm.state.colorpicker = null;
}
- function onKeyup(cm, evt) {
- cm.state.colorpicker.keyup(evt);
- }
-
- function onMousedown(cm, evt) {
- if (cm.state.colorpicker.is_edit_mode())
- {
- cm.state.colorpicker.check_mousedown(evt);
+ openPopup(defaultColor = '#FFFFFF') {
+ const cursor = this.cm.getCursor();
+ const data = {
+ line: cursor.line,
+ ch: cursor.ch,
+ color: defaultColor,
+ isShortCut: true,
+ };
+ for (const {from, marker} of this.cm.getLineHandle(cursor.line).markedSpans || []) {
+ if (from <= data.ch && (marker.replacedWith || {}).colorpickerData) {
+ const {color, colorValue} = marker.replacedWith.colorpickerData;
+ if (data.ch <= from + color.length) {
+ data.ch = from;
+ data.color = color;
+ data.colorValue = colorValue;
+ break;
+ }
}
+ }
+ this.openPopupForToken({colorpickerData: data});
}
- function onPaste (cm, evt) {
- onChange(cm, { origin : 'setValue'});
+ openPopupForToken({colorpickerData: data}) {
+ if (this.popup) {
+ const {left, bottom: top} = this.cm.charCoords(data, 'window');
+ this.popup.show(Object.assign(this.options.popup, data, {
+ top,
+ left,
+ cm: this.cm,
+ color: data.colorValue || data.color,
+ prevColor: data.color,
+ isShortCut: false,
+ callback: ColorMarker.popupOnChange,
+ }));
+ }
}
- function onScroll (cm) {
- cm.state.colorpicker.close_color_picker();
+ closePopup() {
+ if (this.popup) {
+ this.popup.hide();
+ }
}
- function debounce (callback, delay) {
-
- var t = undefined;
-
- return function (cm, e) {
- if (t) {
- clearTimeout(t);
- }
-
- t = setTimeout(function () {
- callback(cm, e);
- }, delay || 300);
- }
+ static popupOnChange(newColor) {
+ const {cm, line, ch, embedderCallback} = this;
+ const to = {line, ch: ch + this.prevColor.length};
+ if (cm.getRange(this, to) !== newColor) {
+ this.prevColor = newColor;
+ cm.replaceRange(newColor, this, to, '*colorpicker');
+ }
+ if (typeof embedderCallback === 'function') {
+ embedderCallback(this);
+ }
}
+ }
- function has_class(el, cls) {
- if (!el || !el.className) {
- return false;
- } else {
- var newClass = ' ' + el.className + ' ';
- return newClass.indexOf(' ' + cls + ' ') > -1;
- }
+ CodeMirror.defineOption('colorpicker', false, (cm, value, oldValue) => {
+ if (oldValue && oldValue !== CodeMirror.Init && cm.state.colorpicker) {
+ cm.state.colorpicker.destroy();
}
-
- function codemirror_colorpicker (cm, opt) {
- var self = this;
-
- if (typeof opt == 'boolean')
- {
- opt = { mode : 'view' };
- } else {
- opt = Object.assign({ mode: 'view' }, opt || {});
- }
-
- this.opt = opt;
- this.cm = cm;
- this.markers = {};
-
- // set excluded token
- excluded_token = this.opt.excluded_token || excluded_token;
-
- if (this.cm.colorpicker) {
- this.colorpicker = this.cm.colorpicker();
- } else if (this.opt.colorpicker) {
- this.colorpicker = this.opt.colorpicker;
- }
-
- this.init_event();
-
+ if (value) {
+ cm.state.colorpicker = new ColorMarker(cm, value);
}
+ });
- codemirror_colorpicker.prototype.init_event = function () {
-
- this.cm.on('mousedown', onMousedown);
- this.cm.on('keyup', onKeyup);
- this.cm.on('change', onChange);
- this.cm.on('update', onUpdate);
- this.cm.on('refresh', onRefresh);
-
- // create paste callback
- this.onPasteCallback = (function (cm, callback) {
- return function (evt) {
- callback.call(this, cm, evt);
- }
- })(this.cm, onPaste);
-
- this.cm.getWrapperElement().addEventListener('paste', this.onPasteCallback);
-
- if (this.is_edit_mode())
- {
- this.cm.on('scroll', debounce(onScroll, 50));
- }
-
- }
-
- codemirror_colorpicker.prototype.is_edit_mode = function () {
- return this.opt.mode == 'edit';
- }
-
- codemirror_colorpicker.prototype.is_view_mode = function () {
- return this.opt.mode == 'view';
- }
-
- codemirror_colorpicker.prototype.destroy = function () {
- this.cm.off('mousedown', onMousedown);
- this.cm.off('keyup', onKeyup);
- this.cm.off('change', onChange)
- this.cm.getWrapperElement().removeEventListener('paste', this.onPasteCallback);
-
- if (this.is_edit_mode())
- {
- this.cm.off('scroll');
- }
- }
-
- codemirror_colorpicker.prototype.hasClass = function (el, className) {
- if (!el.className)
- {
- return false;
- } else {
- var newClass = ' ' + el.className + ' ';
- return newClass.indexOf(' ' + className + ' ') > -1;
- }
- }
-
- codemirror_colorpicker.prototype.check_mousedown = function (evt) {
- if (this.hasClass(evt.target, colorpicker_background_class) )
- {
- this.open_color_picker(evt.target.parentNode);
- } else {
- this.close_color_picker();
- }
- }
-
- codemirror_colorpicker.prototype.popup_color_picker = function (defalutColor) {
- var cursor = this.cm.getCursor();
- var self = this;
- var colorMarker = {
- lineNo : cursor.line,
- ch : cursor.ch,
- color: defalutColor || '#FFFFFF',
- isShortCut : true
- };
-
- Object.keys(this.markers).forEach(function(key) {
- var searchKey = "#" + key;
- if (searchKey.indexOf( "#" + colorMarker.lineNo + ":") > -1) {
- var marker = self.markers[key];
-
- if (marker.ch <= colorMarker.ch && colorMarker.ch <= marker.ch + marker.color.length) {
- // when cursor has marker
- colorMarker.ch = marker.ch;
- colorMarker.color = marker.color;
- colorMarker.nameColor = marker.nameColor;
- }
-
- }
- });
-
- this.open_color_picker(colorMarker);
- }
-
- codemirror_colorpicker.prototype.open_color_picker = function (el) {
- var lineNo = el.lineNo;
- var ch = el.ch;
- var nameColor = el.nameColor;
- var color = el.color;
-
-
- if (this.colorpicker) {
- var self = this;
- var prevColor = color;
- var pos = this.cm.charCoords({line : lineNo, ch : ch });
- this.colorpicker.show({
- left : pos.left,
- top : pos.bottom,
- isShortCut : el.isShortCut || false,
- hideDelay : self.opt.hideDelay || 2000
- }, nameColor || color, function (newColor) {
- self.cm.replaceRange(newColor, { line : lineNo, ch : ch } , { line : lineNo, ch : ch + prevColor.length }, '*colorpicker');
- prevColor = newColor;
- });
-
- }
-
- }
-
- codemirror_colorpicker.prototype.close_color_picker = function (el) {
- if (this.colorpicker)
- {
- this.colorpicker.hide();
- }
- }
-
- codemirror_colorpicker.prototype.key = function (lineNo, ch) {
- return [lineNo, ch].join(":");
- }
-
-
- codemirror_colorpicker.prototype.keyup = function (evt) {
-
- if (this.colorpicker ) {
- if (evt.key == 'Escape') {
- this.colorpicker.hide();
- } else if (this.colorpicker.isShortCut() == false) {
- this.colorpicker.hide();
- }
- }
- }
-
- codemirror_colorpicker.prototype.init_color_update = function () {
- this.markers = {}; // initialize marker list
- }
-
- codemirror_colorpicker.prototype.style_color_update = function (lineHandle) {
-
- if (lineHandle) {
- this.match(lineHandle);
- } else {
- var max = this.cm.lineCount();
-
- for(var lineNo = 0; lineNo < max; lineNo++) {
- this.match(lineNo);
- }
- }
-
- }
-
- codemirror_colorpicker.prototype.empty_marker = function (lineNo, lineHandle) {
- var list = lineHandle.markedSpans || [];
-
- for(var i = 0, len = list.length; i < len; i++) {
- var key = this.key(lineNo, list[i].from);
-
- if (key && has_class(list[i].marker.replacedWith, colorpicker_class)) {
- delete this.markers[key];
- list[i].marker.clear();
- }
-
- }
- }
-
- codemirror_colorpicker.prototype.color_regexp = /(#(?:[\da-f]{3}){1,2}|rgb\((?:\s*\d{1,3},\s*){2}\d{1,3}\s*\)|rgba\((?:\s*\d{1,3},\s*){3}\d*\.?\d+\s*\)|hsl\(\s*\d{1,3}(?:,\s*\d{1,3}%){2}\s*\)|hsla\(\s*\d{1,3}(?:,\s*\d{1,3}%){2},\s*\d*\.?\d+\s*\)|([\w_\-]+))/gi;
-
- codemirror_colorpicker.prototype.match_result = function (lineHandle) {
- return lineHandle.text.match(this.color_regexp);
- }
-
- codemirror_colorpicker.prototype.match = function (lineNo) {
- var lineHandle = this.cm.getLineHandle(lineNo);
-
- this.empty_marker(lineNo, lineHandle);
-
- var result = this.match_result(lineHandle);
- if (result)
- {
- var obj = { next : 0 };
- for(var i = 0, len = result.length; i < len; i++) {
-
- if (result[i].indexOf('#') > -1 || result[i].indexOf('rgb') > -1 || result[i].indexOf('hsl') > -1) {
- this.render(obj, lineNo, lineHandle, result[i]);
- } else {
- var nameColor = color_names[result[i]];
- if (nameColor) {
- this.render(obj, lineNo, lineHandle, result[i], nameColor);
- }
- }
- }
- }
- }
-
- codemirror_colorpicker.prototype.make_element = function () {
- var el = document.createElement('div');
-
- el.className = colorpicker_class;
-
- if (this.is_edit_mode())
- {
- el.title ="open color picker";
- } else {
- el.title ="";
- }
-
- el.back_element = this.make_background_element();
- el.appendChild(el.back_element);
-
- return el;
- }
-
- codemirror_colorpicker.prototype.make_background_element = function () {
- var el = document.createElement('div');
-
- el.className = colorpicker_background_class;
-
- return el;
- }
-
- codemirror_colorpicker.prototype.set_state = function (lineNo, start, color, nameColor) {
- var marker = this.create_marker(lineNo, start);
-
-
- marker.lineNo = lineNo;
- marker.ch = start;
- marker.color = color;
- marker.nameColor = nameColor;
-
- return marker;
- }
-
- codemirror_colorpicker.prototype.create_marker = function (lineNo, start) {
-
- var key = this.key(lineNo,start);
-
- if (!this.markers[key]) {
- this.markers[key] = this.make_element();
- }
-
-
- return this.markers[key];
-
- }
-
- codemirror_colorpicker.prototype.has_marker = function (lineNo, start) {
- var key = this.key(lineNo,start);
- return !!(this.markers[key])
- }
-
- codemirror_colorpicker.prototype.update_element = function (el, color) {
- el.back_element.style.backgroundColor = color;
- }
-
- codemirror_colorpicker.prototype.set_mark = function (line, ch, el) {
- this.cm.setBookmark({ line : line, ch : ch}, { widget : el, handleMouseEvents : true} );
-
- }
-
- codemirror_colorpicker.prototype.is_excluded_token = function (line, ch) {
- var token = this.cm.getTokenAt({line : line, ch : ch});
- var count = 0;
- for(var i = 0, len = excluded_token.length; i < len; i++) {
- if (token.type === excluded_token[i]) {
- count++;
- break;
- }
- }
-
- return count > 0; // true is that it has a excluded token
- }
-
- codemirror_colorpicker.prototype.render = function (cursor, lineNo, lineHandle, color, nameColor) {
- var start = lineHandle.text.indexOf(color, cursor.next);
-
- if (this.is_excluded_token(lineNo, start) === true) {
- // excluded token do not show.
- return;
- }
-
- cursor.next = start + color.length;
-
- if (this.has_marker(lineNo, start))
- {
- this.update_element(this.create_marker(lineNo, start), nameColor || color);
- this.set_state(lineNo, start, color, nameColor);
- return;
- }
-
- var el = this.create_marker(lineNo, start);
-
- this.update_element(el, nameColor || color);
- this.set_state(lineNo, start, color, nameColor || color);
- this.set_mark(lineNo, start, el);
- }
-});
+ // initial runMode is performed by CodeMirror before setting our option
+ // so we register the hooks right away - not a problem as our js is loaded on demand
+ registerHooks();
+})();