Merge branch 'master' of https://github.com/openstyles/stylus into dev-sync
This commit is contained in:
commit
37ebcf0593
|
@ -1,10 +1,11 @@
|
||||||
/* global regExpTester debounce messageBox CodeMirror template colorMimicry msg
|
/* global regExpTester debounce messageBox CodeMirror template colorMimicry msg
|
||||||
$ $create t prefs tryCatch */
|
$ $create t prefs tryCatch deepEqual */
|
||||||
/* exported createAppliesToLineWidget */
|
/* exported createAppliesToLineWidget */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function createAppliesToLineWidget(cm) {
|
function createAppliesToLineWidget(cm) {
|
||||||
const THROTTLE_DELAY = 400;
|
const THROTTLE_DELAY = 400;
|
||||||
|
const RX_SPACE = /(?:\s+|\/\*)+/y;
|
||||||
let TPL, EVENTS, CLICK_ROUTE;
|
let TPL, EVENTS, CLICK_ROUTE;
|
||||||
let widgets = [];
|
let widgets = [];
|
||||||
let fromLine, toLine, actualStyle;
|
let fromLine, toLine, actualStyle;
|
||||||
|
@ -172,6 +173,10 @@ function createAppliesToLineWidget(cm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRuntimeMessage(msg) {
|
function onRuntimeMessage(msg) {
|
||||||
|
if (msg.reason === 'editPreview' && !$(`#stylus-${msg.style.id}`)) {
|
||||||
|
// no style element with this id means the style doesn't apply to the editor URL
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (msg.style || msg.styles ||
|
if (msg.style || msg.styles ||
|
||||||
msg.prefs && 'disableAll' in msg.prefs ||
|
msg.prefs && 'disableAll' in msg.prefs ||
|
||||||
msg.method === 'styleDeleted') {
|
msg.method === 'styleDeleted') {
|
||||||
|
@ -294,21 +299,15 @@ function createAppliesToLineWidget(cm) {
|
||||||
const toPos = {line: widgets[j] ? widgets[j].line.lineNo() : toLine + 1, ch: 0};
|
const toPos = {line: widgets[j] ? widgets[j].line.lineNo() : toLine + 1, ch: 0};
|
||||||
|
|
||||||
// calc index->pos lookup table
|
// calc index->pos lookup table
|
||||||
let line = 0;
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
let fromIndex, toIndex;
|
const lineIndexes = [0];
|
||||||
const lineIndexes = [index];
|
cm.doc.iter(0, toPos.line + 1, ({text}) => {
|
||||||
cm.doc.iter(({text}) => {
|
|
||||||
fromIndex = line === fromPos.line ? index : fromIndex;
|
|
||||||
lineIndexes.push((index += text.length + 1));
|
lineIndexes.push((index += text.length + 1));
|
||||||
line++;
|
|
||||||
toIndex = line >= toPos.line ? index : toIndex;
|
|
||||||
return toIndex;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// splice
|
// splice
|
||||||
i = Math.max(0, i);
|
i = Math.max(0, i);
|
||||||
widgets.splice(i, 0, ...createWidgets(fromIndex, toIndex, widgets.splice(i, j - i), lineIndexes));
|
widgets.splice(i, 0, ...createWidgets(fromPos, toPos, widgets.splice(i, j - i), lineIndexes));
|
||||||
|
|
||||||
fromLine = null;
|
fromLine = null;
|
||||||
toLine = null;
|
toLine = null;
|
||||||
|
@ -317,12 +316,17 @@ function createAppliesToLineWidget(cm) {
|
||||||
function *createWidgets(start, end, removed, lineIndexes) {
|
function *createWidgets(start, end, removed, lineIndexes) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let itemHeight;
|
let itemHeight;
|
||||||
for (const section of findAppliesTo(start, end)) {
|
for (const section of findAppliesTo(start, end, lineIndexes)) {
|
||||||
let removedWidget = removed[i];
|
let removedWidget = removed[i];
|
||||||
while (removedWidget && removedWidget.line.lineNo() < section.pos.line) {
|
while (removedWidget && removedWidget.line.lineNo() < section.pos.line) {
|
||||||
clearWidget(removed[i]);
|
clearWidget(removed[i]);
|
||||||
removedWidget = removed[++i];
|
removedWidget = removed[++i];
|
||||||
}
|
}
|
||||||
|
if (removedWidget && deepEqual(removedWidget.node.__applies, section.applies, ['mark'])) {
|
||||||
|
yield removedWidget;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const a of section.applies) {
|
for (const a of section.applies) {
|
||||||
setupApplyMarkers(a, lineIndexes);
|
setupApplyMarkers(a, lineIndexes);
|
||||||
}
|
}
|
||||||
|
@ -488,40 +492,84 @@ function createAppliesToLineWidget(cm) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function *findAppliesTo(posStart, posEnd) {
|
function *findAppliesTo(posStart, posEnd, lineIndexes) {
|
||||||
const text = cm.getValue();
|
const funcRe = /^(url|url-prefix|domain|regexp)$/i;
|
||||||
const re = /^[\t ]*@-moz-document[\s\n]+/gm;
|
let pos;
|
||||||
const applyRe = new RegExp([
|
const eatToken = sticky => {
|
||||||
/(?:\/\*[\s\S]*?(?:\*\/\s*|$))*/,
|
if (!sticky) skipSpace(pos, posEnd);
|
||||||
/(url|url-prefix|domain|regexp)/,
|
pos.ch++;
|
||||||
/\(((['"])(?:\\\\|\\\n|\\\3|[^\n])*?\3|[^)\n]*)\)\s*(,\s*)?/,
|
const token = cm.getTokenAt(pos, true);
|
||||||
].map(rx => rx.source).join(''), 'giy');
|
pos.ch = token.end;
|
||||||
let match;
|
return CodeMirror.cmpPos(pos, posEnd) <= 0 ? token : {};
|
||||||
re.lastIndex = posStart;
|
};
|
||||||
while ((match = re.exec(text))) {
|
const docCur = cm.getSearchCursor('@-moz-document', posStart);
|
||||||
if (match.index >= posEnd) {
|
while (docCur.findNext() &&
|
||||||
return;
|
CodeMirror.cmpPos(docCur.pos.to, posEnd) <= 0) {
|
||||||
}
|
// CM can be nitpicky at token boundary so we'll check the next character
|
||||||
|
const safePos = {line: docCur.pos.from.line, ch: docCur.pos.from.ch + 1};
|
||||||
|
if (/\b(string|comment)\b/.test(cm.getTokenTypeAt(safePos))) continue;
|
||||||
const applies = [];
|
const applies = [];
|
||||||
let m;
|
pos = docCur.pos.to;
|
||||||
applyRe.lastIndex = re.lastIndex;
|
do {
|
||||||
while ((m = applyRe.exec(text))) {
|
skipSpace(pos, posEnd);
|
||||||
|
const funcIndex = lineIndexes[pos.line] + pos.ch;
|
||||||
|
const func = eatToken().string;
|
||||||
|
// no space allowed before the opening parenthesis
|
||||||
|
if (!funcRe.test(func) || eatToken(true).string !== '(') break;
|
||||||
|
const url = eatToken();
|
||||||
|
if (url.type !== 'string' || eatToken().string !== ')') break;
|
||||||
|
const unquotedUrl = unquote(url.string);
|
||||||
const apply = createApply(
|
const apply = createApply(
|
||||||
m.index,
|
funcIndex,
|
||||||
m[1],
|
func,
|
||||||
unquote(m[2]),
|
unquotedUrl,
|
||||||
unquote(m[2]) !== m[2]
|
unquotedUrl !== url.string
|
||||||
);
|
);
|
||||||
applies.push(apply);
|
applies.push(apply);
|
||||||
re.lastIndex = applyRe.lastIndex;
|
} while (eatToken().string === ',');
|
||||||
}
|
|
||||||
yield {
|
yield {
|
||||||
pos: cm.posFromIndex(match.index),
|
pos: docCur.pos.from,
|
||||||
applies
|
applies
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function skipSpace(pos, posEnd) {
|
||||||
|
let {ch, line} = pos;
|
||||||
|
let lookForEnd;
|
||||||
|
line--;
|
||||||
|
cm.doc.iter(pos.line, posEnd.line + 1, ({text}) => {
|
||||||
|
line++;
|
||||||
|
while (true) {
|
||||||
|
if (lookForEnd) {
|
||||||
|
ch = text.indexOf('*/', ch) + 1;
|
||||||
|
if (!ch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ch++;
|
||||||
|
lookForEnd = false;
|
||||||
|
}
|
||||||
|
// EOL is a whitespace so we'll check the next line
|
||||||
|
if (ch >= text.length) {
|
||||||
|
ch = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RX_SPACE.lastIndex = ch;
|
||||||
|
const m = RX_SPACE.exec(text);
|
||||||
|
if (!m) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ch += m[0].length;
|
||||||
|
lookForEnd = m[0].includes('/*');
|
||||||
|
if (ch < text.length && !lookForEnd) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
pos.line = line;
|
||||||
|
pos.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
function unquote(s) {
|
function unquote(s) {
|
||||||
const first = s.charAt(0);
|
const first = s.charAt(0);
|
||||||
return (first === '"' || first === "'") && s.endsWith(first) ? s.slice(1, -1) : s;
|
return (first === '"' || first === "'") && s.endsWith(first) ? s.slice(1, -1) : s;
|
||||||
|
|
|
@ -242,6 +242,23 @@
|
||||||
CodeMirror.commands[name] = (...args) => editor[name](...args);
|
CodeMirror.commands[name] = (...args) => editor[name](...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// speedup: reuse the old folding marks
|
||||||
|
// TODO: remove when https://github.com/codemirror/CodeMirror/pull/6010 is shipped in /vendor
|
||||||
|
const {setGutterMarker} = CodeMirror.prototype;
|
||||||
|
CodeMirror.prototype.setGutterMarker = function (line, gutterID, value) {
|
||||||
|
const o = this.state.foldGutter.options;
|
||||||
|
if (typeof o.indicatorOpen === 'string' ||
|
||||||
|
typeof o.indicatorFolded === 'string') {
|
||||||
|
const old = line.gutterMarkers && line.gutterMarkers[gutterID];
|
||||||
|
// old className can contain other names set by CodeMirror so we'll use classList
|
||||||
|
if (old && value && old.classList.contains(value.className) ||
|
||||||
|
!old && !value) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return setGutterMarker.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
// CodeMirror convenience commands
|
// CodeMirror convenience commands
|
||||||
Object.assign(CodeMirror.commands, {
|
Object.assign(CodeMirror.commands, {
|
||||||
toggleEditorFocus,
|
toggleEditorFocus,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* exported getActiveTab onTabReady stringAsRegExp getTabRealURL openURL
|
/* exported getActiveTab onTabReady stringAsRegExp getTabRealURL openURL
|
||||||
getStyleWithNoCode tryRegExp sessionStorageHash download
|
getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual
|
||||||
closeCurrentTab capitalize */
|
closeCurrentTab capitalize */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ const VIVALDI = Boolean(chrome.app) && navigator.userAgent.includes('Vivaldi');
|
||||||
// const ANDROID = !chrome.windows;
|
// const ANDROID = !chrome.windows;
|
||||||
let FIREFOX = !chrome.app && parseFloat(navigator.userAgent.match(/\bFirefox\/(\d+\.\d+)|$/)[1]);
|
let FIREFOX = !chrome.app && parseFloat(navigator.userAgent.match(/\bFirefox\/(\d+\.\d+)|$/)[1]);
|
||||||
|
|
||||||
|
// see PR #781
|
||||||
|
const CHROME_HAS_BORDER_BUG = CHROME >= 3167 && CHROME <= 3704;
|
||||||
|
|
||||||
if (!CHROME && !chrome.browserAction.openPopup) {
|
if (!CHROME && !chrome.browserAction.openPopup) {
|
||||||
// in FF pre-57 legacy addons can override useragent so we assume the worst
|
// in FF pre-57 legacy addons can override useragent so we assume the worst
|
||||||
// until we know for sure in the async getBrowserInfo()
|
// until we know for sure in the async getBrowserInfo()
|
||||||
|
@ -357,6 +360,31 @@ function deepCopy(obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function deepEqual(a, b, ignoredKeys) {
|
||||||
|
if (!a || !b) return a === b;
|
||||||
|
const type = typeof a;
|
||||||
|
if (type !== typeof b) return false;
|
||||||
|
if (type !== 'object') return a === b;
|
||||||
|
if (Array.isArray(a)) {
|
||||||
|
return Array.isArray(b) &&
|
||||||
|
a.length === b.length &&
|
||||||
|
a.every((v, i) => deepEqual(v, b[i], ignoredKeys));
|
||||||
|
}
|
||||||
|
for (const key in a) {
|
||||||
|
if (!Object.hasOwnProperty.call(a, key) ||
|
||||||
|
ignoredKeys && ignoredKeys.includes(key)) continue;
|
||||||
|
if (!Object.hasOwnProperty.call(b, key)) return false;
|
||||||
|
if (!deepEqual(a[key], b[key], ignoredKeys)) return false;
|
||||||
|
}
|
||||||
|
for (const key in b) {
|
||||||
|
if (!Object.hasOwnProperty.call(b, key) ||
|
||||||
|
ignoredKeys && ignoredKeys.includes(key)) continue;
|
||||||
|
if (!Object.hasOwnProperty.call(a, key)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function sessionStorageHash(name) {
|
function sessionStorageHash(name) {
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
<span></span>
|
<span></span>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="chromium-only">
|
<label class="chromium-only chrome-no-popup-border">
|
||||||
<span i18n-text="popupBorders" i18n-title="popupBordersTooltip"></span>
|
<span i18n-text="popupBorders" i18n-title="popupBordersTooltip"></span>
|
||||||
<span class="onoffswitch">
|
<span class="onoffswitch">
|
||||||
<input type="checkbox" id="popup.borders" class="slider">
|
<input type="checkbox" id="popup.borders" class="slider">
|
||||||
|
|
|
@ -17,6 +17,7 @@ body {
|
||||||
min-width: 480px;
|
min-width: 480px;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports (-moz-appearance:none) {
|
@supports (-moz-appearance:none) {
|
||||||
|
@ -32,7 +33,8 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.firefox .chromium-only {
|
.firefox .chromium-only,
|
||||||
|
.chromium-only.chrome-no-popup-border {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* global messageBox msg setupLivePrefs enforceInputRange
|
/* global messageBox msg setupLivePrefs enforceInputRange
|
||||||
$ $$ $create $createLink
|
$ $$ $create $createLink
|
||||||
FIREFOX OPERA CHROME URLS openURL prefs t API ignoreChromeError capitalize */
|
FIREFOX OPERA CHROME URLS openURL prefs t API ignoreChromeError
|
||||||
|
CHROME_HAS_BORDER_BUG capitalize */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
setupLivePrefs();
|
setupLivePrefs();
|
||||||
|
@ -8,6 +9,13 @@ setupRadioButtons();
|
||||||
enforceInputRange($('#popupWidth'));
|
enforceInputRange($('#popupWidth'));
|
||||||
setTimeout(splitLongTooltips);
|
setTimeout(splitLongTooltips);
|
||||||
|
|
||||||
|
if (CHROME_HAS_BORDER_BUG) {
|
||||||
|
const borderOption = $('.chrome-no-popup-border');
|
||||||
|
if (borderOption) {
|
||||||
|
borderOption.classList.remove('chrome-no-popup-border');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// collapse #advanced block in Chrome pre-66 (classic chrome://extensions UI)
|
// collapse #advanced block in Chrome pre-66 (classic chrome://extensions UI)
|
||||||
if (!FIREFOX && !OPERA && CHROME < 3343) {
|
if (!FIREFOX && !OPERA && CHROME < 3343) {
|
||||||
const block = $('#advanced');
|
const block = $('#advanced');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* global configDialog hotkeys onTabReady msg
|
/* global configDialog hotkeys onTabReady msg
|
||||||
getActiveTab FIREFOX getTabRealURL URLS API onDOMready $ $$ prefs CHROME
|
getActiveTab FIREFOX getTabRealURL URLS API onDOMready $ $$ prefs CHROME
|
||||||
setupLivePrefs template t $create tWordBreak animateElement
|
setupLivePrefs template t $create tWordBreak animateElement
|
||||||
tryJSONparse debounce */
|
tryJSONparse debounce CHROME_HAS_BORDER_BUG */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -42,7 +42,10 @@ prefs.subscribe(['popup.stylesFirst'], (key, stylesFirst) => {
|
||||||
document.body.insertBefore(installed, before);
|
document.body.insertBefore(installed, before);
|
||||||
});
|
});
|
||||||
prefs.subscribe(['popupWidth'], (key, value) => setPopupWidth(value));
|
prefs.subscribe(['popupWidth'], (key, value) => setPopupWidth(value));
|
||||||
|
|
||||||
|
if (CHROME_HAS_BORDER_BUG) {
|
||||||
prefs.subscribe(['popup.borders'], (key, value) => toggleSideBorders(value));
|
prefs.subscribe(['popup.borders'], (key, value) => toggleSideBorders(value));
|
||||||
|
}
|
||||||
|
|
||||||
function onRuntimeMessage(msg) {
|
function onRuntimeMessage(msg) {
|
||||||
switch (msg.method) {
|
switch (msg.method) {
|
||||||
|
@ -68,7 +71,7 @@ function setPopupWidth(width = prefs.get('popupWidth')) {
|
||||||
function toggleSideBorders(state = prefs.get('popup.borders')) {
|
function toggleSideBorders(state = prefs.get('popup.borders')) {
|
||||||
// runs before <body> is parsed
|
// runs before <body> is parsed
|
||||||
const style = document.documentElement.style;
|
const style = document.documentElement.style;
|
||||||
if (CHROME >= 3167 && state) {
|
if (CHROME_HAS_BORDER_BUG && state) {
|
||||||
style.cssText +=
|
style.cssText +=
|
||||||
'border-left: 2px solid white !important;' +
|
'border-left: 2px solid white !important;' +
|
||||||
'border-right: 2px solid white !important;';
|
'border-right: 2px solid white !important;';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user