420733b93a
* add Patch CSP option * show style version, size, and update age in manager * add scope selector to style search in manager * keep scroll position and selections in tab's session * directly install usercss from raw github links * ditch localStorage, use on-demand SessionStore proxy * simplify localization * allow <code> tag in i18n-html * keep nodes in HTML templates * API.getAllStyles is actually faster with code untouched * fix fitToContent when applies-to is taller than window * dedupe linter.enableForEditor calls * prioritize visible CMs in refreshOnViewListener * don't scroll to last style on editing a new one * delay colorview for invisible CMs * eslint comma-dangle error + autofix files * styleViaXhr: also toggle for disableAll pref * styleViaXhr: allow cookies for sandbox CSP * simplify notes in options * simplify getStylesViaXhr * oldUI fixups: * remove separator before 1st applies-to * center name bubbles * fix updateToc focus on a newly added section * fix fitToContent when cloning section * remove CSS `contain` as it makes no difference * replace overrides with declarative CSS + code cosmetics * simplify adjustWidth and make it work in FF
104 lines
3.0 KiB
JavaScript
104 lines
3.0 KiB
JavaScript
/* global backgroundWorker */
|
|
/* exported usercss */
|
|
'use strict';
|
|
|
|
const usercss = (() => {
|
|
const GLOBAL_METAS = {
|
|
author: undefined,
|
|
description: undefined,
|
|
homepageURL: 'url',
|
|
updateURL: 'updateUrl',
|
|
name: undefined,
|
|
};
|
|
const RX_META = /\/\*!?\s*==userstyle==[\s\S]*?==\/userstyle==\s*\*\//i;
|
|
const ERR_ARGS_IS_LIST = new Set(['missingMandatory', 'missingChar']);
|
|
return {
|
|
RX_META,
|
|
buildMeta,
|
|
buildCode,
|
|
assignVars,
|
|
};
|
|
|
|
function buildMeta(sourceCode) {
|
|
sourceCode = sourceCode.replace(/\r\n?/g, '\n');
|
|
|
|
const style = {
|
|
enabled: true,
|
|
sourceCode,
|
|
sections: [],
|
|
};
|
|
|
|
const match = sourceCode.match(RX_META);
|
|
if (!match) {
|
|
throw new Error('can not find metadata');
|
|
}
|
|
|
|
return backgroundWorker.parseUsercssMeta(match[0], match.index)
|
|
.catch(err => {
|
|
if (err.code) {
|
|
const args = ERR_ARGS_IS_LIST.has(err.code) ? drawList(err.args) : err.args;
|
|
const message = chrome.i18n.getMessage(`meta_${err.code}`, args);
|
|
if (message) {
|
|
err.message = message;
|
|
}
|
|
}
|
|
throw err;
|
|
})
|
|
.then(({metadata}) => {
|
|
style.usercssData = metadata;
|
|
// https://github.com/openstyles/stylus/issues/560#issuecomment-440561196
|
|
for (const [key, value] of Object.entries(GLOBAL_METAS)) {
|
|
if (metadata[key] !== undefined) {
|
|
style[value || key] = metadata[key];
|
|
}
|
|
}
|
|
return style;
|
|
});
|
|
}
|
|
|
|
function drawList(items) {
|
|
return items.map(i => i.length === 1 ? JSON.stringify(i) : i).join(', ');
|
|
}
|
|
|
|
/**
|
|
* @param {Object} style
|
|
* @param {Boolean} [allowErrors=false]
|
|
* @returns {(Style | {style: Style, errors: (false|String[])})} - style object
|
|
* when allowErrors is falsy or {style, errors} object when allowErrors is truthy
|
|
*/
|
|
function buildCode(style, allowErrors) {
|
|
const match = style.sourceCode.match(RX_META);
|
|
return backgroundWorker.compileUsercss(
|
|
style.usercssData.preprocessor,
|
|
style.sourceCode.slice(0, match.index) + style.sourceCode.slice(match.index + match[0].length),
|
|
style.usercssData.vars
|
|
)
|
|
.then(({sections, errors}) => {
|
|
if (!errors.length) errors = false;
|
|
if (!sections.length || errors && !allowErrors) {
|
|
throw errors || 'Style does not contain any actual CSS to apply.';
|
|
}
|
|
style.sections = sections;
|
|
return allowErrors ? {style, errors} : style;
|
|
});
|
|
}
|
|
|
|
function assignVars(style, oldStyle) {
|
|
const {usercssData: {vars}} = style;
|
|
const {usercssData: {vars: oldVars}} = oldStyle;
|
|
if (!vars || !oldVars) {
|
|
return Promise.resolve();
|
|
}
|
|
// The type of var might be changed during the update. Set value to null if the value is invalid.
|
|
for (const key of Object.keys(vars)) {
|
|
if (oldVars[key] && oldVars[key].value) {
|
|
vars[key].value = oldVars[key].value;
|
|
}
|
|
}
|
|
return backgroundWorker.nullifyInvalidVars(vars)
|
|
.then(vars => {
|
|
style.usercssData.vars = vars;
|
|
});
|
|
}
|
|
})();
|