move getRealColors to colorpicker and reuse it
This commit is contained in:
parent
97e486e139
commit
fd047f8323
|
@ -1,4 +1,4 @@
|
|||
/* global regExpTester debounce messageBox CodeMirror template */
|
||||
/* global regExpTester debounce messageBox CodeMirror template colorMimicry */
|
||||
'use strict';
|
||||
|
||||
function createAppliesToLineWidget(cm) {
|
||||
|
@ -214,13 +214,13 @@ function createAppliesToLineWidget(cm) {
|
|||
const MIN_LUMA = .05;
|
||||
const MIN_LUMA_DIFF = .4;
|
||||
const color = {
|
||||
wrapper: getRealColors(cm.display.wrapper),
|
||||
gutter: getRealColors(cm.display.gutters, {
|
||||
wrapper: colorMimicry.get(cm.display.wrapper),
|
||||
gutter: colorMimicry.get(cm.display.gutters, {
|
||||
bg: 'backgroundColor',
|
||||
border: 'borderRightColor',
|
||||
}),
|
||||
line: getRealColors('.CodeMirror-linenumber'),
|
||||
comment: getRealColors('span.cm-comment'),
|
||||
line: colorMimicry.get('.CodeMirror-linenumber', null, cm.display.lineDiv),
|
||||
comment: colorMimicry.get('span.cm-comment', null, cm.display.lineDiv),
|
||||
};
|
||||
const hasBorder =
|
||||
color.gutter.style.borderRightWidth !== '0px' &&
|
||||
|
@ -258,65 +258,11 @@ function createAppliesToLineWidget(cm) {
|
|||
fill: ${fore};
|
||||
transition: none;
|
||||
}
|
||||
.applies-to button {
|
||||
color: ${fore};
|
||||
}
|
||||
`;
|
||||
document.documentElement.appendChild(actualStyle);
|
||||
|
||||
function getRealColors(el, targets = {}) {
|
||||
targets.fore = 'color';
|
||||
const colors = {};
|
||||
const done = {};
|
||||
let numDone = 0;
|
||||
let numTotal = 0;
|
||||
for (const k in targets) {
|
||||
colors[k] = {r: 255, g: 255, b: 255, a: 1};
|
||||
numTotal++;
|
||||
}
|
||||
const isDummy = typeof el === 'string';
|
||||
el = isDummy ? cm.display.lineDiv.appendChild($create(el, {style: 'display: none'})) : el;
|
||||
for (let current = el; current; current = current && current.parentElement) {
|
||||
const style = getComputedStyle(current);
|
||||
for (const k in targets) {
|
||||
if (!done[k]) {
|
||||
done[k] = blend(colors[k], style[targets[k]]);
|
||||
numDone += done[k] ? 1 : 0;
|
||||
if (numDone === numTotal) {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
colors.style = colors.style || style;
|
||||
}
|
||||
if (isDummy) {
|
||||
el.remove();
|
||||
}
|
||||
for (const k in targets) {
|
||||
const {r, g, b, a} = colors[k];
|
||||
colors[k] = `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||
// https://www.w3.org/TR/AERT#color-contrast
|
||||
colors[k + 'Luma'] = (r * .299 + g * .587 + b * .114) / 256;
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
function blend(base, color) {
|
||||
const [r, g, b, a = 255] = (color.match(/\d+/g) || []).map(Number);
|
||||
if (a === 255) {
|
||||
base.r = r;
|
||||
base.g = g;
|
||||
base.b = b;
|
||||
base.a = 1;
|
||||
} else if (a) {
|
||||
const mixedA = 1 - (1 - a / 255) * (1 - base.a);
|
||||
const q1 = a / 255 / mixedA;
|
||||
const q2 = base.a * (1 - mixedA) / mixedA;
|
||||
base.r = Math.round(r * q1 + base.r * q2);
|
||||
base.g = Math.round(g * q1 + base.g * q2);
|
||||
base.b = Math.round(b * q1 + base.b * q2);
|
||||
base.a = mixedA;
|
||||
}
|
||||
return Math.abs(base.a - 1) < 1e-3;
|
||||
}
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
|
|
|
@ -932,30 +932,11 @@
|
|||
}
|
||||
|
||||
function guessTheme() {
|
||||
const realColor = {r: 255, g: 255, b: 255, a: 1};
|
||||
const start = options.guessBrightness ||
|
||||
((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;
|
||||
if (Math.abs(realColor.a - 1) < 1e-3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 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';
|
||||
const el = options.guessBrightness ||
|
||||
((cm.display.renderedView || [])[0] || {}).text ||
|
||||
cm.display.lineDiv;
|
||||
const bgLuma = window.colorMimicry.get(el, {bg: 'backgroundColor'}).bgLuma;
|
||||
return bgLuma < .5 ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
function constrain(min, max, value) {
|
||||
|
@ -979,3 +960,92 @@
|
|||
|
||||
//endregion
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// eslint-disable-next-line no-var
|
||||
var colorMimicry = (() => {
|
||||
const styleCache = new Map();
|
||||
return {get};
|
||||
|
||||
// Calculates real color of an element:
|
||||
// colorMimicry.get(cm.display.gutters, {bg: 'backgroundColor'})
|
||||
// colorMimicry.get('input.foo.bar', null, $('some.parent.to.host.the.dummy'))
|
||||
function get(el, targets, dummyContainer = document.body) {
|
||||
targets = targets || {};
|
||||
targets.fore = 'color';
|
||||
const colors = {};
|
||||
const done = {};
|
||||
let numDone = 0;
|
||||
let numTotal = 0;
|
||||
const rootStyle = getStyle(document.documentElement);
|
||||
for (const k in targets) {
|
||||
const base = {r: 255, g: 255, b: 255, a: 1};
|
||||
blend(base, rootStyle[targets[k]]);
|
||||
colors[k] = base;
|
||||
numTotal++;
|
||||
}
|
||||
const isDummy = typeof el === 'string';
|
||||
if (isDummy) {
|
||||
el = dummyContainer.appendChild($create(el, {style: 'display: none'}));
|
||||
}
|
||||
for (let current = el; current; current = current && current.parentElement) {
|
||||
const style = getStyle(current);
|
||||
for (const k in targets) {
|
||||
if (!done[k]) {
|
||||
done[k] = blend(colors[k], style[targets[k]]);
|
||||
numDone += done[k] ? 1 : 0;
|
||||
if (numDone === numTotal) {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
colors.style = colors.style || style;
|
||||
}
|
||||
if (isDummy) {
|
||||
el.remove();
|
||||
}
|
||||
for (const k in targets) {
|
||||
const {r, g, b, a} = colors[k];
|
||||
colors[k] = `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||
// https://www.w3.org/TR/AERT#color-contrast
|
||||
colors[k + 'Luma'] = (r * .299 + g * .587 + b * .114) / 256;
|
||||
}
|
||||
debounce(clearCache);
|
||||
return colors;
|
||||
}
|
||||
|
||||
function blend(base, color) {
|
||||
const [r, g, b, a = 255] = (color.match(/\d+/g) || []).map(Number);
|
||||
if (a === 255) {
|
||||
base.r = r;
|
||||
base.g = g;
|
||||
base.b = b;
|
||||
base.a = 1;
|
||||
} else if (a) {
|
||||
const mixedA = 1 - (1 - a / 255) * (1 - base.a);
|
||||
const q1 = a / 255 / mixedA;
|
||||
const q2 = base.a * (1 - mixedA) / mixedA;
|
||||
base.r = Math.round(r * q1 + base.r * q2);
|
||||
base.g = Math.round(g * q1 + base.g * q2);
|
||||
base.b = Math.round(b * q1 + base.b * q2);
|
||||
base.a = mixedA;
|
||||
}
|
||||
return Math.abs(base.a - 1) < 1e-3;
|
||||
}
|
||||
|
||||
// speed-up for sequential invocations within the same event loop cycle
|
||||
// (we're assuming the invoker doesn't force CSSOM to refresh between the calls)
|
||||
function getStyle(el) {
|
||||
let style = styleCache.get(el);
|
||||
if (!style) {
|
||||
style = getComputedStyle(el);
|
||||
styleCache.set(el, style);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
styleCache.clear();
|
||||
}
|
||||
})();
|
||||
|
|
Loading…
Reference in New Issue
Block a user