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