Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fc39f0d5a6 | ||
|
1725c0ecb9 | ||
|
79dff2775b | ||
|
b22bbaaec0 | ||
|
fff59ee12f | ||
|
540e2af62c | ||
|
0128489bbb | ||
|
a5b11ac687 |
|
@ -186,6 +186,10 @@
|
|||
"message": "Theme",
|
||||
"description": "Label for the style editor's CSS theme."
|
||||
},
|
||||
"cm_arrowKeysTraverse": {
|
||||
"message": "Arrow keys ↑↓ traverse sections",
|
||||
"description": "Label for the option in the editor."
|
||||
},
|
||||
"colorpickerPaletteHint": {
|
||||
"message": "Right-click a swatch to cycle through its source lines"
|
||||
},
|
||||
|
|
|
@ -199,6 +199,18 @@ const styleMan = (() => {
|
|||
|
||||
getOrder: () => orderWrap.value,
|
||||
|
||||
/** @returns {Promise<string | {[remoteId:string]: styleId}>}>} */
|
||||
async getRemoteInfo(id) {
|
||||
if (ready.then) await ready;
|
||||
if (id) return calcRemoteId(id2style(id));
|
||||
const res = {};
|
||||
for (const {style} of dataMap.values()) {
|
||||
const [rid, vars] = calcRemoteId(style);
|
||||
if (rid) res[rid] = [style.id, vars];
|
||||
}
|
||||
return res;
|
||||
},
|
||||
|
||||
/** @returns {Promise<StyleSectionsToApply>} */
|
||||
async getSectionsByUrl(url, id, isInitialApply) {
|
||||
if (ready.then) await ready;
|
||||
|
@ -366,6 +378,17 @@ const styleMan = (() => {
|
|||
return id2style(uuidIndex.get(uuid));
|
||||
}
|
||||
|
||||
function calcRemoteId({md5Url, updateUrl, usercssData: ucd} = {}) {
|
||||
let id;
|
||||
id = (id = /\d+/.test(md5Url) || URLS.extractUsoArchiveId(updateUrl)) && `uso-${id}`
|
||||
|| (id = URLS.extractUSwId(updateUrl)) && `usw-${id}`
|
||||
|| '';
|
||||
return id && [
|
||||
id,
|
||||
ucd && !isEmptyObj(ucd.vars),
|
||||
];
|
||||
}
|
||||
|
||||
/** @returns {StyleObj} */
|
||||
function createNewStyle() {
|
||||
return /** @namespace StyleObj */ {
|
||||
|
|
|
@ -338,6 +338,12 @@
|
|||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option sectioned-only">
|
||||
<label i18n="cm_arrowKeysTraverse">
|
||||
<input id="editor.arrowKeysTraverse" type="checkbox">
|
||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<label i18n="cm_colorpicker">
|
||||
<input id="editor.colorpicker" type="checkbox">
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
k.slice('editor.'.length);
|
||||
const prefKeys = prefs.knownKeys.filter(k =>
|
||||
k !== 'editor.colorpicker' && // handled in colorpicker-helper.js
|
||||
k !== 'editor.arrowKeysTraverse' && // handled in sections-editor.js
|
||||
prefToCmOpt(k) in CodeMirror.defaults);
|
||||
const {insertTab, insertSoftTab} = CodeMirror.commands;
|
||||
|
||||
|
|
|
@ -75,8 +75,8 @@ html:not(.is-new-style) #heading::before {
|
|||
right: 24px;
|
||||
}
|
||||
/************ checkbox & select************/
|
||||
.options-column > div[class="option"] {
|
||||
margin-bottom: 4px;
|
||||
.options-column > .option {
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
|
||||
.options-column > .usercss-only {
|
||||
|
@ -107,6 +107,8 @@ label {
|
|||
}
|
||||
#sections {
|
||||
padding-left: var(--header-width);
|
||||
}
|
||||
.usercss #sections {
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ function createSection(originalSection, genId, si) {
|
|||
value: originalSection.code,
|
||||
});
|
||||
el.CodeMirror = cm; // used by getAssociatedEditor
|
||||
cm.el = el;
|
||||
editor.applyScrollInfo(cm, si);
|
||||
|
||||
const changeListeners = new Set();
|
||||
|
@ -114,49 +115,10 @@ function createSection(originalSection, genId, si) {
|
|||
changeGeneration = newGeneration;
|
||||
emitSectionChange('code');
|
||||
});
|
||||
cm.display.wrapper.on('keydown', event => handleKeydown(cm, event), true);
|
||||
$('.test-regexp', el).onclick = () => updateRegexpTester(true);
|
||||
initBeautifyButton($('.beautify-section', el), [cm]);
|
||||
}
|
||||
|
||||
function handleKeydown(cm, event) {
|
||||
if (event.shiftKey || event.altKey || event.metaKey) {
|
||||
return;
|
||||
}
|
||||
const {key} = event;
|
||||
const {line, ch} = cm.getCursor();
|
||||
switch (key) {
|
||||
case 'ArrowLeft':
|
||||
if (line || ch) {
|
||||
return;
|
||||
}
|
||||
// fallthrough
|
||||
case 'ArrowUp':
|
||||
cm = line === 0 && editor.prevEditor(cm, false);
|
||||
if (!cm) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
cm.setCursor(cm.doc.size - 1, key === 'ArrowLeft' ? 1e20 : ch);
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
if (line < cm.doc.size - 1 || ch < cm.getLine(line).length - 1) {
|
||||
return;
|
||||
}
|
||||
// fallthrough
|
||||
case 'ArrowDown':
|
||||
cm = line === cm.doc.size - 1 && editor.nextEditor(cm, false);
|
||||
if (!cm) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
cm.setCursor(0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateRegexpTester(toggle) {
|
||||
const isLoaded = typeof regexpTester === 'object' ||
|
||||
toggle && await require(['/edit/regexp-tester']); /* global regexpTester */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
/* global createSection */// sections-editor-section.js
|
||||
/* global editor */
|
||||
/* global linterMan */
|
||||
/* global prefs */
|
||||
/* global styleSectionsEqual */ // sections-util.js
|
||||
/* global t */// localization.js
|
||||
'use strict';
|
||||
|
@ -21,6 +22,7 @@ function SectionsEditor() {
|
|||
let sectionOrder = '';
|
||||
let headerOffset; // in compact mode the header is at the top so it reduces the available height
|
||||
let cmExtrasHeight; // resize grip + borders
|
||||
let upDownJumps;
|
||||
|
||||
updateMeta();
|
||||
rerouteHotkeys.toggle(true); // enabled initially because we don't always focus a CodeMirror
|
||||
|
@ -30,6 +32,10 @@ function SectionsEditor() {
|
|||
$('#from-mozilla').on('click', () => showMozillaFormatImport());
|
||||
document.on('wheel', scrollEntirePageOnCtrlShift, {passive: false});
|
||||
CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow';
|
||||
prefs.subscribe('editor.arrowKeysTraverse', (_, val) => {
|
||||
for (const {cm} of sections) handleKeydownSetup(cm, val);
|
||||
upDownJumps = val;
|
||||
}, {runNow: true});
|
||||
|
||||
/** @namespace Editor */
|
||||
Object.assign(editor, {
|
||||
|
@ -70,15 +76,15 @@ function SectionsEditor() {
|
|||
}
|
||||
},
|
||||
|
||||
nextEditor(cm, cycle = true) {
|
||||
return cycle || cm !== findLast(sections, s => !s.removed).cm
|
||||
? nextPrevEditor(cm, 1)
|
||||
nextEditor(cm, upDown) {
|
||||
return !upDown || cm !== findLast(sections, s => !s.removed).cm
|
||||
? nextPrevEditor(cm, 1, upDown)
|
||||
: null;
|
||||
},
|
||||
|
||||
prevEditor(cm, cycle = true) {
|
||||
return cycle || cm !== sections.find(s => !s.removed).cm
|
||||
? nextPrevEditor(cm, -1)
|
||||
prevEditor(cm, upDown) {
|
||||
return !upDown || cm !== sections.find(s => !s.removed).cm
|
||||
? nextPrevEditor(cm, -1, upDown)
|
||||
: null;
|
||||
},
|
||||
|
||||
|
@ -112,14 +118,16 @@ function SectionsEditor() {
|
|||
editor.useSavedStyle(newStyle);
|
||||
},
|
||||
|
||||
scrollToEditor(cm) {
|
||||
const {el} = sections.find(s => s.cm === cm);
|
||||
const r = el.getBoundingClientRect();
|
||||
const h = window.innerHeight;
|
||||
if (r.bottom > h && r.top > 0 ||
|
||||
r.bottom < h && r.top < 0) {
|
||||
window.scrollBy(0, (r.top + r.bottom - h) / 2 | 0);
|
||||
}
|
||||
scrollToEditor(cm, partial) {
|
||||
const cc = partial && cm.cursorCoords(true, 'window');
|
||||
const {top: y1, bottom: y2} = cm.el.getBoundingClientRect();
|
||||
const rc = container.getBoundingClientRect();
|
||||
const rcY1 = Math.max(rc.top, 0);
|
||||
const rcY2 = Math.min(rc.bottom, innerHeight);
|
||||
const bad = partial
|
||||
? cc.top < rcY1 || cc.top > rcY2 - 30
|
||||
: y1 >= rcY1 ^ y2 <= rcY2;
|
||||
if (bad) window.scrollBy(0, (y1 + y2 - rcY2 + rcY1) / 2 | 0);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -291,10 +299,36 @@ function SectionsEditor() {
|
|||
}
|
||||
}
|
||||
|
||||
function nextPrevEditor(cm, direction) {
|
||||
function handleKeydown(event) {
|
||||
if (event.shiftKey || event.altKey || event.metaKey ||
|
||||
event.key !== 'ArrowUp' && event.key !== 'ArrowDown') {
|
||||
return;
|
||||
}
|
||||
let pos;
|
||||
let cm = this.CodeMirror;
|
||||
const {line, ch} = cm.getCursor();
|
||||
if (event.key === 'ArrowUp') {
|
||||
cm = line === 0 && editor.prevEditor(cm, true);
|
||||
pos = cm && [cm.doc.size - 1, ch];
|
||||
} else {
|
||||
cm = line === cm.doc.size - 1 && editor.nextEditor(cm, true);
|
||||
pos = cm && [0, 0];
|
||||
}
|
||||
if (cm) {
|
||||
cm.setCursor(...pos);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydownSetup(cm, state) {
|
||||
cm.display.wrapper[state ? 'on' : 'off']('keydown', handleKeydown, true);
|
||||
}
|
||||
|
||||
function nextPrevEditor(cm, direction, upDown) {
|
||||
const editors = editor.getEditors();
|
||||
cm = editors[(editors.indexOf(cm) + direction + editors.length) % editors.length];
|
||||
editor.scrollToEditor(cm);
|
||||
editor.scrollToEditor(cm, upDown);
|
||||
cm.focus();
|
||||
return cm;
|
||||
}
|
||||
|
@ -577,6 +611,9 @@ function SectionsEditor() {
|
|||
cm.focus();
|
||||
editor.scrollToEditor(cm);
|
||||
}
|
||||
if (upDownJumps) {
|
||||
handleKeydownSetup(cm, true);
|
||||
}
|
||||
updateSectionOrder();
|
||||
updateLivePreview();
|
||||
section.onChange(updateLivePreview);
|
||||
|
|
|
@ -1,32 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
const colorConverter = (() => {
|
||||
const colorConverter = (NAMED_COLORS => {
|
||||
|
||||
const RXS_NUM = /\s*([+-]?(?:\d+\.?\d*|\d*\.\d+))(?:e[+-]?\d+)?/.source;
|
||||
const RXS_NUM_ANGLE = `${RXS_NUM}(deg|g?rad|turn)?`;
|
||||
// All groups in RXS_NUM must use ?: in order to enable \1 in RX_COLOR.rgb
|
||||
const RXS_NUM = /\s*[+-]?(\.\d+|\d+(\.\d*)?)(e[+-]?\d+)?/.source.replace(/\(/g, '(?:');
|
||||
const RXS_ANGLE = '(?:deg|g?rad|turn)?';
|
||||
const expandRe = re => RegExp(re.source.replace(/N/g, RXS_NUM).replace(/A/g, RXS_ANGLE), 'iy');
|
||||
const RX_COLOR = {
|
||||
hex: /#([a-f\d]{3}(?:[a-f\d](?:[a-f\d]{2}){0,2})?)\b/iy,
|
||||
|
||||
hsl: new RegExp([
|
||||
// num_or_angle, pct, pct [ , num_or_pct]?
|
||||
`^(${RXS_NUM_ANGLE})\\s*,(${RXS_NUM}%\\s*(,|$)){2}(${RXS_NUM}%?)?\\s*$`,
|
||||
// num_or_angle pct pct [ / num_or_pct]?
|
||||
`^(${RXS_NUM_ANGLE})\\s+(${RXS_NUM}%\\s*(\\s|$)){2}(/${RXS_NUM}%?)?\\s*$`,
|
||||
].join('|'), 'iy'),
|
||||
|
||||
hwb: new RegExp(
|
||||
// num|angle|none pct|none pct|none [ / num|pct|none ]?
|
||||
`^(${RXS_NUM_ANGLE}|none)(\\s+(${RXS_NUM}%|none)){2}(\\s+|$)(/${RXS_NUM}%?|none)?\\s*$`,
|
||||
'iy'),
|
||||
|
||||
rgb: new RegExp([
|
||||
// num, num, num [ , num_or_pct]?
|
||||
// pct, pct, pct [ , num_or_pct]?
|
||||
`^((${RXS_NUM}\\s*(,|$)){3}|(${RXS_NUM}%\\s*(,|$)){3})(${RXS_NUM}%?)?\\s*$`,
|
||||
// num num num [ / num_or_pct]?
|
||||
// pct pct pct [ / num_or_pct]?
|
||||
`^((${RXS_NUM}\\s*(\\s|$)){3}|(${RXS_NUM}%\\s*(\\s|$)){3})(/${RXS_NUM}%?)?\\s*$`,
|
||||
].join('|'), 'iy'),
|
||||
// num_or_angle, pct, pct [ , num_or_pct]?
|
||||
// num_or_angle pct pct [ / num_or_pct]?
|
||||
hsl: expandRe(/^NA(\s*(,N%\s*){2}(,N%?\s*)?|(\s+N%){2}\s*(\/N%?\s*)?)$/),
|
||||
// num_or_angle|none pct|none pct|none [ / num_or_pct|none ]?
|
||||
hwb: expandRe(/^(NA|none)(\s+(N%|none)){2}\s*(\/(N%?|none)\s*)?$/),
|
||||
// num, num, num [ , num_or_pct]?
|
||||
// pct, pct, pct [ , num_or_pct]?
|
||||
// num num num [ / num_or_pct]?
|
||||
// pct pct pct [ / num_or_pct]?
|
||||
rgb: expandRe(/^N(%?)(\s*,N\1\s*,N\1\s*(,N%?\s*)?|\s+N\1\s+N\1\s*(\/N%?\s*)?)$/),
|
||||
};
|
||||
const ANGLE_TO_DEG = {
|
||||
grad: 360 / 400,
|
||||
|
@ -51,6 +42,7 @@ const colorConverter = (() => {
|
|||
'v' in c ? 'hsv' :
|
||||
'l' in c ? 'hsl' :
|
||||
undefined;
|
||||
let HEX;
|
||||
|
||||
return {
|
||||
parse,
|
||||
|
@ -64,8 +56,8 @@ const colorConverter = (() => {
|
|||
snapToInt,
|
||||
testAt,
|
||||
ALPHA_DIGITS: 3,
|
||||
NAMED_COLORS,
|
||||
RX_COLOR,
|
||||
// NAMED_COLORS is added below
|
||||
};
|
||||
|
||||
function format(color = '', type = color.type, {hexUppercase, usoMode, round} = {}) {
|
||||
|
@ -95,57 +87,71 @@ const colorConverter = (() => {
|
|||
}
|
||||
}
|
||||
|
||||
function parse(str) {
|
||||
if (typeof str !== 'string') return;
|
||||
str = str.trim().toLowerCase();
|
||||
if (!str) return;
|
||||
|
||||
if (str[0] !== '#' && !str.includes('(')) {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
str = colorConverter.NAMED_COLORS.get(str);
|
||||
if (!str) return;
|
||||
function parse(s) {
|
||||
if (typeof s !== 'string' || !(s = s.trim())) {
|
||||
return;
|
||||
} else if (s[0] === '#') {
|
||||
return parseHex(s);
|
||||
} else if (s.endsWith(')') && (s = s.match(/^(hwb|(hsl|rgb)a?)\(\s*([^)]+)/i))) {
|
||||
return parseFunc((s[2] || s[1]).toLowerCase(), s[3]);
|
||||
} else {
|
||||
return colorConverter.NAMED_COLORS.get(s.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
if (str[0] === '#') {
|
||||
if (!testAt(RX_COLOR.hex, 0, str)) {
|
||||
return;
|
||||
}
|
||||
str = str.slice(1);
|
||||
const [r, g, b, a = 255] = str.length <= 4 ?
|
||||
str.match(/(.)/g).map(c => parseInt(c + c, 16)) :
|
||||
str.match(/(..)/g).map(c => parseInt(c, 16));
|
||||
return {
|
||||
type: 'hex',
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
a: a === 255 ? undefined : a / 255,
|
||||
};
|
||||
function initHexMap() {
|
||||
HEX = Array(256).fill(-0xFFFF); // ensuring a PACKED_SMI array
|
||||
for (let i = 48; i < 58; i++) HEX[i] = i - 48; // 0123456789
|
||||
for (let i = 65; i < 71; i++) HEX[i] = i - 65 + 10; // ABCDEF
|
||||
for (let i = 97; i < 103; i++) HEX[i] = i - 97 + 10; // abcdef
|
||||
}
|
||||
|
||||
function parseHex(str) {
|
||||
if (!HEX) initHexMap();
|
||||
let r, g, b, a;
|
||||
const len = str.length;
|
||||
if (len === 4 || len === 5
|
||||
? (r = HEX[str.charCodeAt(1)] * 0x11) >= 0 &&
|
||||
(g = HEX[str.charCodeAt(2)] * 0x11) >= 0 &&
|
||||
(b = HEX[str.charCodeAt(3)] * 0x11) >= 0 &&
|
||||
(len < 5 || (a = HEX[str.charCodeAt(4)] * 0x11 / 255) >= 0)
|
||||
: (len === 7 || len === 9) &&
|
||||
(r = HEX[str.charCodeAt(1)] * 0x10 + HEX[str.charCodeAt(2)]) >= 0 &&
|
||||
(g = HEX[str.charCodeAt(3)] * 0x10 + HEX[str.charCodeAt(4)]) >= 0 &&
|
||||
(b = HEX[str.charCodeAt(5)] * 0x10 + HEX[str.charCodeAt(6)]) >= 0 &&
|
||||
(len < 9 || (a = (HEX[str.charCodeAt(7)] * 0x10 + HEX[str.charCodeAt(8)]) / 255) >= 0)
|
||||
) {
|
||||
return {type: 'hex', r, g, b, a};
|
||||
}
|
||||
}
|
||||
|
||||
const [, func, type = func, value] = str.match(/^((rgb|hsl)a?|hwb)\(\s*(.*?)\s*\)|$/);
|
||||
if (!func || !testAt(RX_COLOR[type], 0, value)) {
|
||||
function parseFunc(type, val) {
|
||||
if (!testAt(RX_COLOR[type], 0, val)) {
|
||||
return;
|
||||
}
|
||||
const [s1, s2, s3, sA] = value.split(/\s*[,/]\s*|\s+/);
|
||||
const a = isNaN(sA) ? 1 : constrain(0, 1, sA / (sA.endsWith('%') ? 100 : 1));
|
||||
|
||||
// Not using destructuring because it's slow
|
||||
const parts = val.trim().split(/\s*[,/]\s*|\s+/);
|
||||
const n1 = parseFloat(parts[0]);
|
||||
const n2 = parseFloat(parts[1]);
|
||||
const n3 = parseFloat(parts[2]);
|
||||
const nA = parseFloat(parts[3]);
|
||||
const a = isNaN(nA) ? undefined : constrain(0, 1, parts[3].endsWith('%') ? nA / 100 : nA);
|
||||
if (type === 'rgb') {
|
||||
const k = s1.endsWith('%') ? 2.55 : 1;
|
||||
const k = parts[0].endsWith('%') ? 2.55 : 1;
|
||||
return {
|
||||
type,
|
||||
r: constrain(0, 255, Math.round(s1 * k)),
|
||||
g: constrain(0, 255, Math.round(s2 * k)),
|
||||
b: constrain(0, 255, Math.round(s3 * k)),
|
||||
r: constrain(0, 255, Math.round(n1 * k)),
|
||||
g: constrain(0, 255, Math.round(n2 * k)),
|
||||
b: constrain(0, 255, Math.round(n3 * k)),
|
||||
a,
|
||||
};
|
||||
}
|
||||
const h = constrainHue(parseFloat(s1) * (ANGLE_TO_DEG[s1.match(/\D*$/)[0]] || 1));
|
||||
const n2 = constrain(0, 100, parseFloat(s2) || 0);
|
||||
const n3 = constrain(0, 100, parseFloat(s3) || 0);
|
||||
const h = constrainHue(n1 * (ANGLE_TO_DEG[parts[0].match(/\D*$/)[0].toLowerCase()] || 1));
|
||||
const n2c = constrain(0, 100, n2 || 0);
|
||||
const n3c = constrain(0, 100, n3 || 0);
|
||||
return type === 'hwb'
|
||||
? {type, h, w: n2, b: n3, a}
|
||||
: {type, h, s: n2, l: n3, a};
|
||||
? {type, h, w: n2c, b: n3c, a}
|
||||
: {type, h, s: n2c, l: n3c, a};
|
||||
}
|
||||
|
||||
function formatAlpha(a) {
|
||||
|
@ -265,157 +271,154 @@ const colorConverter = (() => {
|
|||
rx.lastIndex = index;
|
||||
return rx.test(text);
|
||||
}
|
||||
})();
|
||||
|
||||
colorConverter.NAMED_COLORS = new Map([
|
||||
['transparent', 'rgba(0, 0, 0, 0)'],
|
||||
// CSS4 named colors
|
||||
['aliceblue', '#f0f8ff'],
|
||||
['antiquewhite', '#faebd7'],
|
||||
['aqua', '#00ffff'],
|
||||
['aquamarine', '#7fffd4'],
|
||||
['azure', '#f0ffff'],
|
||||
['beige', '#f5f5dc'],
|
||||
['bisque', '#ffe4c4'],
|
||||
['black', '#000000'],
|
||||
['blanchedalmond', '#ffebcd'],
|
||||
['blue', '#0000ff'],
|
||||
['blueviolet', '#8a2be2'],
|
||||
['brown', '#a52a2a'],
|
||||
['burlywood', '#deb887'],
|
||||
['cadetblue', '#5f9ea0'],
|
||||
['chartreuse', '#7fff00'],
|
||||
['chocolate', '#d2691e'],
|
||||
['coral', '#ff7f50'],
|
||||
['cornflowerblue', '#6495ed'],
|
||||
['cornsilk', '#fff8dc'],
|
||||
['crimson', '#dc143c'],
|
||||
['cyan', '#00ffff'],
|
||||
['darkblue', '#00008b'],
|
||||
['darkcyan', '#008b8b'],
|
||||
['darkgoldenrod', '#b8860b'],
|
||||
['darkgray', '#a9a9a9'],
|
||||
['darkgrey', '#a9a9a9'],
|
||||
['darkgreen', '#006400'],
|
||||
['darkkhaki', '#bdb76b'],
|
||||
['darkmagenta', '#8b008b'],
|
||||
['darkolivegreen', '#556b2f'],
|
||||
['darkorange', '#ff8c00'],
|
||||
['darkorchid', '#9932cc'],
|
||||
['darkred', '#8b0000'],
|
||||
['darksalmon', '#e9967a'],
|
||||
['darkseagreen', '#8fbc8f'],
|
||||
['darkslateblue', '#483d8b'],
|
||||
['darkslategray', '#2f4f4f'],
|
||||
['darkslategrey', '#2f4f4f'],
|
||||
['darkturquoise', '#00ced1'],
|
||||
['darkviolet', '#9400d3'],
|
||||
['deeppink', '#ff1493'],
|
||||
['deepskyblue', '#00bfff'],
|
||||
['dimgray', '#696969'],
|
||||
['dimgrey', '#696969'],
|
||||
['dodgerblue', '#1e90ff'],
|
||||
['firebrick', '#b22222'],
|
||||
['floralwhite', '#fffaf0'],
|
||||
['forestgreen', '#228b22'],
|
||||
['fuchsia', '#ff00ff'],
|
||||
['gainsboro', '#dcdcdc'],
|
||||
['ghostwhite', '#f8f8ff'],
|
||||
['gold', '#ffd700'],
|
||||
['goldenrod', '#daa520'],
|
||||
['gray', '#808080'],
|
||||
['grey', '#808080'],
|
||||
['green', '#008000'],
|
||||
['greenyellow', '#adff2f'],
|
||||
['honeydew', '#f0fff0'],
|
||||
['hotpink', '#ff69b4'],
|
||||
['indianred', '#cd5c5c'],
|
||||
['indigo', '#4b0082'],
|
||||
['ivory', '#fffff0'],
|
||||
['khaki', '#f0e68c'],
|
||||
['lavender', '#e6e6fa'],
|
||||
['lavenderblush', '#fff0f5'],
|
||||
['lawngreen', '#7cfc00'],
|
||||
['lemonchiffon', '#fffacd'],
|
||||
['lightblue', '#add8e6'],
|
||||
['lightcoral', '#f08080'],
|
||||
['lightcyan', '#e0ffff'],
|
||||
['lightgoldenrodyellow', '#fafad2'],
|
||||
['lightgray', '#d3d3d3'],
|
||||
['lightgrey', '#d3d3d3'],
|
||||
['lightgreen', '#90ee90'],
|
||||
['lightpink', '#ffb6c1'],
|
||||
['lightsalmon', '#ffa07a'],
|
||||
['lightseagreen', '#20b2aa'],
|
||||
['lightskyblue', '#87cefa'],
|
||||
['lightslategray', '#778899'],
|
||||
['lightslategrey', '#778899'],
|
||||
['lightsteelblue', '#b0c4de'],
|
||||
['lightyellow', '#ffffe0'],
|
||||
['lime', '#00ff00'],
|
||||
['limegreen', '#32cd32'],
|
||||
['linen', '#faf0e6'],
|
||||
['magenta', '#ff00ff'],
|
||||
['maroon', '#800000'],
|
||||
['mediumaquamarine', '#66cdaa'],
|
||||
['mediumblue', '#0000cd'],
|
||||
['mediumorchid', '#ba55d3'],
|
||||
['mediumpurple', '#9370db'],
|
||||
['mediumseagreen', '#3cb371'],
|
||||
['mediumslateblue', '#7b68ee'],
|
||||
['mediumspringgreen', '#00fa9a'],
|
||||
['mediumturquoise', '#48d1cc'],
|
||||
['mediumvioletred', '#c71585'],
|
||||
['midnightblue', '#191970'],
|
||||
['mintcream', '#f5fffa'],
|
||||
['mistyrose', '#ffe4e1'],
|
||||
['moccasin', '#ffe4b5'],
|
||||
['navajowhite', '#ffdead'],
|
||||
['navy', '#000080'],
|
||||
['oldlace', '#fdf5e6'],
|
||||
['olive', '#808000'],
|
||||
['olivedrab', '#6b8e23'],
|
||||
['orange', '#ffa500'],
|
||||
['orangered', '#ff4500'],
|
||||
['orchid', '#da70d6'],
|
||||
['palegoldenrod', '#eee8aa'],
|
||||
['palegreen', '#98fb98'],
|
||||
['paleturquoise', '#afeeee'],
|
||||
['palevioletred', '#db7093'],
|
||||
['papayawhip', '#ffefd5'],
|
||||
['peachpuff', '#ffdab9'],
|
||||
['peru', '#cd853f'],
|
||||
['pink', '#ffc0cb'],
|
||||
['plum', '#dda0dd'],
|
||||
['powderblue', '#b0e0e6'],
|
||||
['purple', '#800080'],
|
||||
['rebeccapurple', '#663399'],
|
||||
['red', '#ff0000'],
|
||||
['rosybrown', '#bc8f8f'],
|
||||
['royalblue', '#4169e1'],
|
||||
['saddlebrown', '#8b4513'],
|
||||
['salmon', '#fa8072'],
|
||||
['sandybrown', '#f4a460'],
|
||||
['seagreen', '#2e8b57'],
|
||||
['seashell', '#fff5ee'],
|
||||
['sienna', '#a0522d'],
|
||||
['silver', '#c0c0c0'],
|
||||
['skyblue', '#87ceeb'],
|
||||
['slateblue', '#6a5acd'],
|
||||
['slategray', '#708090'],
|
||||
['slategrey', '#708090'],
|
||||
['snow', '#fffafa'],
|
||||
['springgreen', '#00ff7f'],
|
||||
['steelblue', '#4682b4'],
|
||||
['tan', '#d2b48c'],
|
||||
['teal', '#008080'],
|
||||
['thistle', '#d8bfd8'],
|
||||
['tomato', '#ff6347'],
|
||||
['turquoise', '#40e0d0'],
|
||||
['violet', '#ee82ee'],
|
||||
['wheat', '#f5deb3'],
|
||||
['white', '#ffffff'],
|
||||
['whitesmoke', '#f5f5f5'],
|
||||
['yellow', '#ffff00'],
|
||||
['yellowgreen', '#9acd32'],
|
||||
]);
|
||||
})(new Map([
|
||||
['transparent', {r: 0, g: 0, b: 0, a: 0, type: 'rgb'}],
|
||||
['aliceblue', {r: 240, g: 248, b: 255, type: 'hex'}],
|
||||
['antiquewhite', {r: 250, g: 235, b: 215, type: 'hex'}],
|
||||
['aqua', {r: 0, g: 255, b: 255, type: 'hex'}],
|
||||
['aquamarine', {r: 127, g: 255, b: 212, type: 'hex'}],
|
||||
['azure', {r: 240, g: 255, b: 255, type: 'hex'}],
|
||||
['beige', {r: 245, g: 245, b: 220, type: 'hex'}],
|
||||
['bisque', {r: 255, g: 228, b: 196, type: 'hex'}],
|
||||
['black', {r: 0, g: 0, b: 0, type: 'hex'}],
|
||||
['blanchedalmond', {r: 255, g: 235, b: 205, type: 'hex'}],
|
||||
['blue', {r: 0, g: 0, b: 255, type: 'hex'}],
|
||||
['blueviolet', {r: 138, g: 43, b: 226, type: 'hex'}],
|
||||
['brown', {r: 165, g: 42, b: 42, type: 'hex'}],
|
||||
['burlywood', {r: 222, g: 184, b: 135, type: 'hex'}],
|
||||
['cadetblue', {r: 95, g: 158, b: 160, type: 'hex'}],
|
||||
['chartreuse', {r: 127, g: 255, b: 0, type: 'hex'}],
|
||||
['chocolate', {r: 210, g: 105, b: 30, type: 'hex'}],
|
||||
['coral', {r: 255, g: 127, b: 80, type: 'hex'}],
|
||||
['cornflowerblue', {r: 100, g: 149, b: 237, type: 'hex'}],
|
||||
['cornsilk', {r: 255, g: 248, b: 220, type: 'hex'}],
|
||||
['crimson', {r: 220, g: 20, b: 60, type: 'hex'}],
|
||||
['cyan', {r: 0, g: 255, b: 255, type: 'hex'}],
|
||||
['darkblue', {r: 0, g: 0, b: 139, type: 'hex'}],
|
||||
['darkcyan', {r: 0, g: 139, b: 139, type: 'hex'}],
|
||||
['darkgoldenrod', {r: 184, g: 134, b: 11, type: 'hex'}],
|
||||
['darkgray', {r: 169, g: 169, b: 169, type: 'hex'}],
|
||||
['darkgrey', {r: 169, g: 169, b: 169, type: 'hex'}],
|
||||
['darkgreen', {r: 0, g: 100, b: 0, type: 'hex'}],
|
||||
['darkkhaki', {r: 189, g: 183, b: 107, type: 'hex'}],
|
||||
['darkmagenta', {r: 139, g: 0, b: 139, type: 'hex'}],
|
||||
['darkolivegreen', {r: 85, g: 107, b: 47, type: 'hex'}],
|
||||
['darkorange', {r: 255, g: 140, b: 0, type: 'hex'}],
|
||||
['darkorchid', {r: 153, g: 50, b: 204, type: 'hex'}],
|
||||
['darkred', {r: 139, g: 0, b: 0, type: 'hex'}],
|
||||
['darksalmon', {r: 233, g: 150, b: 122, type: 'hex'}],
|
||||
['darkseagreen', {r: 143, g: 188, b: 143, type: 'hex'}],
|
||||
['darkslateblue', {r: 72, g: 61, b: 139, type: 'hex'}],
|
||||
['darkslategray', {r: 47, g: 79, b: 79, type: 'hex'}],
|
||||
['darkslategrey', {r: 47, g: 79, b: 79, type: 'hex'}],
|
||||
['darkturquoise', {r: 0, g: 206, b: 209, type: 'hex'}],
|
||||
['darkviolet', {r: 148, g: 0, b: 211, type: 'hex'}],
|
||||
['deeppink', {r: 255, g: 20, b: 147, type: 'hex'}],
|
||||
['deepskyblue', {r: 0, g: 191, b: 255, type: 'hex'}],
|
||||
['dimgray', {r: 105, g: 105, b: 105, type: 'hex'}],
|
||||
['dimgrey', {r: 105, g: 105, b: 105, type: 'hex'}],
|
||||
['dodgerblue', {r: 30, g: 144, b: 255, type: 'hex'}],
|
||||
['firebrick', {r: 178, g: 34, b: 34, type: 'hex'}],
|
||||
['floralwhite', {r: 255, g: 250, b: 240, type: 'hex'}],
|
||||
['forestgreen', {r: 34, g: 139, b: 34, type: 'hex'}],
|
||||
['fuchsia', {r: 255, g: 0, b: 255, type: 'hex'}],
|
||||
['gainsboro', {r: 220, g: 220, b: 220, type: 'hex'}],
|
||||
['ghostwhite', {r: 248, g: 248, b: 255, type: 'hex'}],
|
||||
['gold', {r: 255, g: 215, b: 0, type: 'hex'}],
|
||||
['goldenrod', {r: 218, g: 165, b: 32, type: 'hex'}],
|
||||
['gray', {r: 128, g: 128, b: 128, type: 'hex'}],
|
||||
['grey', {r: 128, g: 128, b: 128, type: 'hex'}],
|
||||
['green', {r: 0, g: 128, b: 0, type: 'hex'}],
|
||||
['greenyellow', {r: 173, g: 255, b: 47, type: 'hex'}],
|
||||
['honeydew', {r: 240, g: 255, b: 240, type: 'hex'}],
|
||||
['hotpink', {r: 255, g: 105, b: 180, type: 'hex'}],
|
||||
['indianred', {r: 205, g: 92, b: 92, type: 'hex'}],
|
||||
['indigo', {r: 75, g: 0, b: 130, type: 'hex'}],
|
||||
['ivory', {r: 255, g: 255, b: 240, type: 'hex'}],
|
||||
['khaki', {r: 240, g: 230, b: 140, type: 'hex'}],
|
||||
['lavender', {r: 230, g: 230, b: 250, type: 'hex'}],
|
||||
['lavenderblush', {r: 255, g: 240, b: 245, type: 'hex'}],
|
||||
['lawngreen', {r: 124, g: 252, b: 0, type: 'hex'}],
|
||||
['lemonchiffon', {r: 255, g: 250, b: 205, type: 'hex'}],
|
||||
['lightblue', {r: 173, g: 216, b: 230, type: 'hex'}],
|
||||
['lightcoral', {r: 240, g: 128, b: 128, type: 'hex'}],
|
||||
['lightcyan', {r: 224, g: 255, b: 255, type: 'hex'}],
|
||||
['lightgoldenrodyellow', {r: 250, g: 250, b: 210, type: 'hex'}],
|
||||
['lightgray', {r: 211, g: 211, b: 211, type: 'hex'}],
|
||||
['lightgrey', {r: 211, g: 211, b: 211, type: 'hex'}],
|
||||
['lightgreen', {r: 144, g: 238, b: 144, type: 'hex'}],
|
||||
['lightpink', {r: 255, g: 182, b: 193, type: 'hex'}],
|
||||
['lightsalmon', {r: 255, g: 160, b: 122, type: 'hex'}],
|
||||
['lightseagreen', {r: 32, g: 178, b: 170, type: 'hex'}],
|
||||
['lightskyblue', {r: 135, g: 206, b: 250, type: 'hex'}],
|
||||
['lightslategray', {r: 119, g: 136, b: 153, type: 'hex'}],
|
||||
['lightslategrey', {r: 119, g: 136, b: 153, type: 'hex'}],
|
||||
['lightsteelblue', {r: 176, g: 196, b: 222, type: 'hex'}],
|
||||
['lightyellow', {r: 255, g: 255, b: 224, type: 'hex'}],
|
||||
['lime', {r: 0, g: 255, b: 0, type: 'hex'}],
|
||||
['limegreen', {r: 50, g: 205, b: 50, type: 'hex'}],
|
||||
['linen', {r: 250, g: 240, b: 230, type: 'hex'}],
|
||||
['magenta', {r: 255, g: 0, b: 255, type: 'hex'}],
|
||||
['maroon', {r: 128, g: 0, b: 0, type: 'hex'}],
|
||||
['mediumaquamarine', {r: 102, g: 205, b: 170, type: 'hex'}],
|
||||
['mediumblue', {r: 0, g: 0, b: 205, type: 'hex'}],
|
||||
['mediumorchid', {r: 186, g: 85, b: 211, type: 'hex'}],
|
||||
['mediumpurple', {r: 147, g: 112, b: 219, type: 'hex'}],
|
||||
['mediumseagreen', {r: 60, g: 179, b: 113, type: 'hex'}],
|
||||
['mediumslateblue', {r: 123, g: 104, b: 238, type: 'hex'}],
|
||||
['mediumspringgreen', {r: 0, g: 250, b: 154, type: 'hex'}],
|
||||
['mediumturquoise', {r: 72, g: 209, b: 204, type: 'hex'}],
|
||||
['mediumvioletred', {r: 199, g: 21, b: 133, type: 'hex'}],
|
||||
['midnightblue', {r: 25, g: 25, b: 112, type: 'hex'}],
|
||||
['mintcream', {r: 245, g: 255, b: 250, type: 'hex'}],
|
||||
['mistyrose', {r: 255, g: 228, b: 225, type: 'hex'}],
|
||||
['moccasin', {r: 255, g: 228, b: 181, type: 'hex'}],
|
||||
['navajowhite', {r: 255, g: 222, b: 173, type: 'hex'}],
|
||||
['navy', {r: 0, g: 0, b: 128, type: 'hex'}],
|
||||
['oldlace', {r: 253, g: 245, b: 230, type: 'hex'}],
|
||||
['olive', {r: 128, g: 128, b: 0, type: 'hex'}],
|
||||
['olivedrab', {r: 107, g: 142, b: 35, type: 'hex'}],
|
||||
['orange', {r: 255, g: 165, b: 0, type: 'hex'}],
|
||||
['orangered', {r: 255, g: 69, b: 0, type: 'hex'}],
|
||||
['orchid', {r: 218, g: 112, b: 214, type: 'hex'}],
|
||||
['palegoldenrod', {r: 238, g: 232, b: 170, type: 'hex'}],
|
||||
['palegreen', {r: 152, g: 251, b: 152, type: 'hex'}],
|
||||
['paleturquoise', {r: 175, g: 238, b: 238, type: 'hex'}],
|
||||
['palevioletred', {r: 219, g: 112, b: 147, type: 'hex'}],
|
||||
['papayawhip', {r: 255, g: 239, b: 213, type: 'hex'}],
|
||||
['peachpuff', {r: 255, g: 218, b: 185, type: 'hex'}],
|
||||
['peru', {r: 205, g: 133, b: 63, type: 'hex'}],
|
||||
['pink', {r: 255, g: 192, b: 203, type: 'hex'}],
|
||||
['plum', {r: 221, g: 160, b: 221, type: 'hex'}],
|
||||
['powderblue', {r: 176, g: 224, b: 230, type: 'hex'}],
|
||||
['purple', {r: 128, g: 0, b: 128, type: 'hex'}],
|
||||
['rebeccapurple', {r: 102, g: 51, b: 153, type: 'hex'}],
|
||||
['red', {r: 255, g: 0, b: 0, type: 'hex'}],
|
||||
['rosybrown', {r: 188, g: 143, b: 143, type: 'hex'}],
|
||||
['royalblue', {r: 65, g: 105, b: 225, type: 'hex'}],
|
||||
['saddlebrown', {r: 139, g: 69, b: 19, type: 'hex'}],
|
||||
['salmon', {r: 250, g: 128, b: 114, type: 'hex'}],
|
||||
['sandybrown', {r: 244, g: 164, b: 96, type: 'hex'}],
|
||||
['seagreen', {r: 46, g: 139, b: 87, type: 'hex'}],
|
||||
['seashell', {r: 255, g: 245, b: 238, type: 'hex'}],
|
||||
['sienna', {r: 160, g: 82, b: 45, type: 'hex'}],
|
||||
['silver', {r: 192, g: 192, b: 192, type: 'hex'}],
|
||||
['skyblue', {r: 135, g: 206, b: 235, type: 'hex'}],
|
||||
['slateblue', {r: 106, g: 90, b: 205, type: 'hex'}],
|
||||
['slategray', {r: 112, g: 128, b: 144, type: 'hex'}],
|
||||
['slategrey', {r: 112, g: 128, b: 144, type: 'hex'}],
|
||||
['snow', {r: 255, g: 250, b: 250, type: 'hex'}],
|
||||
['springgreen', {r: 0, g: 255, b: 127, type: 'hex'}],
|
||||
['steelblue', {r: 70, g: 130, b: 180, type: 'hex'}],
|
||||
['tan', {r: 210, g: 180, b: 140, type: 'hex'}],
|
||||
['teal', {r: 0, g: 128, b: 128, type: 'hex'}],
|
||||
['thistle', {r: 216, g: 191, b: 216, type: 'hex'}],
|
||||
['tomato', {r: 255, g: 99, b: 71, type: 'hex'}],
|
||||
['turquoise', {r: 64, g: 224, b: 208, type: 'hex'}],
|
||||
['violet', {r: 238, g: 130, b: 238, type: 'hex'}],
|
||||
['wheat', {r: 245, g: 222, b: 179, type: 'hex'}],
|
||||
['white', {r: 255, g: 255, b: 255, type: 'hex'}],
|
||||
['whitesmoke', {r: 245, g: 245, b: 245, type: 'hex'}],
|
||||
['yellow', {r: 255, g: 255, b: 0, type: 'hex'}],
|
||||
['yellowgreen', {r: 154, g: 205, b: 50, type: 'hex'}],
|
||||
]));
|
||||
|
|
|
@ -3503,7 +3503,7 @@ self.parserlib = (() => {
|
|||
do {
|
||||
this._ws();
|
||||
if ((t = stream.get(true)).type === Tokens.IDENT) {
|
||||
ids.push(t.value);
|
||||
ids.push(this._layerName(t));
|
||||
this._ws();
|
||||
t = stream.get(true);
|
||||
}
|
||||
|
@ -3521,6 +3521,16 @@ self.parserlib = (() => {
|
|||
this._ws();
|
||||
}
|
||||
|
||||
_layerName(start) {
|
||||
let res = '';
|
||||
const stream = this._tokenStream;
|
||||
for (let t; (t = start || stream.match(Tokens.IDENT));) {
|
||||
res += t.value + (stream.match(Tokens.DOT) ? '.' : '');
|
||||
start = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
_stylesheet() {
|
||||
const stream = this._tokenStream;
|
||||
this.fire('startstylesheet');
|
||||
|
@ -3590,7 +3600,7 @@ self.parserlib = (() => {
|
|||
this._ws();
|
||||
t = stream.get(true);
|
||||
if (/^layer(\()?$/i.test(t.value)) {
|
||||
layer = RegExp.$1 ? stream.mustMatch(Tokens.IDENT) : '';
|
||||
layer = RegExp.$1 ? this._layerName() : '';
|
||||
if (layer) stream.mustMatch(Tokens.RPAREN);
|
||||
this._ws();
|
||||
t = stream.get(true);
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
// "Delete" item in context menu for browsers that don't have it
|
||||
'editor.contextDelete': false,
|
||||
'editor.selectByTokens': true,
|
||||
|
||||
'editor.arrowKeysTraverse': true,
|
||||
'editor.appliesToLineWidget': true, // show applies-to line widget on the editor
|
||||
'editor.autosaveDraft': 10, // seconds
|
||||
'editor.livePreview': true,
|
||||
|
|
7082
package-lock.json
generated
7082
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -27,7 +27,7 @@
|
|||
"glob": "^8.0.3",
|
||||
"node-fetch": "^2.6.7",
|
||||
"sync-version": "^1.0.1",
|
||||
"web-ext": "^6.8.0"
|
||||
"web-ext": "^7.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint \"**/*.js\" --cache",
|
||||
|
|
|
@ -98,6 +98,10 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template data-id="writeForFrames">
|
||||
<div id="write-for-frames" tabindex="0"><iframe>...</div>
|
||||
</template>
|
||||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/msg.js"></script>
|
||||
<script src="js/toolbox.js"></script>
|
||||
|
@ -143,7 +147,6 @@
|
|||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
<div>U</div>
|
||||
</label>
|
||||
<a id="write-for-frames" title="‹iframe›..." tabindex="0" hidden></a>
|
||||
<span id="write-style-for" i18n="writeStyleFor"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -491,6 +491,7 @@ a:hover .svg-icon {
|
|||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
#write-for-frames::before,
|
||||
.match .match::before {
|
||||
content: "";
|
||||
width: .25rem;
|
||||
|
@ -510,33 +511,18 @@ a:hover .svg-icon {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#write-for-frames:not([hidden]) {
|
||||
position: relative;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
display: inline-block;
|
||||
margin: 0 2px 2px;
|
||||
--dash: transparent 2px, currentColor 2px, currentColor 3px, transparent 3px;
|
||||
background: linear-gradient(var(--dash)), linear-gradient(90deg, var(--dash));
|
||||
#write-for-frames {
|
||||
cursor: pointer;
|
||||
margin: 0 0 -.25em .5rem;
|
||||
color: var(--c50);
|
||||
transition: color .2s;
|
||||
}
|
||||
#write-for-frames:hover {
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
#write-for-frames.expanded {
|
||||
background: linear-gradient(var(--dash));
|
||||
}
|
||||
|
||||
#write-for-frames::after {
|
||||
position: absolute;
|
||||
margin: -2px;
|
||||
border: 1px solid currentColor;
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#write-for-frames:not(.expanded) ~ .match:not([data-frame-id="0"]),
|
||||
#write-for-frames:not(.expanded) ~ .match .match {
|
||||
#write-style:not(.expanded) .match:not([data-frame-id="0"]),
|
||||
#write-style:not(.expanded) .match .match {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -144,10 +144,15 @@ async function initPopup(frames) {
|
|||
}
|
||||
|
||||
frames.forEach(createWriterElement);
|
||||
Object.assign($('#write-for-frames'), {
|
||||
onclick: e => e.currentTarget.classList.toggle('expanded'),
|
||||
hidden: frames.length < 2 || !$('.match .match:not(.dupe)'),
|
||||
});
|
||||
|
||||
if (frames.length > 1 && $('.match .match:not(.dupe)')) {
|
||||
$('#write-style').append(Object.assign(t.template.writeForFrames, {
|
||||
onclick() {
|
||||
this.remove();
|
||||
$('#write-style').classList.add('expanded');
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
const isStore = tabURL.startsWith(URLS.browserWebStore);
|
||||
if (isStore && !FIREFOX) {
|
||||
|
|
|
@ -134,6 +134,10 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.search-result[data-installed] {
|
||||
box-shadow: 1px 1px 10px darkcyan;
|
||||
border-color: darkcyan;
|
||||
}
|
||||
.search-result:not([data-installed]) .search-result-actions {
|
||||
opacity: 0;
|
||||
transition: opacity .5s;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* global $entry tabURL */// popup.js
|
||||
/* global API */// msg.js
|
||||
/* global Events */
|
||||
/* global FIREFOX URLS debounce download stringAsRegExp tryRegExp tryURL */// toolbox.js
|
||||
/* global FIREFOX URLS debounce download isEmptyObj stringAsRegExp tryRegExp tryURL */// toolbox.js
|
||||
/* global prefs */
|
||||
/* global t */// localization.js
|
||||
'use strict';
|
||||
|
@ -27,7 +27,7 @@
|
|||
/**
|
||||
* @typedef IndexEntry
|
||||
* @prop {'uso' | 'uso-android'} f - format
|
||||
* @prop {Number} i - id
|
||||
* @prop {Number} i - id, later replaced with string like `uso-123`
|
||||
* @prop {string} n - name
|
||||
* @prop {string} c - category
|
||||
* @prop {Number} u - updatedTime
|
||||
|
@ -39,8 +39,8 @@
|
|||
* @prop {string} sn - screenshotName
|
||||
* @prop {boolean} sa - screenshotArchived
|
||||
*
|
||||
* @prop {boolean} _installed
|
||||
* @prop {number} _installedStyleId
|
||||
* @prop {number} _styleId - installed style id
|
||||
* @prop {boolean} _styleVars - installed style has vars
|
||||
* @prop {number} _year
|
||||
*/
|
||||
/** @type IndexEntry[] */
|
||||
|
@ -73,6 +73,7 @@
|
|||
const entry = el.closest(RESULT_SEL);
|
||||
return {entry, result: entry && entry._result};
|
||||
};
|
||||
const rid2id = rid => rid.split('-')[1];
|
||||
Events.searchInline = () => {
|
||||
calcCategory();
|
||||
ready = start();
|
||||
|
@ -158,18 +159,22 @@
|
|||
|
||||
window.on('styleDeleted', ({detail: {style: {id}}}) => {
|
||||
restoreScrollPosition();
|
||||
const result = results.find(r => r._installedStyleId === id);
|
||||
if (result) {
|
||||
API.uso.pingback(result.i, false);
|
||||
renderActionButtons(result.i, -1);
|
||||
const r = results.find(r => r._styleId === id);
|
||||
if (r) {
|
||||
if (r.f) API.uso.pingback(rid2id(r.i), false);
|
||||
delete r._styleId;
|
||||
renderActionButtons(r.i);
|
||||
}
|
||||
});
|
||||
|
||||
window.on('styleAdded', async ({detail: {style}}) => {
|
||||
restoreScrollPosition();
|
||||
const id = calcId(style) || calcId(await API.styles.get(style.id));
|
||||
if (id && results.find(r => r.i === id)) {
|
||||
renderActionButtons(id, style.id);
|
||||
const ri = await API.styles.getRemoteInfo(style.id);
|
||||
const r = ri && results.find(r => ri[0] === r.i);
|
||||
if (r) {
|
||||
r._styleId = style.id;
|
||||
r._styleVars = ri[1];
|
||||
renderActionButtons(ri[0]);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -209,9 +214,10 @@
|
|||
results = await search({retry});
|
||||
}
|
||||
if (results.length) {
|
||||
const installedStyles = await API.styles.getAll();
|
||||
const allSupportedIds = new Set(installedStyles.map(calcId));
|
||||
results = results.filter(r => !allSupportedIds.has(r.i));
|
||||
const info = await API.styles.getRemoteInfo();
|
||||
for (const r of results) {
|
||||
[r._styleId, r._styleVars] = info[r.i] || [];
|
||||
}
|
||||
}
|
||||
if (!keepYears) resultsAllYears = results;
|
||||
renderYears();
|
||||
|
@ -330,7 +336,7 @@
|
|||
function createSearchResultNode(result) {
|
||||
const entry = t.template.searchResult.cloneNode(true);
|
||||
const {
|
||||
i: id,
|
||||
i: rid,
|
||||
n: name,
|
||||
r: rating,
|
||||
u: updateTime,
|
||||
|
@ -342,7 +348,8 @@
|
|||
sn: shot,
|
||||
f: fmt,
|
||||
} = entry._result = result;
|
||||
entry.id = RESULT_ID_PREFIX + id;
|
||||
const id = rid2id(rid);
|
||||
entry.id = RESULT_ID_PREFIX + rid;
|
||||
// title
|
||||
Object.assign($('.search-result-title', entry), {
|
||||
onclick: Events.openURLandHide,
|
||||
|
@ -421,22 +428,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
function renderActionButtons(entry, installedId) {
|
||||
if (Number(entry)) {
|
||||
function renderActionButtons(entry) {
|
||||
if (typeof entry !== 'object') {
|
||||
entry = $('#' + RESULT_ID_PREFIX + entry);
|
||||
}
|
||||
if (!entry) return;
|
||||
const result = entry._result;
|
||||
if (typeof installedId === 'number') {
|
||||
result._installed = installedId > 0;
|
||||
result._installedStyleId = installedId;
|
||||
}
|
||||
const isInstalled = result._installed;
|
||||
const installedId = result._styleId;
|
||||
const isInstalled = installedId > 0; // must be boolean for comparisons below
|
||||
const status = $('.search-result-status', entry).textContent =
|
||||
isInstalled ? t('clickToUninstall') :
|
||||
entry.dataset.noImage != null ? t('installButton') :
|
||||
'';
|
||||
const notMatching = installedId > 0 && !$entry(installedId);
|
||||
const notMatching = isInstalled && !$entry(installedId);
|
||||
if (notMatching !== entry.classList.contains('not-matching')) {
|
||||
entry.classList.toggle('not-matching');
|
||||
if (notMatching) {
|
||||
|
@ -456,6 +460,7 @@
|
|||
disabled: notMatching,
|
||||
});
|
||||
toggleDataset(entry, 'installed', isInstalled);
|
||||
toggleDataset(entry, 'customizable', result._styleVars);
|
||||
}
|
||||
|
||||
function renderFullInfo(entry, style) {
|
||||
|
@ -469,17 +474,20 @@
|
|||
textContent: description,
|
||||
title: description,
|
||||
});
|
||||
vars = !isEmptyObj(vars);
|
||||
entry._result._styleVars = vars;
|
||||
toggleDataset(entry, 'customizable', vars);
|
||||
}
|
||||
|
||||
function configure() {
|
||||
const styleEntry = $entry($resultEntry(this).result._installedStyleId);
|
||||
const styleEntry = $entry($resultEntry(this).result._styleId);
|
||||
Events.configure.call(this, {target: styleEntry});
|
||||
}
|
||||
|
||||
async function install() {
|
||||
const {entry, result} = $resultEntry(this);
|
||||
const {i: id, f: fmt} = result;
|
||||
const {f: fmt} = result;
|
||||
const id = rid2id(result.i);
|
||||
const installButton = $('.search-result-install', entry);
|
||||
|
||||
showSpinner(entry);
|
||||
|
@ -507,7 +515,7 @@
|
|||
function uninstall() {
|
||||
const {entry, result} = $resultEntry(this);
|
||||
saveScrollPosition(entry);
|
||||
API.styles.delete(result._installedStyleId);
|
||||
API.styles.delete(result._styleId);
|
||||
}
|
||||
|
||||
function saveScrollPosition(entry) {
|
||||
|
@ -553,10 +561,11 @@
|
|||
async function fetchIndex() {
|
||||
const timer = setTimeout(showSpinner, BUSY_DELAY, dom.list);
|
||||
const jobs = [
|
||||
[INDEX_URL, json => json.filter(entry => entry.f === 'uso')],
|
||||
[USW_INDEX_URL, json => json.data],
|
||||
].map(async ([url, transform]) => {
|
||||
[INDEX_URL, 'uso', json => json.filter(v => v.f === 'uso')],
|
||||
[USW_INDEX_URL, 'usw', json => json.data],
|
||||
].map(async ([url, prefix, transform]) => {
|
||||
const res = transform(await download(url, {responseType: 'json'}));
|
||||
for (const v of res) v.i = `${prefix}-${v.i}`;
|
||||
index = index ? index.concat(res) : res;
|
||||
if (index !== res) ready = ready.then(start);
|
||||
});
|
||||
|
@ -607,17 +616,4 @@
|
|||
: b[order] - a[order]
|
||||
) || b.t - a.t;
|
||||
}
|
||||
|
||||
function calcUsoId({md5Url: m, updateUrl}) {
|
||||
return Number(m && m.match(/\d+|$/)[0]) ||
|
||||
URLS.extractUsoArchiveId(updateUrl);
|
||||
}
|
||||
|
||||
function calcUswId({updateUrl}) {
|
||||
return URLS.extractUSwId(updateUrl) || 0;
|
||||
}
|
||||
|
||||
function calcId(style) {
|
||||
return calcUsoId(style) || calcUswId(style);
|
||||
}
|
||||
})();
|
||||
|
|
Loading…
Reference in New Issue
Block a user