add colorpicker hotkey config icon [default: none]
* uses the last submitted color by default * doesn't insert the default color until a change or the Enter key * fix a few bugs in colorpicker introduced in the rewrite
This commit is contained in:
parent
352846c8b4
commit
b99391887d
|
@ -193,6 +193,11 @@
|
|||
<div class="option">
|
||||
<input id="editor.colorpicker" type="checkbox">
|
||||
<label for="editor.colorpicker" i18n-text="cm_colorpicker"></label>
|
||||
<span class="svg-inline-wrapper" i18n-title="shortcutsNote">
|
||||
<svg id="colorpicker-settings" class="svg-icon settings">
|
||||
<use xlink:href="#svg-icon-settings"/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="option aligned">
|
||||
<label id="tabSize-label" for="editor.tabSize" i18n-text="cm_tabSize"></label>
|
||||
|
|
96
edit/edit.js
96
edit/edit.js
|
@ -1457,6 +1457,7 @@ function initHooks() {
|
|||
$('#sections-help').addEventListener('click', showSectionHelp, false);
|
||||
$('#keyMap-help').addEventListener('click', showKeyMapHelp, false);
|
||||
$('#cancel-button').addEventListener('click', goBackToManage);
|
||||
$('#colorpicker-settings').addEventListener('click', configureColorpicker);
|
||||
|
||||
setupOptionsExpand();
|
||||
initLint();
|
||||
|
@ -1872,8 +1873,8 @@ function showHelp(title, body) {
|
|||
// avoid chaining on multiple showHelp() calls
|
||||
$('.dismiss', div).onclick = closeHelp;
|
||||
}
|
||||
|
||||
div.style.display = 'block';
|
||||
// reset any inline styles
|
||||
div.style = 'display: block';
|
||||
return div;
|
||||
|
||||
function closeHelp(e) {
|
||||
|
@ -2078,6 +2079,7 @@ function onColorpickerReady() {
|
|||
'/vendor-overwrites/colorpicker/colorpicker.js',
|
||||
'/vendor-overwrites/colorpicker/colorview.js',
|
||||
];
|
||||
prefs.subscribe(['editor.colorpicker.hotkey'], registerHotkey);
|
||||
prefs.subscribe(['editor.colorpicker'], colorpickerOnDemand);
|
||||
return prefs.get('editor.colorpicker') && colorpickerOnDemand(null, true);
|
||||
|
||||
|
@ -2087,21 +2089,83 @@ function onColorpickerReady() {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
const defaults = CodeMirror.defaults;
|
||||
const keyName = prefs.get('editor.colorpicker.hotkey');
|
||||
delete defaults.extraKeys[keyName];
|
||||
defaults.colorpicker = enabled;
|
||||
if (enabled) {
|
||||
if (keyName) {
|
||||
CodeMirror.commands.colorpicker = invokeColorpicker;
|
||||
defaults.extraKeys[keyName] = 'colorpicker';
|
||||
}
|
||||
defaults.colorpicker = {
|
||||
forceUpdate: editors.length > 0,
|
||||
tooltip: t('colorpickerTooltip'),
|
||||
popupOptions: {
|
||||
tooltipForSwitcher: t('colorpickerSwitchFormatTooltip'),
|
||||
hexUppercase: prefs.get('editor.colorpicker.hexUppercase'),
|
||||
hideDelay: 5000,
|
||||
embedderCallback: state => {
|
||||
['hexUppercase', 'color']
|
||||
.filter(name => state[name] !== prefs.get('editor.colorpicker.' + name))
|
||||
.forEach(name => prefs.set('editor.colorpicker.' + name, state[name]));
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
// on page load runs before CodeMirror.setOption is defined
|
||||
editors.forEach(cm => cm.setOption('colorpicker', CodeMirror.defaults.colorpicker));
|
||||
editors.forEach(cm => cm.setOption('colorpicker', defaults.colorpicker));
|
||||
}
|
||||
|
||||
function registerHotkey(id, hotkey) {
|
||||
const extraKeys = CodeMirror.defaults.extraKeys;
|
||||
for (const key in extraKeys) {
|
||||
if (extraKeys[key] === 'colorpicker') {
|
||||
delete extraKeys[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hotkey) {
|
||||
extraKeys[hotkey] = 'colorpicker';
|
||||
}
|
||||
}
|
||||
|
||||
function invokeColorpicker(cm) {
|
||||
cm.state.colorpicker.openPopup(prefs.get('editor.colorpicker.color'));
|
||||
}
|
||||
}
|
||||
|
||||
function configureColorpicker() {
|
||||
const input = $element({
|
||||
tag: 'input',
|
||||
type: 'search',
|
||||
spellcheck: false,
|
||||
value: prefs.get('editor.colorpicker.hotkey'),
|
||||
onkeydown(event) {
|
||||
const key = CodeMirror.keyName(event);
|
||||
// ignore: [Shift?] characters, modifiers-only, [Shift?] Esc, Enter, [Shift?] Tab
|
||||
if (/^(Enter|(Shift-)?(Esc|Tab|[!-~])|(Shift-?|Ctrl-?|Alt-?|Cmd-?)*)$/.test(key)) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
prefs.set('editor.colorpicker.hotkey', key);
|
||||
this.value = key;
|
||||
},
|
||||
oninput() {
|
||||
// fired on pressing "x" to clear the field
|
||||
prefs.set('editor.colorpicker.hotkey', '');
|
||||
},
|
||||
onpaste(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
const popup = showHelp(t('helpKeyMapHotkey'), input);
|
||||
if (this instanceof Element) {
|
||||
const bounds = this.getBoundingClientRect();
|
||||
popup.style.left = bounds.right + 10 + 'px';
|
||||
popup.style.top = bounds.top - popup.clientHeight / 2 + 'px';
|
||||
popup.style.right = 'auto';
|
||||
}
|
||||
input.focus();
|
||||
}
|
||||
|
|
|
@ -60,6 +60,10 @@ var prefs = new function Prefs() {
|
|||
'editor.colorpicker': true,
|
||||
// #DEAD or #beef
|
||||
'editor.colorpicker.hexUppercase': false,
|
||||
// default hotkey
|
||||
'editor.colorpicker.hotkey': '',
|
||||
// last color
|
||||
'editor.colorpicker.color': '',
|
||||
|
||||
'iconset': 0, // 0 = dark-themed icon
|
||||
// 1 = light-themed icon
|
||||
|
|
|
@ -203,7 +203,7 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
options = PUBLIC_API.options = opt;
|
||||
prevFocusedElement = document.activeElement;
|
||||
userActivity = 0;
|
||||
lastOutputColor = opt.color;
|
||||
lastOutputColor = opt.color || '';
|
||||
$formatChangeButton.title = opt.tooltipForSwitcher || '';
|
||||
opt.hideDelay = Math.max(0, opt.hideDelay) || 2000;
|
||||
|
||||
|
@ -337,7 +337,7 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
}
|
||||
|
||||
function validateInput(el) {
|
||||
const isAlpha = el.type === 'text';
|
||||
const isAlpha = el === $inputs[currentFormat][3];
|
||||
let isValid = (isAlpha || el.value.trim()) && el.checkValidity();
|
||||
if (!isAlpha && !isValid && currentFormat === 'rgb') {
|
||||
isValid = parseAs(el, parseInt);
|
||||
|
@ -352,8 +352,9 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
//endregion
|
||||
//region State-to-DOM
|
||||
|
||||
function setFromColor(color = '#FF0000') {
|
||||
function setFromColor(color) {
|
||||
color = typeof color === 'string' ? stringToColor(color) : color;
|
||||
color = color || stringToColor('#f00');
|
||||
const newHSV = color.type === 'hsl' ? HSLtoHSV(color) : RGBtoHSV(color);
|
||||
if (Object.keys(newHSV).every(k => Math.abs(newHSV[k] - HSV[k]) < 1e-3)) {
|
||||
return;
|
||||
|
@ -440,7 +441,7 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
}
|
||||
}
|
||||
|
||||
function onSaturationMouseUp() {
|
||||
function onSaturationMouseUp(event) {
|
||||
if (event.button === 0) {
|
||||
dragging.saturation = false;
|
||||
releaseMouse();
|
||||
|
@ -454,7 +455,7 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
}
|
||||
}
|
||||
|
||||
function onOpacityKnobMouseDown() {
|
||||
function onOpacityKnobMouseDown(event) {
|
||||
if (event.button === 0) {
|
||||
dragging.opacity = true;
|
||||
captureMouse();
|
||||
|
@ -517,6 +518,7 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
if (!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
||||
switch (e.which) {
|
||||
case 13:
|
||||
setFromInputs();
|
||||
colorpickerCallback();
|
||||
// fallthrough to 27
|
||||
case 27:
|
||||
|
@ -647,7 +649,6 @@ CodeMirror.defineExtension('colorpicker', function () {
|
|||
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}) {
|
||||
|
|
|
@ -400,10 +400,11 @@
|
|||
openPopup(color) {
|
||||
let {line, ch} = this.cm.getCursor();
|
||||
const lineText = this.cm.getLine(line);
|
||||
ch -= (lineText.lastIndexOf('!important', ch) >= ch - '!important'.length) ? '!important'.length : 0;
|
||||
const atImportant = lineText.lastIndexOf('!important', ch);
|
||||
ch -= (atImportant >= Math.max(0, ch - '!important'.length)) ? '!important'.length : 0;
|
||||
const lineCache = this.cm.state.colorpicker.cache.get(lineText);
|
||||
const data = {line, ch, color, isShortCut: true};
|
||||
for (const [start, {color, colorValue}] of lineCache && lineCache.entries() || []) {
|
||||
const data = {line, ch, colorValue: color, isShortCut: true};
|
||||
for (const [start, {color, colorValue = color}] of lineCache && lineCache.entries() || []) {
|
||||
if (start <= ch && ch <= start + color.length) {
|
||||
Object.assign(data, {ch: start, color, colorValue});
|
||||
break;
|
||||
|
@ -419,7 +420,7 @@
|
|||
top,
|
||||
left,
|
||||
cm: this.cm,
|
||||
color: data.colorValue || data.color || '#fff',
|
||||
color: data.colorValue || data.color,
|
||||
prevColor: data.color || '',
|
||||
isShortCut: false,
|
||||
callback: ColorMarker.popupOnChange,
|
||||
|
@ -437,8 +438,8 @@
|
|||
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');
|
||||
this.prevColor = newColor;
|
||||
}
|
||||
if (typeof embedderCallback === 'function') {
|
||||
embedderCallback(this);
|
||||
|
|
Loading…
Reference in New Issue
Block a user