From fd047f8323bff247a9a103398f48b5c9ace6d4ff Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 17 Dec 2017 22:07:37 +0300 Subject: [PATCH] move getRealColors to colorpicker and reuse it --- edit/applies-to-line-widget.js | 70 ++--------- vendor-overwrites/colorpicker/colorpicker.js | 118 +++++++++++++++---- 2 files changed, 102 insertions(+), 86 deletions(-) diff --git a/edit/applies-to-line-widget.js b/edit/applies-to-line-widget.js index 1003554e..df83dcfa 100644 --- a/edit/applies-to-line-widget.js +++ b/edit/applies-to-line-widget.js @@ -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() { diff --git a/vendor-overwrites/colorpicker/colorpicker.js b/vendor-overwrites/colorpicker/colorpicker.js index cb96cdce..b5c972cc 100644 --- a/vendor-overwrites/colorpicker/colorpicker.js +++ b/vendor-overwrites/colorpicker/colorpicker.js @@ -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(); + } +})();