diff --git a/edit.html b/edit.html index 3368a28b..b8d2b243 100644 --- a/edit.html +++ b/edit.html @@ -8,8 +8,8 @@ - + @@ -34,6 +34,7 @@ + diff --git a/edit/edit.js b/edit/edit.js index 34b8eadd..b6ebaa74 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -162,8 +162,6 @@ function initCodeMirror() { const CM = CodeMirror; const isWindowsOS = navigator.appVersion.indexOf('Windows') > 0; // lint.js is not loaded initially - const hasLinter = window.linterConfig ? linterConfig.getForCodeMirror() : false; - // CodeMirror miserably fails on keyMap='' so let's ensure it's not if (!prefs.get('editor.keyMap')) { prefs.reset('editor.keyMap'); @@ -175,11 +173,15 @@ function initCodeMirror() { lineNumbers: true, lineWrapping: true, foldGutter: true, - gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'], + gutters: [ + 'CodeMirror-linenumbers', + 'CodeMirror-foldgutter', + ...(prefs.get('editor.linter') ? ['CodeMirror-lint-markers'] : []), + ], matchBrackets: true, highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true}, hintOptions: {}, - lint: hasLinter, + lint: linterConfig.getForCodeMirror(), lintReportDelay: prefs.get('editor.lintReportDelay'), styleActiveLine: true, theme: 'default', @@ -370,7 +372,7 @@ function acmeEventListener(event) { option = 'highlightSelectionMatches'; break; case 'linter': - updateLinter(value); + debounce(updateLinter); break; } CodeMirror.setOption(option, value); diff --git a/edit/lint.js b/edit/lint.js index 802d8196..5bb30033 100644 --- a/edit/lint.js +++ b/edit/lint.js @@ -3,6 +3,8 @@ /* global onDOMscripted injectCSS require CSSLint stylelint */ 'use strict'; +loadLinterAssets(); + // eslint-disable-next-line no-var var linterConfig = { csslint: {}, @@ -133,19 +135,49 @@ function initLint() { } function updateLinter(linter = prefs.get('editor.linter')) { + const GUTTERS_CLASS = 'CodeMirror-lint-markers'; + function updateEditors() { - const options = linterConfig.getForCodeMirror(linter); - CodeMirror.defaults.lint = options; + CodeMirror.defaults.lint = linterConfig.getForCodeMirror(linter); + const guttersOption = prepareGuttersOption(); editors.forEach(cm => { - // set lint to "null" to disable - cm.setOption('lint', options); - // enabling/disabling linting changes the gutter width + cm.setOption('lint', CodeMirror.defaults.lint); + if (guttersOption) { + cm.setOption('guttersOption', guttersOption); + updateGutters(cm, guttersOption); + } cm.refresh(); updateLintReport(cm, 200); }); } + + function prepareGuttersOption() { + const gutters = CodeMirror.defaults.gutters; + const needRefresh = Boolean(linter) !== gutters.includes(GUTTERS_CLASS); + if (needRefresh) { + if (linter) { + gutters.push(GUTTERS_CLASS); + } else { + gutters.splice(gutters.indexOf(GUTTERS_CLASS), 1); + } + } + return needRefresh && gutters; + } + + function updateGutters(cm, guttersOption) { + cm.options.gutters = guttersOption; + const el = $('.' + GUTTERS_CLASS, cm.display.gutters); + if (linter && !el) { + cm.display.gutters.appendChild($element({ + className: 'CodeMirror-gutter ' + GUTTERS_CLASS + })); + } else if (!linter && el) { + el.remove(); + } + } + // load scripts - loadSelectedLinter(linter).then(() => { + loadLinterAssets(linter).then(() => { updateEditors(); }); $('#linter-settings').style.display = !linter ? 'none' : 'inline-block'; @@ -159,8 +191,10 @@ function updateLintReport(cm, delay) { } if (delay > 0) { setTimeout(cm => { - cm.performLint(); - update(cm); + if (cm.performLint) { + cm.performLint(); + update(cm); + } }, delay, cm); return; } @@ -374,7 +408,7 @@ function setupLinterSettingsEvents(popup) { } linterConfig.save(json); linterConfig.showSavedMessage(); - debounce(updateLinter, 0, linter); + debounce(updateLinter); } else { showLinterErrorMessage(linter, t('linterJSONError')); } @@ -450,7 +484,11 @@ function setupLinterPopup(config) { setupLinterSettingsEvents(popup); } -function loadSelectedLinter(name) { +function loadLinterAssets(name = prefs.get('editor.linter')) { + if (loadLinterAssets.loadingName === name) { + return onDOMscripted(); + } + loadLinterAssets.loadingName = name; const scripts = []; if (name === 'csslint' && !window.CSSLint) { scripts.push( @@ -473,5 +511,6 @@ function loadSelectedLinter(name) { 'msgbox/msgbox.js' ); } - return onDOMscripted(scripts); + return onDOMscripted(scripts) + .then(() => (loadLinterAssets.loadingName = null)); }