From 586ad8aad755aa520a87c4f6e72af0ff84861f35 Mon Sep 17 00:00:00 2001 From: narcolepticinsomniac Date: Fri, 12 Oct 2018 16:24:42 -0400 Subject: [PATCH] edit --- edit/beautify.js | 5 +- edit/codemirror-default.css | 63 ++++++++++------- edit/codemirror-editing-hooks.js | 9 +-- edit/edit.css | 113 +++++++++++++++++-------------- edit/edit.js | 46 +++++++++---- edit/global-search.css | 42 ++++++++---- edit/global-search.js | 10 ++- 7 files changed, 179 insertions(+), 109 deletions(-) diff --git a/edit/beautify.js b/edit/beautify.js index 50ef5553..830b7e71 100644 --- a/edit/beautify.js +++ b/edit/beautify.js @@ -40,8 +40,7 @@ function beautify(event) { $create('.buttons', [ $create('button', { attributes: {role: 'close'}, - // showHelp.close will be defined after showHelp() is invoked - onclick: () => showHelp.close(), + onclick: showHelp.close, }, t('confirmClose')), $create('button', { attributes: {role: 'undo'}, @@ -63,7 +62,7 @@ function beautify(event) { ]), ])); - $('#help-popup').className = 'wide'; + $('#help-popup').className = 'main-bg wide'; scope.forEach(cm => { setTimeout(() => { diff --git a/edit/codemirror-default.css b/edit/codemirror-default.css index 83085a6d..eaee8378 100644 --- a/edit/codemirror-default.css +++ b/edit/codemirror-default.css @@ -1,12 +1,48 @@ +:root { + --applies-to-pseudo: hsla(214, 100%, 90%, 0.15); +} + +/************ CM default ************/ +.CodeMirror.cm-s-default { + background: var(--gray-lightness-93); +} + +.CodeMirror { + outline-style: solid; + outline-color: transparent; + outline-width: 1px; + outline-offset: -1px; + transition: outline-color .25s; +} + +.CodeMirror-focused { + outline-color: var(--focus-outline); +} + +.CodeMirror.cm-s-default .CodeMirror-gutters { + background-color: var(--truegray-alpha-1); + border-right: 1px solid var(--truegray-alpha-2); +} + +.CodeMirror.cm-s-default .CodeMirror-activeline-background { + background: var(--cm-activeline-bg); +} + +.CodeMirror-hints.default { + background-color: var(--main-bg); +} + .CodeMirror-hints { z-index: 999; } + +/* match Windows select hover, so no variables */ .CodeMirror-hint:hover { - color: white; + color: #fff; background: #08f; } .CodeMirror { - border: solid #CCC 1px; + border: 1px solid var(--gray-lightness-76); } .CodeMirror-lint-mark-warning { background: none; @@ -14,17 +50,6 @@ .CodeMirror-dialog { -webkit-animation: highlight 3s cubic-bezier(.18, .02, 0, .94); } -.CodeMirror-focused { - outline: -webkit-focus-ring-color auto 5px; - outline-offset: -2px; -} -@supports (-moz-appearance:none) { - /* restrict to FF */ - .CodeMirror-focused { - outline: #7dadd9 auto 1px; - outline-offset: -1px; - } -} .CodeMirror-search-field { width: 10em; } @@ -32,22 +57,14 @@ width: 5em; } .CodeMirror-search-hint { - color: #888; + color: var(--truegray); } .cm-uso-variable { font-weight: bold; } -.cm-searching.cm-matchhighlight { - /* tokens found by manual search should not animate by cm-matchhighlight */ - animation-name: search-and-match-highlighter !important; -} -@keyframes search-and-match-highlighter { - from { background-color: rgba(255, 255, 0, .4); } /* search color */ - to { background-color: rgba(100, 255, 100, .4); } /* sarch + highlight */ -} .CodeMirror-activeline .applies-to:before { - background-color: hsla(214, 100%, 90%, 0.15); + background-color: var(--applies-to-pseudo); content: ""; top: 1em; left: 0; diff --git a/edit/codemirror-editing-hooks.js b/edit/codemirror-editing-hooks.js index 01cd79c4..308f99e7 100644 --- a/edit/codemirror-editing-hooks.js +++ b/edit/codemirror-editing-hooks.js @@ -1,5 +1,5 @@ /* -global CodeMirror loadScript +global CodeMirror linterConfig loadScript global editors editor styleId ownTabId global save toggleStyle setupAutocomplete makeSectionVisible getSectionForChild global getSectionsHashes @@ -8,6 +8,9 @@ global messageBox 'use strict'; onDOMscriptReady('/codemirror.js').then(() => { + + CodeMirror.defaults.lint = linterConfig.getForCodeMirror(); + const COMMANDS = { save, toggleStyle, @@ -40,9 +43,6 @@ onDOMscriptReady('/codemirror.js').then(() => { }); CodeMirror.defineInitHook(cm => { - if (!cm.display.wrapper.closest('#sections')) { - return; - } if (prefs.get('editor.livePreview') && styleId) { cm.on('changes', updatePreview); } @@ -299,6 +299,7 @@ onDOMscriptReady('/codemirror.js').then(() => { break; default: value = null; + document.body.removeAttribute('data-match-highlight'); } option = 'highlightSelectionMatches'; break; diff --git a/edit/edit.css b/edit/edit.css index 5481bb08..9c84596d 100644 --- a/edit/edit.css +++ b/edit/edit.css @@ -1,8 +1,17 @@ :root { --header-narrow-min-height: 12em; + --match-highlighter-alpha-15: hsla(193, 99%, 38%, .15); + --regexp-report-mark-alpha-5: hsla(60, 100%, 50%, .5); + --section-label-highlight: hsl(60, 100%, 80%); + --cm-activeline-bg: hsl(180, 22%, 88%); + --darkgreen: hsl(120, 100%, 20%); + --global-progress: hsla(180, 66%, 36%, .25); + --beautify-select-gradient-left: hsla(0, 0%, 0%, .07); + --beautify-select-gradient-right: hsla(0, 0%, 0%, .05); } body { + display: flex; margin: 0; font: 12px arial,sans-serif; } @@ -13,8 +22,8 @@ body { top: 0; left: 0; right: 0; - background-color: hsla(180, 66%, 36%, .25); - border-left: 0 solid darkcyan; + background-color: var(--global-progress); + border-left: 0 solid var(--darkcyan); z-index: 2147483647; opacity: 0; transition: opacity 2s; @@ -27,7 +36,7 @@ body { display: none !important; } -/************ checkbox & select************/ +/************ checkbox & select ************/ .options-column > div[class="option"] { margin-bottom: 4px; } @@ -49,9 +58,9 @@ label { position: fixed; top: 0; padding: 1rem; - border-right: 1px dashed #AAA; - -webkit-box-shadow: 0 0 3rem -1.2rem black; - box-shadow: 0 0 3rem -1.2rem black; + border-right: 1px dashed var(--gray-lightness-66); + -webkit-box-shadow: 0 0 3rem -1.2rem var(--black); + box-shadow: 0 0 3rem -1.2rem var(--black); box-sizing: border-box; z-index: 10; display: flex; @@ -61,6 +70,7 @@ label { margin-top: 0; } #sections { + flex-grow: 1; padding-left: 280px; } #sections h2 { @@ -122,7 +132,7 @@ label { #preview-errors { background-color: red; - color: white; + color: var(--white); padding: 0 6px; border-radius: 9px; margin-left: -.5em; @@ -164,19 +174,19 @@ label { .svg-icon:hover, .svg-icon.info, .svg-icon.settings { - fill: #666; + fill: var(--gray-lightness-40); } .svg-icon, .svg-icon.info:hover, .svg-icon.settings:hover { - fill: #000; + fill: var(--black); } #options span .svg-icon { margin-top: -3px; /* inline info and config icons */ } input:invalid { - background-color: rgba(255, 0, 0, 0.1); - color: darkred; + background-color: var(--truegray-alpha-05); + color: var(--darkred); } #enabled { margin-left: 0; @@ -198,7 +208,7 @@ input:invalid { } #header summary:hover h2 { - border-color: #bbb; + border-color: var(--truegray-alpha-7); } #header summary svg { @@ -272,7 +282,7 @@ input:invalid { padding: 0 1rem .3rem; } #sections > *:not(:first-child) { - border-top: 2px solid hsl(0, 0%, 80%); + border-top: 2px solid var(--truegray-alpha-3); } .add-section:after { content: attr(short-text); @@ -348,18 +358,23 @@ input:invalid { .resize-grip-enabled .CodeMirror-scrollbar-filler { bottom: 7px; /* make space for resize-grip */ } -body[data-match-highlight="token"] .cm-matchhighlight-approved .cm-matchhighlight, -body[data-match-highlight="token"] .CodeMirror-selection-highlight-scrollbar { +.CodeMirror-vscrollbar, +.CodeMirror-hscrollbar { + outline: 0; +} +body[data-match-highlight="token"]:not(.find-open) .cm-matchhighlight-approved .cm-matchhighlight, +body[data-match-highlight="token"]:not(.find-open) .cm-matchhighlight-approved .CodeMirror-selection-highlight-scrollbar { animation: fadein-match-highlighter 1s cubic-bezier(.97,.01,.42,.98); animation-fill-mode: both; } -body[data-match-highlight="selection"] .cm-matchhighlight-approved .cm-matchhighlight, -body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar { - background-color: rgba(1, 151, 193, 0.1); +body[data-match-highlight="selection"]:not(.find-open) .cm-matchhighlight, +body[data-match-highlight="selection"]:not(.find-open) .CodeMirror-selection-highlight-scrollbar { + background-color: var(--match-highlighter-alpha-15); } + @-webkit-keyframes highlight { from { - background-color: #ff9; + background-color: var(--section-label-highlight); } to { background-color: inherit; @@ -375,7 +390,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar } @keyframes fadein-match-highlighter { from { background-color: transparent; } - to { background-color: rgba(1, 151, 193, 0.1); } + to { background-color: var(--match-highlighter-alpha-15); } } .resize-grip { position: absolute; @@ -416,7 +431,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar padding: 0; height: 22px; align-items: center; - margin: 0 .2em 0 0; + margin: 0 .35em 0 0; white-space: nowrap; } .applies-to ul { @@ -468,14 +483,14 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar .add-applies-to .svg-icon, .remove-applies-to .svg-icon { pointer-events: none; - fill: hsl(0, 0%, 60%); + fill: var(--gray-lightness-60); height: 12px; width: 12px; } .add-applies-to:hover .svg-icon, .remove-applies-to:hover .svg-icon { pointer-events: none; - fill: hsl(0, 0%, 0%); + fill: var(--black); } .test-regexp { display: none; @@ -487,7 +502,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar cursor: pointer; } .regexp-report mark { - background-color: rgba(255, 255, 0, .5); + background-color: var(--regexp-report-mark-alpha-5); } .regexp-report details { margin-left: 1rem; @@ -504,10 +519,10 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar overflow-wrap: break-word; } .regexp-report details[data-type="full"] { - color: darkgreen; + color: var(--darkgreen); } .regexp-report details[data-type="partial"] { - color: darkgray; + color: var(--truegray-alpha-6); } .regexp-report details[data-type="invalid"] { color: maroon; @@ -538,7 +553,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar margin-top: -1px; } .regexp-report-note { - color: #999; + color: var(--truegray); position: absolute; margin: 0 0.5rem 0 0; hyphens: auto; @@ -550,8 +565,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar max-width: 50vw; position: fixed; display: none; - background-color: white; - box-shadow: 3px 3px 30px rgba(0, 0, 0, 0.5); + box-shadow: 3px 3px 30px var(--black-alpha-5); padding: 0.5rem; z-index: 99; } @@ -560,7 +574,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar max-width: 100%; } #help-popup.big { - box-shadow: rgba(0, 0, 0, 0.45) 0px 0px 0px 100000px !important; + box-shadow: var(--black-alpha-5) 0px 0px 0px 100000px !important; left: calc(280px - 3rem); } #help-popup.big .CodeMirror { @@ -569,7 +583,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar } #help-popup .title { font-weight: bold; - background-color: rgba(0,0,0,0.05); + background-color: var(--truegray-alpha-15); margin: -0.5rem -0.5rem 0.5rem; padding: .5rem 32px .5rem .5rem; } @@ -594,10 +608,12 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar word-break: break-all; } .keymap-list input { + background-color: var(--main-bg); + border: 1px solid var(--truegray-alpha-6); width: 100%; } .keymap-list tr:nth-child(odd) { - background-color: rgba(0, 0, 0, 0.07); + background-color: var(--truegray-alpha-1); } .keymap-list td:first-child { white-space: nowrap; @@ -651,9 +667,6 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar #lint table:last-child { margin-bottom: 0; } -#lint table.empty { - display: none; -} #lint caption { text-align: left; font-weight: bold; @@ -663,7 +676,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar cursor: pointer; } #lint tr:hover { - background-color: rgba(0, 0, 0, 0.1); + background-color: var(--black-alpha-1); } #lint td[role="severity"] { font-size: 0; @@ -716,12 +729,15 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar } .beautify-options select { border: none; - background: linear-gradient(90deg, rgba(0, 0, 0, .05) 18px, rgba(0, 0, 0, .02) 24px); + background: linear-gradient(90deg, var(--beautify-select-gradient-left) 18px, var(--beautify-select-gradient-right) 24px); font-family: monospace; font-weight: bold; padding-left: 4px; margin-left: 4px; } +.beautify-options select option{ + background-color: var(--truegray-alpha-2) +} /************ single editor **************/ .usercss body { @@ -751,8 +767,9 @@ html:not(.usercss) .usercss-only, } .usercss #name { - background-color: #eee; - color: #888; + background-color: var(--truegray-alpha-07); + color: var(--truegray); + cursor: not-allowed; } #sections .single-editor, @@ -770,14 +787,8 @@ html:not(.usercss) .usercss-only, outline: none; } -#footer a { - color: #333; - transition: color .5s; - text-decoration-skip: ink; -} - -#footer a:hover { - color: #666; +.single-editor .CodeMirror.cm-s-default { + outline: none !important; } .usercss.firefox #sections, @@ -788,9 +799,13 @@ html:not(.usercss) .usercss-only, /************ line widget *************/ .CodeMirror-linewidget .applies-to { + font: normal 12px Arial, system-ui, sans-serif; margin: 1em 0; padding: .75rem .75rem .25rem; padding-right: calc(1em + 20px); + background-color: var(--gray-lightness-90); + border-top: 1px solid var(--truegray-alpha-3); + border-bottom: 1px solid var(--truegray-alpha-3); } .CodeMirror-linewidget .applies-to li { @@ -821,7 +836,7 @@ html:not(.usercss) .usercss-only, width: unset; position: inherit; border-right: none; - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed var(--gray-lightness-66); padding: 0; } #actions { @@ -933,7 +948,7 @@ html:not(.usercss) .usercss-only, padding-left: 0; display: flex; flex-direction: column; - flex: 1; + flex: 1 1 auto; } #sections > * { margin: 0 .5rem .5rem; diff --git a/edit/edit.js b/edit/edit.js index 7ee8e21b..44af06c1 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -1,12 +1,13 @@ /* -global CodeMirror loadScript +global CodeMirror parserlib loadScript +global CSSLint initLint linterConfig updateLintReport renderLintReport updateLinter global createSourceEditor global closeCurrentTab regExpTester messageBox global setupCodeMirror global beautify global initWithSectionStyle addSections removeSection getSectionsHashes global sectionsToMozFormat -global moveFocus editorWorker +global moveFocus */ 'use strict'; @@ -211,6 +212,7 @@ function beforeUnload() { } const isDirty = editor ? editor.isDirty() : !isCleanGlobal(); if (isDirty) { + updateLintReportIfEnabled(null, 0); // neither confirm() nor custom messages work in modern browsers but just in case return t('styleChangesNotSaved'); } @@ -226,7 +228,7 @@ function isUsercss(style) { function initStyleData() { // TODO: remove .replace(/^\?/, '') when minimum_chrome_version >= 52 (https://crbug.com/601425) const params = new URLSearchParams(location.search.replace(/^\?/, '')); - const id = Number(params.get('id')); + const id = params.get('id'); const createEmptyStyle = () => ({ id: null, name: params.get('domain') || @@ -242,8 +244,8 @@ function initStyleData() { ) ], }); - return fetchStyle() - .then(style => { + return API.getStyles({id: id || -1}) + .then(([style = createEmptyStyle()]) => { styleId = style.id; if (styleId) sessionStorage.justEditedStyleId = styleId; // we set "usercss" class on when is empty @@ -257,13 +259,6 @@ function initStyleData() { } return style; }); - - function fetchStyle() { - if (id) { - return API.getStyleFromDB(id); - } - return Promise.resolve(createEmptyStyle()); - } } function initHooks() { @@ -281,6 +276,9 @@ function initHooks() { $('#save-button').addEventListener('click', save, false); $('#sections-help').addEventListener('click', showSectionHelp, false); + // TODO: investigate why FF needs this delay + debounce(initLint, FIREFOX ? 100 : 0); + if (!FIREFOX) { $$([ 'input:not([type])', @@ -355,6 +353,7 @@ function toggleStyle() { } function save() { + updateLintReportIfEnabled(null, 0); if (!validate()) { return; } @@ -415,6 +414,12 @@ function updateTitle() { $('#save-button').disabled = clean; } +function updateLintReportIfEnabled(...args) { + if (CodeMirror.defaults.lint) { + updateLintReport(...args); + } +} + function showMozillaFormat() { const popup = showCodeMirrorPopup(t('styleToMozillaFormatTitle'), '', {readOnly: true}); popup.codebox.setValue(toMozillaFormat()); @@ -456,7 +461,16 @@ function fromMozillaFormat() { function doImport({replaceOldStyle = false}) { lockPageUI(true); - editorWorker.parseMozFormat({code: popup.codebox.getValue().trim()}) + new Promise(setTimeout) + .then(() => { + const worker = linterConfig.worker.csslint; + if (!worker.instance) worker.instance = new Worker(worker.path); + }) + .then(() => linterConfig.invokeWorker({ + linter: 'csslint', + action: 'parse', + code: popup.codebox.getValue().trim(), + })) .then(({sections, errors}) => { // shouldn't happen but just in case if (!sections.length && errors.length) { @@ -469,7 +483,8 @@ function fromMozillaFormat() { removeOldSections(replaceOldStyle); return addSections(sections, div => setCleanItem(div, false)); }) - .then(() => { + .then(sectionDivs => { + sectionDivs.forEach(div => updateLintReportIfEnabled(div.CodeMirror, 1)); $('.dismiss').dispatchEvent(new Event('click')); }) .catch(showError) @@ -524,7 +539,7 @@ function showToMozillaHelp(event) { function showHelp(title = '', body) { const div = $('#help-popup'); - div.className = ''; + div.className = 'main-bg'; const contents = $('.contents', div); contents.textContent = ''; @@ -589,6 +604,7 @@ function showCodeMirrorPopup(title, html, options) { foldGutter: true, gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'], matchBrackets: true, + lint: linterConfig.getForCodeMirror(), styleActiveLine: true, theme: prefs.get('editor.theme'), keyMap: prefs.get('editor.keyMap') diff --git a/edit/global-search.css b/edit/global-search.css index 51ec9111..e7698991 100644 --- a/edit/global-search.css +++ b/edit/global-search.css @@ -6,9 +6,9 @@ max-width: calc(100vw - 4rem); box-sizing: border-box; z-index: 10000; - background-color: white; - box-shadow: 4px 5px 20px -6px rgba(0, 0, 0, .5); - border: 1px solid hsla(0, 0%, 50%, .4); + background-color: var(--white); + box-shadow: 4px 5px 20px -6px var(--black-alpha-5); + border: 1px solid var(--truegray-alpha-4); transition: opacity .25s; border-top: none; } @@ -21,7 +21,7 @@ padding-right: .75em; display: flex; align-items: stretch; - background-color: hsla(0, 0%, 50%, .1); + background-color: var(--truegray-alpha-1); } #search-replace-dialog [data-type="content"] { @@ -59,7 +59,7 @@ padding: .25rem .25rem .25rem .5rem; margin: 0; border: none; - background-color: white; + background-color: var(--white); font-weight: bold; white-space: nowrap; color: currentColor; /* use the current theme's color instead of UserAgent's CSS */ @@ -118,7 +118,7 @@ right: 0; bottom: 0; position: absolute; - border-color: hsla(180, 100%, 30%, .5); + border-color: var(--darkcyan-alpha-5); border-style: none none solid none; border-width: 4px; } @@ -160,11 +160,11 @@ display: flex; align-items: center; justify-content: center; - background-color: hsla(0, 0%, 100%, .75); + background-color: var(--white-alpha-75); } #search-replace-dialog [data-type="status"] { - background-color: hsla(0, 0%, 50%, .2); + background-color: var(--truegray-alpha-2); padding-top: 2px; padding-left: .5rem; display: flex; @@ -181,17 +181,33 @@ opacity: 1; } -/*********** CodeMirror ****************/ - -.search-target-editor { - outline: 1px solid darkorange; +/*********** CodeMirror search. Shouldn't need variables ****************/ +body.find-open .search-target-editor { + outline-color: darkorange !important; } -#stylus .search-target-match { +body.find-open .cm-searching { + background-color: rgba(255, 255, 0, .4); +} + +body.find-open .cm-searching.search-target-match { background-color: darkorange; color: black; } +body.find-open .CodeMirror-search-match { + background: gold; + border-top: 1px solid orange; + border-bottom: 1px solid orange; +} + +/* hide default CM search highlighting */ +body .cm-searching, +body .CodeMirror-search-match { + background-color: transparent; + border-color: transparent; +} + @media (max-width: 500px) { #search-replace-dialog { left: 0; diff --git a/edit/global-search.js b/edit/global-search.js index c8bdaa5c..24df31e5 100644 --- a/edit/global-search.js +++ b/edit/global-search.js @@ -753,8 +753,14 @@ onDOMready().then(() => { function makeTargetVisible(element) { const old = $('.' + TARGET_CLASS); if (old !== element) { - if (old) old.classList.remove(TARGET_CLASS); - if (element) element.classList.add(TARGET_CLASS); + if (old) { + old.classList.remove(TARGET_CLASS); + document.body.classList.remove('find-open'); + } + if (element) { + element.classList.add(TARGET_CLASS); + document.body.classList.add('find-open'); + } } }