From 7c0d8f0841231d562e80af3f7b688d5c7297bf7d Mon Sep 17 00:00:00 2001 From: tophf Date: Fri, 24 Nov 2017 13:16:59 +0300 Subject: [PATCH] prevent inline overlays from breaking color swatches --- edit/colorpicker-helper.js | 31 ++++----- edit/match-highlighter-helper.js | 67 ++++++++++++------- vendor-overwrites/colorpicker/colorpicker.css | 3 + vendor-overwrites/colorpicker/colorview.js | 1 - 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/edit/colorpicker-helper.js b/edit/colorpicker-helper.js index 30d9fbef..7d7cd651 100644 --- a/edit/colorpicker-helper.js +++ b/edit/colorpicker-helper.js @@ -1,7 +1,8 @@ /* global CodeMirror loadScript editors showHelp */ 'use strict'; -window.initColorpicker = () => { +// eslint-disable-next-line no-var +var initColorpicker = () => { initOverlayHooks(); onDOMready().then(() => { $('#colorpicker-settings').onclick = configureColorpicker; @@ -109,41 +110,37 @@ window.initColorpicker = () => { 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 === (this.state.matchHighlighter || {}).overlay) { - if (overlay.token !== tokenHook) { - overlay.stylusColorpickerHelper = { - token: overlay.token, - }; - overlay.token = tokenHook; - } + 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.stylusColorpickerHelper.token.call(this, stream); - if (style === 'matchhighlight') { - return tokenHookForHighlighter.call(this, stream, style); - } else { + const style = this.colopickerHelper.token.apply(this, arguments); + if (!style) { return style; } - } - - function tokenHookForHighlighter(stream, 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) { + if (prev <= start && start <= end) { const base = baseTokens[i + 1]; if (base && base.includes('colorview')) { - return style + COLORVIEW_DISABLED_SUFFIX; + return style + + (start > prev ? COLORVIEW_DISABLED_SUFFIX : '') + + (pos < end ? COLORVIEW_NEXT_DISABLED_SUFFIX : ''); } } else if (end > pos) { break; diff --git a/edit/match-highlighter-helper.js b/edit/match-highlighter-helper.js index 2d3ed913..20576c19 100644 --- a/edit/match-highlighter-helper.js +++ b/edit/match-highlighter-helper.js @@ -28,7 +28,10 @@ function addOverlayForHighlighter(overlay) { const state = this.state.matchHighlighter || {}; - const helper = state.stylusMHLHelper || {}; + const helper = state.highlightHelper = state.highlightHelper || {}; + + clearTimeout(helper.hookTimer); + if (helper.matchesonscroll) { // restore the original addon's unwanted removeOverlay effects // (in case the token under cursor hasn't changed) @@ -38,22 +41,22 @@ helper.overlay = null; return true; } + if (overlay.token !== tokenHook) { - overlay.stylusMHLHelper = { + overlay.highlightHelper = { token: overlay.token, occurrences: 0, }; overlay.token = tokenHook; } - clearTimeout(helper.hookTimer); } function tokenHook(stream) { - const style = this.stylusMHLHelper.token.call(this, stream); + const style = this.highlightHelper.token.call(this, stream); if (style !== 'matchhighlight') { return style; } - const num = ++this.stylusMHLHelper.occurrences; + const num = ++this.highlightHelper.occurrences; if (num === 1) { stream.lineOracle.doc.cm.display.wrapper.classList.remove(HL_APPROVED); } else if (num === 2) { @@ -64,38 +67,54 @@ function removeOverlayForHighlighter() { const state = this.state.matchHighlighter || {}; - const {query} = state.matchesonscroll || {}; + const {query} = state.highlightHelper || state.matchesonscroll || {}; if (!query) { return; } - const {line, ch} = this.getCursor(); const rx = query instanceof RegExp && query; - const queryLen = rx ? rx.source.length - 4 : query.length; - const start = Math.max(0, ch - queryLen + 1); - const end = ch + queryLen; - const area = this.getLine(line).substring(start, end); - const startInArea = rx ? (area.match(rx) || {}).index : - (area.indexOf(query) + 1 || NaN) - 1; - if (start + startInArea <= ch) { - // same token on cursor => prevent the highlighter from rerunning - state.stylusMHLHelper = { - overlay: state.overlay, - matchesonscroll: state.matchesonscroll, - hookTimer: setTimeout(removeOverlayIfExpired, 0, this, state), - }; - state.matchesonscroll = null; - return true; + const sel = this.getSelection(); + if (sel && (rx && !rx.test(sel) || sel.toLowerCase() !== query)) { + return; } + if (!sel) { + const {line, ch} = this.getCursor(); + const queryLen = rx ? rx.source.length - 4 : query.length; + const start = Math.max(0, ch - queryLen + 1); + const end = ch + queryLen; + const area = this.getLine(line).substring(start, end); + const startInArea = rx ? (area.match(rx) || {}).index : + (area.indexOf(query) + 1 || NaN) - 1; + if (start + startInArea > ch) { + return; + } + } + // same token on cursor => prevent the highlighter from rerunning + state.highlightHelper = { + overlay: state.overlay, + matchesonscroll: state.matchesonscroll, + showMatchesOnScrollbar: this.showMatchesOnScrollbar, + hookTimer: setTimeout(removeOverlayIfExpired, 0, this, state), + }; + state.matchesonscroll = null; + this.showMatchesOnScrollbar = scrollbarForHighlighter; + return true; } function removeOverlayIfExpired(self, state) { - const {overlay, matchesonscroll} = state.stylusMHLHelper || {}; + const {overlay, matchesonscroll} = state.highlightHelper || {}; if (overlay) { originalRemoveOverlay.call(self, overlay); } if (matchesonscroll) { matchesonscroll.clear(); } - state.stylusMHLHelper = null; + self.showMatchesOnScrollbar = state.showMatchesOnScrollbar; + state.highlightHelper = null; + } + + function scrollbarForHighlighter(query) { + const helper = this.state.matchHighlighter.highlightHelper; + this.showMatchesOnScrollbar = helper.showMatchesOnScrollbar; + helper.query = query; } })(); diff --git a/vendor-overwrites/colorpicker/colorpicker.css b/vendor-overwrites/colorpicker/colorpicker.css index 4dc63ead..d5322ff9 100644 --- a/vendor-overwrites/colorpicker/colorpicker.css +++ b/vendor-overwrites/colorpicker/colorpicker.css @@ -16,6 +16,9 @@ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC"); background-repeat: repeat; } +.cm-colorview-next-disabled + .cm-colorview::before { + content: none; +} .codemirror-colorview-background { position: absolute; diff --git a/vendor-overwrites/colorpicker/colorview.js b/vendor-overwrites/colorpicker/colorview.js index e03c522e..f8e069bd 100644 --- a/vendor-overwrites/colorpicker/colorview.js +++ b/vendor-overwrites/colorpicker/colorview.js @@ -177,7 +177,6 @@ if (el.colorpickerData && el.colorpickerData.color === data.color) { continue; } - el.dataset.colorpicker = ''; el.colorpickerData = Object.assign({line, ch: start}, data); let bg = el.firstElementChild; if (!bg) {