parent
207afccd65
commit
e6f94378bf
|
@ -103,7 +103,6 @@ lazyInit();
|
|||
await editor.ready;
|
||||
editor.ready = true;
|
||||
|
||||
setTimeout(() => editor.getEditors().forEach(linter.enableForEditor));
|
||||
// enabling after init to prevent flash of validation failure on an empty name
|
||||
$('#name').required = !editor.isUsercss;
|
||||
$('#save-button').onclick = editor.save;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
importScripts('/js/worker-util.js');
|
||||
const {loadScript} = workerUtil;
|
||||
|
||||
/** @namespace EditorWorker */
|
||||
workerUtil.createAPI({
|
||||
csslint: (code, config) => {
|
||||
loadScript('/vendor-overwrites/csslint/parserlib.js', '/vendor-overwrites/csslint/csslint.js');
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
'use strict';
|
||||
|
||||
/* exported editorWorker */
|
||||
/** @type {EditorWorker} */
|
||||
const editorWorker = workerUtil.createWorker({
|
||||
url: '/edit/editor-worker.js',
|
||||
});
|
||||
|
@ -14,20 +15,57 @@ const linter = (() => {
|
|||
const cms = new Set();
|
||||
|
||||
return {
|
||||
register,
|
||||
run,
|
||||
enableForEditor,
|
||||
disableForEditor,
|
||||
onLintingUpdated,
|
||||
onUnhook,
|
||||
disableForEditor(cm) {
|
||||
cm.setOption('lint', false);
|
||||
cms.delete(cm);
|
||||
for (const cb of unhookListeners) {
|
||||
cb(cm);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {Object} cm
|
||||
* @param {string} [code] - to be used to avoid slowdowns when creating a lot of cms.
|
||||
* Enables lint option only if there are problems, thus avoiding a _very_ costly layout
|
||||
* update when lint gutter is added to a lot of editors simultaneously.
|
||||
*/
|
||||
enableForEditor(cm, code) {
|
||||
if (code) return enableOnProblems(cm, code);
|
||||
cm.setOption('lint', {getAnnotations, onUpdateLinting});
|
||||
cms.add(cm);
|
||||
},
|
||||
onLintingUpdated(cb) {
|
||||
lintingUpdatedListeners.push(cb);
|
||||
},
|
||||
onUnhook(cb) {
|
||||
unhookListeners.push(cb);
|
||||
},
|
||||
register(linterFn) {
|
||||
linters.push(linterFn);
|
||||
},
|
||||
run() {
|
||||
for (const cm of cms) {
|
||||
cm.performLint();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function onUnhook(cb) {
|
||||
unhookListeners.push(cb);
|
||||
async function enableOnProblems(cm, code) {
|
||||
const results = await getAnnotations(code, {}, cm);
|
||||
if (results.length) {
|
||||
cms.add(cm);
|
||||
cm.setOption('lint', {
|
||||
getAnnotations() {
|
||||
cm.options.lint.getAnnotations = getAnnotations;
|
||||
return results;
|
||||
},
|
||||
onUpdateLinting,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onLintingUpdated(cb) {
|
||||
lintingUpdatedListeners.push(cb);
|
||||
async function getAnnotations(...args) {
|
||||
const results = await Promise.all(linters.map(fn => fn(...args)));
|
||||
return [].concat(...results.filter(Boolean));
|
||||
}
|
||||
|
||||
function onUpdateLinting(...args) {
|
||||
|
@ -35,32 +73,4 @@ const linter = (() => {
|
|||
cb(...args);
|
||||
}
|
||||
}
|
||||
|
||||
function enableForEditor(cm) {
|
||||
cm.setOption('lint', {onUpdateLinting, getAnnotations});
|
||||
cms.add(cm);
|
||||
}
|
||||
|
||||
function disableForEditor(cm) {
|
||||
cm.setOption('lint', false);
|
||||
cms.delete(cm);
|
||||
for (const cb of unhookListeners) {
|
||||
cb(cm);
|
||||
}
|
||||
}
|
||||
|
||||
function register(linterFn) {
|
||||
linters.push(linterFn);
|
||||
}
|
||||
|
||||
function run() {
|
||||
for (const cm of cms) {
|
||||
cm.performLint();
|
||||
}
|
||||
}
|
||||
|
||||
function getAnnotations(...args) {
|
||||
return Promise.all(linters.map(fn => fn(...args)))
|
||||
.then(results => [].concat(...results.filter(Boolean)));
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -487,7 +487,7 @@ function SectionsEditor() {
|
|||
livePreview.update(getModel());
|
||||
}
|
||||
|
||||
function initSections(src, {
|
||||
async function initSections(src, {
|
||||
focusOn = 0,
|
||||
replace = false,
|
||||
pristine = false,
|
||||
|
@ -497,10 +497,6 @@ function SectionsEditor() {
|
|||
sections.length = 0;
|
||||
container.textContent = '';
|
||||
}
|
||||
let done;
|
||||
let index = 0;
|
||||
let y = 0;
|
||||
const total = src.length;
|
||||
let si = editor.scrollInfo;
|
||||
if (si && si.cms && si.cms.length === src.length) {
|
||||
si.scrollY2 = si.scrollY + window.innerHeight;
|
||||
|
@ -510,29 +506,27 @@ function SectionsEditor() {
|
|||
} else {
|
||||
si = null;
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
done = resolve;
|
||||
chunk(!si);
|
||||
});
|
||||
function chunk(forceRefresh) {
|
||||
const t0 = performance.now();
|
||||
while (index < total && performance.now() - t0 < 100) {
|
||||
if (si) forceRefresh = y < si.scrollY2 && (y += si.cms[index].parentHeight) > si.scrollY;
|
||||
insertSectionAfter(src[index], undefined, forceRefresh, si && si.cms[index]);
|
||||
if (pristine) dirty.clear();
|
||||
if (index === focusOn && !si) sections[index].cm.focus();
|
||||
index++;
|
||||
}
|
||||
setGlobalProgress(index, total);
|
||||
if (index === total) {
|
||||
setGlobalProgress();
|
||||
if (!si) requestAnimationFrame(fitToAvailableSpace);
|
||||
container.style.removeProperty('height');
|
||||
done();
|
||||
} else {
|
||||
setTimeout(chunk);
|
||||
let forceRefresh = true;
|
||||
let y = 0;
|
||||
let tPrev;
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
const t = performance.now();
|
||||
if (!tPrev) {
|
||||
tPrev = t;
|
||||
} else if (t - tPrev > 100) {
|
||||
tPrev = 0;
|
||||
forceRefresh = false;
|
||||
await new Promise(setTimeout);
|
||||
}
|
||||
if (si) forceRefresh = y < si.scrollY2 && (y += si.cms[i].parentHeight) > si.scrollY;
|
||||
insertSectionAfter(src[i], null, forceRefresh, si && si.cms[i]);
|
||||
setGlobalProgress(i, src.length);
|
||||
if (pristine) dirty.clear();
|
||||
if (i === focusOn && !si) sections[i].cm.focus();
|
||||
}
|
||||
if (!si) requestAnimationFrame(fitToAvailableSpace);
|
||||
container.style.removeProperty('height');
|
||||
setGlobalProgress();
|
||||
}
|
||||
|
||||
/** @param {EditorSection} section */
|
||||
|
@ -584,23 +578,23 @@ function SectionsEditor() {
|
|||
}
|
||||
const section = createSection(init, genId, si);
|
||||
const {cm} = section;
|
||||
const {code} = init;
|
||||
const index = base ? sections.indexOf(base) + 1 : sections.length;
|
||||
sections.splice(index, 0, section);
|
||||
container.insertBefore(section.el, base ? base.el.nextSibling : null);
|
||||
refreshOnView(cm, base || forceRefresh);
|
||||
refreshOnView(cm, {code, force: base || forceRefresh});
|
||||
registerEvents(section);
|
||||
if ((!si || !si.height) && (!base || init.code)) {
|
||||
if ((!si || !si.height) && (!base || code)) {
|
||||
// Fit a) during startup or b) when the clone button is clicked on a section with some code
|
||||
fitToContent(section);
|
||||
}
|
||||
if (base) {
|
||||
cm.focus();
|
||||
editor.scrollToEditor(cm);
|
||||
linter.enableForEditor(cm);
|
||||
}
|
||||
updateSectionOrder();
|
||||
section.onChange(updateLivePreview);
|
||||
updateLivePreview();
|
||||
section.onChange(updateLivePreview);
|
||||
}
|
||||
|
||||
/** @param {EditorSection} section */
|
||||
|
@ -654,10 +648,12 @@ function SectionsEditor() {
|
|||
}
|
||||
}
|
||||
|
||||
function refreshOnView(cm, force) {
|
||||
return force || !xo ?
|
||||
cm.refresh() :
|
||||
function refreshOnView(cm, {code, force} = {}) {
|
||||
if (force || !xo) {
|
||||
refreshOnViewNow(cm, code);
|
||||
} else {
|
||||
xo.observe(cm.display.wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {IntersectionObserverEntry[]} entries */
|
||||
|
@ -668,14 +664,19 @@ function SectionsEditor() {
|
|||
xo.unobserve(e.target);
|
||||
const cm = e.target.CodeMirror;
|
||||
if (r.bottom > 0 && r.top < window.innerHeight) {
|
||||
cm.refresh();
|
||||
refreshOnViewNow(cm);
|
||||
} else {
|
||||
setTimeout(() => cm.refresh());
|
||||
setTimeout(refreshOnViewNow, 0, cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshOnViewNow(cm, code) {
|
||||
cm.refresh();
|
||||
linter.enableForEditor(cm, code);
|
||||
}
|
||||
|
||||
function toggleContextMenuDelete(event) {
|
||||
if (chrome.contextMenus && event.button === 2 && prefs.get('editor.contextDelete')) {
|
||||
chrome.contextMenus.update('editor.contextDelete', {
|
||||
|
|
|
@ -91,6 +91,7 @@ function SourceEditor() {
|
|||
linter.run();
|
||||
updateLinterSwitch();
|
||||
});
|
||||
setTimeout(linter.enableForEditor, 0, cm);
|
||||
if (!$.isTextInput(document.activeElement)) {
|
||||
cm.focus();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user