rewrite colorview to use CodeMirror::TextMarker
* solves all problems with glitching on selection etc. * perceived performance is same due to lazy-processing * colors unsupported in current browser are displayed internally as RGB * the color text is highlighted in the editor when popup is invoked
This commit is contained in:
parent
2dfaa22c35
commit
d0380f76c3
|
@ -179,8 +179,11 @@ function createAppliesToLineWidget(cm) {
|
||||||
fromLine = Math.max(fromLine || 0, cm.display.viewFrom);
|
fromLine = Math.max(fromLine || 0, cm.display.viewFrom);
|
||||||
toLine = Math.min(toLine === null ? cm.doc.size : toLine, cm.display.viewTo || toLine);
|
toLine = Math.min(toLine === null ? cm.doc.size : toLine, cm.display.viewTo || toLine);
|
||||||
const visible = {fromLine, toLine};
|
const visible = {fromLine, toLine};
|
||||||
|
const {curOp} = cm;
|
||||||
if (fromLine >= cm.display.viewFrom && toLine <= (cm.display.viewTo || toLine)) {
|
if (fromLine >= cm.display.viewFrom && toLine <= (cm.display.viewTo || toLine)) {
|
||||||
cm.operation(doUpdate);
|
if (!curOp) cm.startOperation();
|
||||||
|
doUpdate();
|
||||||
|
if (!curOp) cm.endOperation();
|
||||||
}
|
}
|
||||||
if (changed.fromLine !== visible.fromLine || changed.toLine !== visible.toLine) {
|
if (changed.fromLine !== visible.fromLine || changed.toLine !== visible.toLine) {
|
||||||
setTimeout(updateInvisible, 0, changed, visible);
|
setTimeout(updateInvisible, 0, changed, visible);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
onDOMscriptReady('/colorview.js').then(() => {
|
onDOMscriptReady('/colorview.js').then(() => {
|
||||||
initOverlayHooks();
|
|
||||||
onDOMready().then(() => {
|
onDOMready().then(() => {
|
||||||
$('#colorpicker-settings').onclick = configureColorpicker;
|
$('#colorpicker-settings').onclick = configureColorpicker;
|
||||||
});
|
});
|
||||||
|
@ -23,7 +22,7 @@ onDOMscriptReady('/colorview.js').then(() => {
|
||||||
defaults.colorpicker = {
|
defaults.colorpicker = {
|
||||||
forceUpdate: editors.length > 0,
|
forceUpdate: editors.length > 0,
|
||||||
tooltip: t('colorpickerTooltip'),
|
tooltip: t('colorpickerTooltip'),
|
||||||
popupOptions: {
|
popup: {
|
||||||
tooltipForSwitcher: t('colorpickerSwitchFormatTooltip'),
|
tooltipForSwitcher: t('colorpickerSwitchFormatTooltip'),
|
||||||
hexUppercase: prefs.get('editor.colorpicker.hexUppercase'),
|
hexUppercase: prefs.get('editor.colorpicker.hexUppercase'),
|
||||||
hideDelay: 5000,
|
hideDelay: 5000,
|
||||||
|
@ -35,7 +34,6 @@ onDOMscriptReady('/colorview.js').then(() => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
CodeMirror.modeExtensions.css.unregisterColorviewHooks();
|
|
||||||
if (defaults.extraKeys) {
|
if (defaults.extraKeys) {
|
||||||
delete defaults.extraKeys[keyName];
|
delete defaults.extraKeys[keyName];
|
||||||
}
|
}
|
||||||
|
@ -114,47 +112,4 @@ onDOMscriptReady('/colorview.js').then(() => {
|
||||||
}
|
}
|
||||||
input.focus();
|
input.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initOverlayHooks() {
|
|
||||||
const COLORVIEW_DISABLED_SUFFIX = ' colorview-disabled';
|
|
||||||
const COLORVIEW_NEXT_DISABLED_SUFFIX = ' colorview-next-disabled';
|
|
||||||
const originalAddOverlay = CodeMirror.prototype.addOverlay;
|
|
||||||
CodeMirror.prototype.addOverlay = addOverlayHook;
|
|
||||||
|
|
||||||
function addOverlayHook(overlay) {
|
|
||||||
if (overlay.token !== tokenHook && (
|
|
||||||
overlay === (this.state.matchHighlighter || {}).overlay ||
|
|
||||||
overlay === (this.state.search || {}).overlay)) {
|
|
||||||
overlay.colopickerHelper = {token: overlay.token};
|
|
||||||
overlay.token = tokenHook;
|
|
||||||
}
|
|
||||||
originalAddOverlay.apply(this, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenHook(stream) {
|
|
||||||
const style = this.colopickerHelper.token.apply(this, arguments);
|
|
||||||
if (!style) {
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
const {start, pos, lineOracle: {baseTokens}} = stream;
|
|
||||||
if (!baseTokens) {
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
for (let prev = 0, i = 1; i < baseTokens.length; i += 2) {
|
|
||||||
const end = baseTokens[i];
|
|
||||||
if (prev <= start && start <= end) {
|
|
||||||
const base = baseTokens[i + 1];
|
|
||||||
if (base && base.includes('colorview')) {
|
|
||||||
return style +
|
|
||||||
(start > prev ? COLORVIEW_DISABLED_SUFFIX : '') +
|
|
||||||
(pos < end ? COLORVIEW_NEXT_DISABLED_SUFFIX : '');
|
|
||||||
}
|
|
||||||
} else if (end > pos) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev = end;
|
|
||||||
}
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,20 +29,15 @@ function createSourceEditor(style) {
|
||||||
style = deepCopy(style);
|
style = deepCopy(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cm = CodeMirror($('.single-editor'));
|
const cm = CodeMirror($('.single-editor'), {value: style.sourceCode});
|
||||||
editors.push(cm);
|
editors.push(cm);
|
||||||
|
savedGeneration = cm.changeGeneration();
|
||||||
|
|
||||||
|
cm.operation(initAppliesToLineWidget);
|
||||||
updateMeta().then(() => {
|
updateMeta().then(() => {
|
||||||
initLint();
|
initLint();
|
||||||
initLinterSwitch();
|
initLinterSwitch();
|
||||||
|
|
||||||
cm.setValue(style.sourceCode);
|
|
||||||
cm.clearHistory();
|
|
||||||
cm.markClean();
|
|
||||||
savedGeneration = cm.changeGeneration();
|
|
||||||
|
|
||||||
initHooks();
|
initHooks();
|
||||||
initAppliesToLineWidget();
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if ((document.activeElement || {}).localName !== 'input') {
|
if ((document.activeElement || {}).localName !== 'input') {
|
||||||
cm.focus();
|
cm.focus();
|
||||||
|
|
|
@ -11,11 +11,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-heading {
|
.config-heading {
|
||||||
float: right;
|
top: -1em;
|
||||||
margin: -1.25rem 0 0 0;
|
position: relative;
|
||||||
|
text-align: right;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#stylus-popup .config-heading {
|
||||||
|
top: -.25em;
|
||||||
|
}
|
||||||
|
|
||||||
.config-body label {
|
.config-body label {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: .75em 0;
|
padding: .75em 0;
|
||||||
|
@ -97,6 +102,10 @@
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.config-reset-icon {
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.config-reset-icon .svg-icon {
|
.config-reset-icon .svg-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
fill: #aaa;
|
fill: #aaa;
|
||||||
|
@ -140,14 +149,22 @@
|
||||||
animation: fadein .5s;
|
animation: fadein .5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-colorview::before,
|
#message-box .colorview-swatch {
|
||||||
.color-swatch {
|
padding: 0;
|
||||||
width: var(--onoffswitch-width) !important;
|
box-sizing: content-box;
|
||||||
height: 20px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-colorview::before {
|
#message-box .colorview-swatch,
|
||||||
margin: 1px !important;
|
#message-box .colorview-swatch::before,
|
||||||
|
#message-box .colorview-swatch::after,
|
||||||
|
.color-swatch {
|
||||||
|
width: var(--onoffswitch-width);
|
||||||
|
height: 20px;
|
||||||
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
box-sizing: content-box;
|
||||||
|
background-position: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-swatch {
|
.color-swatch {
|
||||||
|
@ -157,6 +174,7 @@
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.colorpicker-popup {
|
.colorpicker-popup {
|
||||||
|
|
|
@ -210,7 +210,7 @@ function configDialog(style) {
|
||||||
switch (va.type) {
|
switch (va.type) {
|
||||||
case 'color':
|
case 'color':
|
||||||
children = [
|
children = [
|
||||||
$create('.cm-colorview.config-value', [
|
$create('.colorview-swatch.config-value', [
|
||||||
va.input = $create('a.color-swatch', {
|
va.input = $create('a.color-swatch', {
|
||||||
va,
|
va,
|
||||||
href: '#',
|
href: '#',
|
||||||
|
|
|
@ -1,39 +1,38 @@
|
||||||
/* codemirror colorview */
|
/* codemirror colorview */
|
||||||
|
|
||||||
.cm-colorview {
|
.colorview-swatch {
|
||||||
position: relative;
|
padding-left: 14px;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-colorview:not(.cm-colorview-disabled)::before {
|
|
||||||
content: "";
|
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
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;
|
|
||||||
}
|
|
||||||
.CodeMirror-lint-mark-warning + .cm-colorview::before,
|
|
||||||
.cm-colorview-next-disabled + .cm-colorview::before {
|
|
||||||
content: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.codemirror-colorview-background {
|
.colorview-swatch::before,
|
||||||
|
.colorview-swatch::after {
|
||||||
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
left: 2px;
|
left: 2px;
|
||||||
top: 2px;
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 1px solid #8e8e8e;
|
|
||||||
content: "";
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.codemirror-colorview-background:hover {
|
.colorview-swatch::before {
|
||||||
|
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC");
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorview-swatch::after {
|
||||||
|
border: 1px solid #8e8e8e;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--colorview-swatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorview-swatch:hover::after {
|
||||||
border-color: #494949;
|
border-color: #494949;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +179,7 @@
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
border: 1px solid var(--input-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.colorpicker-empty {
|
.colorpicker-empty {
|
||||||
|
|
|
@ -1,6 +1,159 @@
|
||||||
/* global CodeMirror */
|
/* global CodeMirror */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const NAMED_COLORS = new Map([
|
||||||
|
['transparent', 'rgba(0, 0, 0, 0)'],
|
||||||
|
// CSS4 named colors
|
||||||
|
['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'],
|
||||||
|
['darkgrey', '#a9a9a9'],
|
||||||
|
['darkgreen', '#006400'],
|
||||||
|
['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'],
|
||||||
|
['grey', '#808080'],
|
||||||
|
['green', '#008000'],
|
||||||
|
['greenyellow', '#adff2f'],
|
||||||
|
['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'],
|
||||||
|
['lightgrey', '#d3d3d3'],
|
||||||
|
['lightgreen', '#90ee90'],
|
||||||
|
['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'],
|
||||||
|
]);
|
||||||
|
|
||||||
(window.CodeMirror ? window.CodeMirror.prototype : window).colorpicker = function () {
|
(window.CodeMirror ? window.CodeMirror.prototype : window).colorpicker = function () {
|
||||||
const cm = this;
|
const cm = this;
|
||||||
const CSS_PREFIX = 'colorpicker-';
|
const CSS_PREFIX = 'colorpicker-';
|
||||||
|
@ -57,6 +210,8 @@
|
||||||
hide,
|
hide,
|
||||||
setColor,
|
setColor,
|
||||||
getColor,
|
getColor,
|
||||||
|
stringToColor,
|
||||||
|
colorToString,
|
||||||
options,
|
options,
|
||||||
};
|
};
|
||||||
return PUBLIC_API;
|
return PUBLIC_API;
|
||||||
|
@ -554,11 +709,16 @@
|
||||||
|
|
||||||
function onMouseUp(event) {
|
function onMouseUp(event) {
|
||||||
releaseMouse(event, ['saturation', 'hue', 'opacity']);
|
releaseMouse(event, ['saturation', 'hue', 'opacity']);
|
||||||
|
if (onMouseDown.outsideClick) {
|
||||||
|
if (!prevFocusedElement) hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMouseDown(event) {
|
function onMouseDown(event) {
|
||||||
if (event.button === 0 && !event.target.closest('.colorpicker-popup')) {
|
onMouseDown.outsideClick = !event.button && !event.target.closest('.colorpicker-popup');
|
||||||
hide();
|
if (onMouseDown.outsideClick) {
|
||||||
|
prevFocusedElement = null;
|
||||||
|
captureMouse(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,6 +767,10 @@
|
||||||
function onCloseRequest(event) {
|
function onCloseRequest(event) {
|
||||||
if (event.detail !== PUBLIC_API) {
|
if (event.detail !== PUBLIC_API) {
|
||||||
hide();
|
hide();
|
||||||
|
} else if (!prevFocusedElement) {
|
||||||
|
// we're between mousedown and mouseup and colorview wants to re-open us in this cm
|
||||||
|
// so we'll prevent onMouseUp from hiding us to avoid flicker
|
||||||
|
prevFocusedElement = cm.display.input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +853,7 @@
|
||||||
function unregisterEvents() {
|
function unregisterEvents() {
|
||||||
window.removeEventListener('keydown', onKeyDown, true);
|
window.removeEventListener('keydown', onKeyDown, true);
|
||||||
window.removeEventListener('mousedown', onMouseDown, true);
|
window.removeEventListener('mousedown', onMouseDown, true);
|
||||||
window.removeEventListener('close-colorpicker-popup', hide, true);
|
window.removeEventListener('close-colorpicker-popup', onCloseRequest, true);
|
||||||
$root.removeEventListener('mouseleave', snooze);
|
$root.removeEventListener('mouseleave', snooze);
|
||||||
$root.removeEventListener('mouseenter', stopSnoozing);
|
$root.removeEventListener('mouseenter', stopSnoozing);
|
||||||
$root.removeEventListener('input', setFromInputs);
|
$root.removeEventListener('input', setFromInputs);
|
||||||
|
@ -709,9 +873,13 @@
|
||||||
//endregion
|
//endregion
|
||||||
//region Color conversion utilities
|
//region Color conversion utilities
|
||||||
|
|
||||||
function colorToString({r, g, b, h, s, l, a}, type = currentFormat) {
|
function colorToString(color, type = currentFormat) {
|
||||||
a = alphaToString(a);
|
const a = alphaToString(color.a);
|
||||||
const hasA = Boolean(a);
|
const hasA = Boolean(a);
|
||||||
|
if (type === 'rgb' && color.type === 'hsl') {
|
||||||
|
color = HSVtoRGB(HSLtoHSV(color));
|
||||||
|
}
|
||||||
|
const {r, g, b, h, s, l} = color;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'hex': {
|
case 'hex': {
|
||||||
const rgbStr = (0x1000000 + (r << 16) + (g << 8) + (b | 0)).toString(16).slice(1);
|
const rgbStr = (0x1000000 + (r << 16) + (g << 8) + (b | 0)).toString(16).slice(1);
|
||||||
|
@ -721,8 +889,8 @@
|
||||||
}
|
}
|
||||||
case 'rgb':
|
case 'rgb':
|
||||||
return hasA ?
|
return hasA ?
|
||||||
`rgba(${r}, ${g}, ${b}, ${a})` :
|
`rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${a})` :
|
||||||
`rgb(${r}, ${g}, ${b})`;
|
`rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
|
||||||
case 'hsl':
|
case 'hsl':
|
||||||
return hasA ?
|
return hasA ?
|
||||||
`hsla(${h}, ${s}%, ${l}%, ${a})` :
|
`hsla(${h}, ${s}%, ${l}%, ${a})` :
|
||||||
|
@ -731,25 +899,47 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringToColor(str) {
|
function stringToColor(str) {
|
||||||
if (typeof str !== 'string') {
|
if (typeof str !== 'string') return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
if (str.startsWith('rgb')) {
|
if (!str) return;
|
||||||
const [r, g, b, a = 1] = str.replace(/rgba?\(|\)/g, '').split(',').map(parseFloat);
|
|
||||||
return {type: 'rgb', r, g, b, a};
|
if (str[0] !== '#' && !str.includes('(')) {
|
||||||
|
str = NAMED_COLORS.get(str);
|
||||||
|
if (!str) return;
|
||||||
}
|
}
|
||||||
if (str.startsWith('hsl')) {
|
|
||||||
const [h, s, l, a = 1] = str.replace(/hsla?\(|\)/g, '').split(',').map(parseFloat);
|
if (str[0] === '#') {
|
||||||
return {type: 'hsl', h, s, l, a};
|
|
||||||
}
|
|
||||||
if (str.startsWith('#')) {
|
|
||||||
str = str.slice(1);
|
str = str.slice(1);
|
||||||
const [r, g, b, a = 255] = str.length <= 4 ?
|
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 + c, 16)) :
|
||||||
str.match(/(..)/g).map(c => parseInt(c, 16));
|
str.match(/(..)/g).map(c => parseInt(c, 16));
|
||||||
return {type: 'hex', r, g, b, a: a === 255 ? undefined : a / 255};
|
return {type: 'hex', r, g, b, a: a === 255 ? undefined : a / 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [, type, value] = str.match(/^(rgb|hsl)a?\((.*?)\)|$/i);
|
||||||
|
if (!type) return;
|
||||||
|
|
||||||
|
const comma = value.includes(',') && !value.includes('/');
|
||||||
|
const num = value.split(comma ? /\s*,\s*/ : /\s+(?!\/)|\s*\/\s*/);
|
||||||
|
if (num.length < 3 || num.length > 4) return;
|
||||||
|
|
||||||
|
let a = !num[3] ? 1 : parseFloat(num[3]) / (num[3].endsWith('%') ? 100 : 1);
|
||||||
|
if (isNaN(a)) a = 1;
|
||||||
|
|
||||||
|
const first = num[0];
|
||||||
|
if (/rgb/i.test(type)) {
|
||||||
|
const k = first.endsWith('%') ? 2.55 : 1;
|
||||||
|
const [r, g, b] = num.map(s => parseFloat(s) * k);
|
||||||
|
return {type: 'rgb', r, g, b, a};
|
||||||
|
} else {
|
||||||
|
let h = parseFloat(first);
|
||||||
|
if (first.endsWith('grad')) h *= 360 / 400;
|
||||||
|
else if (first.endsWith('rad')) h *= 180 / Math.PI;
|
||||||
|
else if (first.endsWith('turn')) h *= 360;
|
||||||
|
const s = parseFloat(num[1]);
|
||||||
|
const l = parseFloat(num[2]);
|
||||||
|
return {type: 'hsl', h, s, l, a};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function constrainHue(h) {
|
function constrainHue(h) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user