Add: a draggable list to customize injection order (#1364)
+ implement messageBox.close() + fix require() with root urls in /dir/page.html + limit messageBox focus shift to config-dialog + flatten vendor dirs and simplify build-vendor: + replace the unicode symbol with ASCII `->` + flatten dirs by default to simplify writing the rules and improve their readability + rename and sort functions in the order they run + use `node-fetch` instead of the gargantuan `make-fetch-happen` + use `glob` which is already installed by other deps Co-authored-by: tophf <tophf@gmx.com>
This commit is contained in:
parent
8ddeef221b
commit
ddc09f3511
|
@ -1667,6 +1667,14 @@
|
|||
"styleIncludeLabel": {
|
||||
"message": "Custom included sites"
|
||||
},
|
||||
"styleInjectionOrder": {
|
||||
"message": "Style injection order",
|
||||
"description": "Tooltip for the button in the manager to open the dialog and also the title of this dialog"
|
||||
},
|
||||
"styleInjectionOrderHint": {
|
||||
"message": "Drag'n'drop a style to change its position. Styles are injected sequentially in the order shown below so a style further down the list can override the earlier styles.",
|
||||
"description": "Hint in the injection order dialog in the manager"
|
||||
},
|
||||
"styleExcludeLabel": {
|
||||
"message": "Custom excluded sites"
|
||||
},
|
||||
|
|
|
@ -59,6 +59,7 @@ const styleMan = (() => {
|
|||
const DELETE_IF_NULL = ['id', 'customName', 'md5Url', 'originalMd5'];
|
||||
/** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */
|
||||
let ready = init();
|
||||
let order = {};
|
||||
|
||||
chrome.runtime.onConnect.addListener(handleLivePreview);
|
||||
// function handleColorScheme() {
|
||||
|
@ -70,6 +71,17 @@ const styleMan = (() => {
|
|||
}
|
||||
});
|
||||
|
||||
prefs.subscribe(['injectionOrder'], (key, value) => {
|
||||
order = {};
|
||||
value.forEach((uid, i) => {
|
||||
const id = uuidIndex.get(uid);
|
||||
if (id) {
|
||||
order[id] = i;
|
||||
}
|
||||
});
|
||||
msg.broadcast({method: 'styleSort', order});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
//#region Exports
|
||||
|
||||
|
@ -148,7 +160,11 @@ const styleMan = (() => {
|
|||
async getSectionsByUrl(url, id, isInitialApply) {
|
||||
if (ready.then) await ready;
|
||||
if (isInitialApply && prefs.get('disableAll')) {
|
||||
return {disableAll: true};
|
||||
return {
|
||||
cfg: {
|
||||
disableAll: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
const sender = CHROME && this && this.sender || {};
|
||||
if (sender.frameId === 0) {
|
||||
|
@ -170,7 +186,7 @@ const styleMan = (() => {
|
|||
}
|
||||
return id
|
||||
? cache.sections[id] ? {[id]: cache.sections[id]} : {}
|
||||
: cache.sections;
|
||||
: Object.assign({cfg: {order}}, cache.sections);
|
||||
},
|
||||
|
||||
/** @returns {Promise<StyleObj>} */
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
return NOP;
|
||||
}
|
||||
return API.styles.getSectionsByUrl(url, id).then(sections => {
|
||||
delete sections.cfg;
|
||||
const tasks = [];
|
||||
for (const section of Object.values(sections)) {
|
||||
const styleId = section.id;
|
||||
|
|
|
@ -13,11 +13,19 @@
|
|||
let hasStyles = false;
|
||||
let isDisabled = false;
|
||||
let isTab = !chrome.tabs || location.pathname !== '/popup.html';
|
||||
let order = {};
|
||||
const isFrame = window !== parent;
|
||||
const isFrameAboutBlank = isFrame && location.href === 'about:blank';
|
||||
const isUnstylable = !chrome.app && document instanceof XMLDocument;
|
||||
const styleInjector = StyleInjector({
|
||||
compare: (a, b) => a.id - b.id,
|
||||
compare: (a, b) => {
|
||||
const ia = order[a.id];
|
||||
const ib = order[b.id];
|
||||
if (ia === ib) return 0;
|
||||
if (ia == null) return 1;
|
||||
if (ib == null) return -1;
|
||||
return ia - ib;
|
||||
},
|
||||
onUpdate: onInjectorUpdate,
|
||||
});
|
||||
// dynamic iframes don't have a URL yet so we'll use their parent's URL (hash isn't inherited)
|
||||
|
@ -100,7 +108,11 @@
|
|||
parentStyles && await new Promise(onFrameElementInView) && parentStyles ||
|
||||
!isFrameAboutBlank && chrome.app && !chrome.tabs && tryCatch(getStylesViaXhr) ||
|
||||
await API.styles.getSectionsByUrl(matchUrl, null, true);
|
||||
isDisabled = styles.disableAll;
|
||||
if (styles.cfg) {
|
||||
isDisabled = styles.cfg.disableAll;
|
||||
order = styles.cfg.order || {};
|
||||
delete styles.cfg;
|
||||
}
|
||||
hasStyles = !isDisabled;
|
||||
if (hasStyles) {
|
||||
window[SYM] = styles;
|
||||
|
@ -166,10 +178,16 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case 'styleSort':
|
||||
order = request.order;
|
||||
styleInjector.sort();
|
||||
break;
|
||||
|
||||
case 'urlChanged':
|
||||
if (!hasStyles && isDisabled || matchUrl === request.url) break;
|
||||
matchUrl = request.url;
|
||||
API.styles.getSectionsByUrl(matchUrl).then(sections => {
|
||||
delete sections.cfg;
|
||||
hasStyles = true;
|
||||
styleInjector.replace(sections);
|
||||
});
|
||||
|
|
|
@ -78,6 +78,8 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
|
|||
_addRemoveElements(enable);
|
||||
if (enable) _toggleObservers(true);
|
||||
},
|
||||
|
||||
sort: _sort,
|
||||
};
|
||||
|
||||
function _add(style) {
|
||||
|
|
58
injection-order/injection-order.css
Normal file
58
injection-order/injection-order.css
Normal file
|
@ -0,0 +1,58 @@
|
|||
#message-box.injection-order > div {
|
||||
height: 100%;
|
||||
max-width: 80vw;
|
||||
}
|
||||
#message-box.injection-order #message-box-contents {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
--border: 1px solid rgba(128, 128, 128, .25);
|
||||
}
|
||||
.injection-order header {
|
||||
padding: 1rem;
|
||||
width: 0;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.injection-order ol {
|
||||
height: 100%;
|
||||
padding: 1px 0 0; /* 1px for keyboard-focused element's outline */
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
overflow-y: auto;
|
||||
border-top: var(--border);
|
||||
}
|
||||
.injection-order a {
|
||||
display: block;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
transition: transform .25s ease-in-out;
|
||||
z-index: 1;
|
||||
user-select: none;
|
||||
padding: 0.3em .5em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: move;
|
||||
}
|
||||
.injection-order a.enabled {
|
||||
font-weight: bold;
|
||||
}
|
||||
.injection-order a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.injection-order a:not(:first-child) {
|
||||
border-top: var(--border);
|
||||
}
|
||||
.injection-order a::before {
|
||||
content: "\2261";
|
||||
padding: 0.6em;
|
||||
font-weight: normal;
|
||||
}
|
||||
.injection-order .draggable-list-target {
|
||||
position: relative;
|
||||
background: lightcyan;
|
||||
transition: none;
|
||||
z-index: 100;
|
||||
}
|
79
injection-order/injection-order.js
Normal file
79
injection-order/injection-order.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* global $create messageBoxProxy */// dom.js
|
||||
/* global API */// msg.js
|
||||
/* global DraggableList */
|
||||
/* global prefs */
|
||||
/* global t */// localization.js
|
||||
'use strict';
|
||||
|
||||
/* exported InjectionOrder */
|
||||
async function InjectionOrder(show = true) {
|
||||
if (!show) {
|
||||
return messageBoxProxy.close();
|
||||
}
|
||||
const entries = (await getOrderedStyles()).map(makeEntry);
|
||||
const ol = $create('ol');
|
||||
let maxTranslateY;
|
||||
ol.append(...entries.map(l => l.el));
|
||||
ol.on('d:dragstart', ({detail: d}) => {
|
||||
d.origin.dataTransfer.setDragImage(new Image(), 0, 0);
|
||||
maxTranslateY = ol.scrollHeight + ol.offsetTop - d.dragTarget.offsetHeight - d.dragTarget.offsetTop;
|
||||
});
|
||||
ol.on('d:dragmove', ({detail: d}) => {
|
||||
d.origin.stopPropagation(); // preserves dropEffect
|
||||
d.origin.dataTransfer.dropEffect = 'move';
|
||||
const y = Math.min(d.currentPos.y - d.startPos.y, maxTranslateY);
|
||||
d.dragTarget.style.transform = `translateY(${y}px)`;
|
||||
});
|
||||
ol.on('d:dragend', ({detail: d}) => {
|
||||
const [item] = entries.splice(d.originalIndex, 1);
|
||||
entries.splice(d.spliceIndex, 0, item);
|
||||
ol.insertBefore(d.dragTarget, d.insertBefore);
|
||||
prefs.set('injectionOrder', entries.map(l => l.style._id));
|
||||
});
|
||||
DraggableList(ol, {scrollContainer: ol});
|
||||
|
||||
await messageBoxProxy.show({
|
||||
title: t('styleInjectionOrder'),
|
||||
contents: $create('fragment', [
|
||||
$create('header', t('styleInjectionOrderHint')),
|
||||
ol,
|
||||
]),
|
||||
className: 'injection-order center-dialog',
|
||||
blockScroll: true,
|
||||
buttons: [t('confirmClose')],
|
||||
});
|
||||
|
||||
async function getOrderedStyles() {
|
||||
const [styles] = await Promise.all([
|
||||
API.styles.getAll(),
|
||||
prefs.ready,
|
||||
]);
|
||||
const styleSet = new Set(styles);
|
||||
const uuidIndex = new Map();
|
||||
for (const s of styleSet) {
|
||||
uuidIndex.set(s._id, s);
|
||||
}
|
||||
const orderedStyles = [];
|
||||
for (const uid of prefs.get('injectionOrder')) {
|
||||
const s = uuidIndex.get(uid);
|
||||
if (s) {
|
||||
uuidIndex.delete(uid);
|
||||
orderedStyles.push(s);
|
||||
styleSet.delete(s);
|
||||
}
|
||||
}
|
||||
orderedStyles.push(...styleSet);
|
||||
return orderedStyles;
|
||||
}
|
||||
|
||||
function makeEntry(style) {
|
||||
return {
|
||||
style,
|
||||
el: $create('a', {
|
||||
className: style.enabled ? 'enabled' : '',
|
||||
href: '/edit.html?id=' + style.id,
|
||||
target: '_blank',
|
||||
}, style.name),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -12,6 +12,19 @@ window.messageBox = {
|
|||
_resolve: null,
|
||||
};
|
||||
|
||||
messageBox.close = async isAnimated => {
|
||||
window.off('keydown', messageBox.listeners.key, true);
|
||||
window.off('scroll', messageBox.listeners.scroll);
|
||||
window.off('mouseup', messageBox.listeners.mouseUp);
|
||||
window.off('mousemove', messageBox.listeners.mouseMove);
|
||||
if (isAnimated) {
|
||||
await animateElement(messageBox.element, 'fadeout');
|
||||
}
|
||||
messageBox.element.remove();
|
||||
messageBox.element = null;
|
||||
messageBox._resolve = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} params
|
||||
* @param {String} params.title
|
||||
|
@ -46,7 +59,8 @@ messageBox.show = async ({
|
|||
|
||||
messageBox._originalFocus = document.activeElement;
|
||||
// focus the first focusable child but skip the first external link which is usually `feedback`
|
||||
if ((moveFocus(messageBox.element, 0) || {}).target === '_blank') {
|
||||
if ((moveFocus(messageBox.element, 0) || {}).target === '_blank' &&
|
||||
/config-dialog/.test(className)) {
|
||||
moveFocus(messageBox.element, 1);
|
||||
}
|
||||
// suppress focus outline when invoked via click
|
||||
|
@ -143,9 +157,7 @@ messageBox.show = async ({
|
|||
|
||||
function resolveWith(value) {
|
||||
setTimeout(messageBox._resolve, 0, value);
|
||||
unbindGlobalListeners();
|
||||
animateElement(messageBox.element, 'fadeout')
|
||||
.then(removeSelf);
|
||||
messageBox.close(true);
|
||||
if (messageBox.element.contains(document.activeElement)) {
|
||||
messageBox._originalFocus.focus();
|
||||
}
|
||||
|
@ -153,8 +165,7 @@ messageBox.show = async ({
|
|||
|
||||
function createElement() {
|
||||
if (messageBox.element) {
|
||||
unbindGlobalListeners();
|
||||
removeSelf();
|
||||
messageBox.close();
|
||||
}
|
||||
const id = 'message-box';
|
||||
messageBox.element =
|
||||
|
@ -186,19 +197,6 @@ messageBox.show = async ({
|
|||
}
|
||||
window.on('keydown', messageBox.listeners.key, true);
|
||||
}
|
||||
|
||||
function unbindGlobalListeners() {
|
||||
window.off('keydown', messageBox.listeners.key, true);
|
||||
window.off('scroll', messageBox.listeners.scroll);
|
||||
window.off('mouseup', messageBox.listeners.mouseUp);
|
||||
window.off('mousemove', messageBox.listeners.mouseMove);
|
||||
}
|
||||
|
||||
function removeSelf() {
|
||||
messageBox.element.remove();
|
||||
messageBox.element = null;
|
||||
messageBox._resolve = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
window.on('click', showTooltipNote);
|
||||
window.on('resize', () => debounce(addTooltipsToEllipsized, 100));
|
||||
// Removing transition-suppressor rule
|
||||
const {sheet} = $('link[href^="global.css"]');
|
||||
const {sheet} = $('link[href$="global.css"]');
|
||||
for (let i = 0, rule; (rule = sheet.cssRules[i]); i++) {
|
||||
if (/#\\1\s?transition-suppressor/.test(rule.selectorText)) {
|
||||
sheet.deleteRule(i);
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
const tag = isCss ? 'link' : 'script';
|
||||
const attr = isCss ? 'href' : 'src';
|
||||
if (!isCss && !url.endsWith('.js')) url += '.js';
|
||||
if (url.startsWith('/')) url = url.slice(1);
|
||||
if (url[0] === '/' && location.pathname.indexOf('/', 1) < 0) url = url.slice(1);
|
||||
let el = document.head.querySelector(`${tag}[${attr}$="${url}"]`);
|
||||
if (!el) {
|
||||
el = document.createElement(tag);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* @namespace PrefsValues
|
||||
*/
|
||||
const defaults = {
|
||||
// TODO: sort everything aphabetically
|
||||
'openEditInWindow': false, // new editor opens in a own browser window
|
||||
'openEditInWindow.popup': false, // new editor opens in a simplified browser window without omnibox
|
||||
'windowPosition': {}, // detached window position
|
||||
|
@ -132,6 +133,8 @@
|
|||
'popupWidth': 246, // popup width in pixels
|
||||
|
||||
'updateInterval': 24, // user-style automatic update interval, hours (0 = disable)
|
||||
|
||||
'injectionOrder': [],
|
||||
};
|
||||
const knownKeys = Object.keys(defaults);
|
||||
/** @type {PrefsValues} */
|
||||
|
|
|
@ -313,8 +313,8 @@
|
|||
</a>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button id="manage-options-button" i18n-text="openOptions"></button>
|
||||
<button id="injection-order-button" i18n-title="styleInjectionOrder">↑↓</button>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1165,3 +1165,4 @@ a:hover {
|
|||
margin-left: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ newUI.renderClass();
|
|||
installed.on('mouseover', Events.lazyAddEntryTitle, {passive: true});
|
||||
installed.on('mouseout', Events.lazyAddEntryTitle, {passive: true});
|
||||
$('#manage-options-button').onclick = () => router.updateHash('#stylus-options');
|
||||
$('#injection-order-button').onclick = () => router.updateHash('#injection-order');
|
||||
$('#sync-styles').onclick = () => router.updateHash('#stylus-options');
|
||||
$$('#header a[href^="http"]').forEach(a => (a.onclick = Events.external));
|
||||
document.on('visibilitychange', handleVisibilityChange);
|
||||
|
@ -101,6 +102,7 @@ newUI.renderClass();
|
|||
msg.onExtension(onRuntimeMessage);
|
||||
window.on('closeOptions', () => router.updateHash(''));
|
||||
router.watch({hash: '#stylus-options'}, toggleEmbeddedOptions);
|
||||
router.watch({hash: '#injection-order'}, toggleInjectionOrder);
|
||||
|
||||
function onRuntimeMessage(msg) {
|
||||
switch (msg.method) {
|
||||
|
@ -137,3 +139,18 @@ async function toggleEmbeddedOptions(state) {
|
|||
el.remove();
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleInjectionOrder(state) {
|
||||
const shown = $('.injection-order');
|
||||
if (state && !shown) {
|
||||
await require([
|
||||
'/vendor/draggable-list/draggable-list.iife.min.js',
|
||||
'/injection-order/injection-order.css',
|
||||
'/injection-order/injection-order', /* global InjectionOrder */
|
||||
]);
|
||||
await InjectionOrder();
|
||||
router.updateHash('');
|
||||
} else if (!state && shown) {
|
||||
await InjectionOrder(false);
|
||||
}
|
||||
}
|
||||
|
|
2113
package-lock.json
generated
2113
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,7 @@
|
|||
"codemirror": "WARNING! Always use an exact version and test it for a while before releasing"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eight04/draggable-list": "^0.3.0",
|
||||
"codemirror": "5.63.3",
|
||||
"db-to-cloud": "^0.7.0",
|
||||
"jsonlint": "^1.6.3",
|
||||
|
@ -21,12 +22,11 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"archiver": "^4.0.1",
|
||||
"endent": "^1.4.0",
|
||||
"eslint": "^7.20.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
"make-fetch-happen": "^8.0.7",
|
||||
"glob": "^7.2.0",
|
||||
"node-fetch": "^2.6.6",
|
||||
"sync-version": "^1.0.1",
|
||||
"tiny-glob": "^0.2.6",
|
||||
"web-ext": "^6.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
/* eslint-env node */
|
||||
'use strict';
|
||||
|
||||
const fetch = require('node-fetch');
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
const glob = require('glob').sync;
|
||||
const path = require('path');
|
||||
|
||||
const endent = require('endent');
|
||||
const fetch = require('make-fetch-happen');
|
||||
const fse = require('fs-extra');
|
||||
const glob = require('tiny-glob');
|
||||
const KEEP_DIRECTORIES = null;
|
||||
|
||||
const files = {
|
||||
'codemirror': [
|
||||
KEEP_DIRECTORIES,
|
||||
'addon/comment/comment.js',
|
||||
'addon/dialog',
|
||||
'addon/edit/closebrackets.js',
|
||||
|
@ -35,30 +37,33 @@ const files = {
|
|||
'theme/*',
|
||||
],
|
||||
'jsonlint': [
|
||||
'lib/jsonlint.js → jsonlint.js',
|
||||
'README.md → LICENSE',
|
||||
'lib/jsonlint.js',
|
||||
'README.md -> LICENSE',
|
||||
],
|
||||
'less-bundle': [
|
||||
'dist/less.min.js → less.min.js',
|
||||
'dist/less.min.js',
|
||||
],
|
||||
'lz-string-unsafe': [
|
||||
'lz-string-unsafe.min.js',
|
||||
],
|
||||
'stylelint-bundle': [
|
||||
'dist/stylelint-bundle.min.js → stylelint-bundle.min.js',
|
||||
'https://github.com/stylelint/stylelint/raw/{VERSION}/LICENSE → LICENSE',
|
||||
'dist/stylelint-bundle.min.js',
|
||||
'https://github.com/stylelint/stylelint/raw/{VERSION}/LICENSE',
|
||||
],
|
||||
'stylus-lang-bundle': [
|
||||
'dist/stylus-renderer.min.js → stylus-renderer.min.js',
|
||||
'dist/stylus-renderer.min.js',
|
||||
],
|
||||
'usercss-meta': [
|
||||
'dist/usercss-meta.min.js → usercss-meta.min.js',
|
||||
'dist/usercss-meta.min.js',
|
||||
],
|
||||
'db-to-cloud': [
|
||||
'dist/db-to-cloud.min.js → db-to-cloud.min.js',
|
||||
'dist/db-to-cloud.min.js',
|
||||
],
|
||||
'webext-launch-web-auth-flow': [
|
||||
'dist/webext-launch-web-auth-flow.min.js → webext-launch-web-auth-flow.min.js',
|
||||
'dist/webext-launch-web-auth-flow.min.js',
|
||||
],
|
||||
'@eight04/draggable-list': [
|
||||
'dist/draggable-list.iife.min.js',
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -66,96 +71,97 @@ main().catch(console.error);
|
|||
|
||||
async function main() {
|
||||
fse.emptyDirSync('vendor');
|
||||
for (const pkg in files) {
|
||||
console.log('\x1b[32m%s\x1b[0m', `Building ${pkg}...`);
|
||||
// other files
|
||||
const [fetched, copied] = await buildFiles(pkg, files[pkg]);
|
||||
// README
|
||||
await fse.outputFile(`vendor/${pkg}/README.md`, generateReadme(pkg, fetched, copied));
|
||||
// LICENSE
|
||||
await copyLicense(pkg);
|
||||
}
|
||||
console.log('\x1b[32m%s\x1b[0m', 'updating codemirror themes list...');
|
||||
await fse.outputFile('edit/codemirror-themes.js', await generateThemeList());
|
||||
await Promise.all(Object.keys(files).map(async pkg => {
|
||||
console.log(`Building ${pkg}...`);
|
||||
const pkgName = getFileName(pkg);
|
||||
const flatPkg = pkg === pkgName || files[pkgName]
|
||||
? pkg.replace(/\//g, '-')
|
||||
: pkgName;
|
||||
const res = await buildFiles(pkg, flatPkg, files[pkg]);
|
||||
buildLicense(pkg, flatPkg);
|
||||
buildReadme(pkg, flatPkg, res);
|
||||
}));
|
||||
console.log('Building CodeMirror theme list...');
|
||||
buildThemeList();
|
||||
}
|
||||
|
||||
async function generateThemeList() {
|
||||
const themes = (await fse.readdir('vendor/codemirror/theme'))
|
||||
.filter(name => name.endsWith('.css'))
|
||||
.map(name => name.replace('.css', ''))
|
||||
.sort();
|
||||
return endent`
|
||||
async function buildFiles(pkg, flatPkg, patterns) {
|
||||
const keepDirs = patterns.includes(KEEP_DIRECTORIES);
|
||||
let fetched = '';
|
||||
let copied = '';
|
||||
for (let pattern of patterns) {
|
||||
if (pattern === KEEP_DIRECTORIES) continue;
|
||||
pattern = pattern.replace('{VERSION}', require(`${pkg}/package.json`).version);
|
||||
const [src, dest = !keepDirs && getFileName(src)] = pattern.split(/\s*->\s*/);
|
||||
if (/^https?:/.test(src)) {
|
||||
fse.outputFileSync(`vendor/${flatPkg}/${dest}`, await (await fetch(src)).text());
|
||||
fetched += `* ${dest}: ${src}\n`;
|
||||
} else {
|
||||
const files = glob(`node_modules/${pkg}/${src}`);
|
||||
if (!files.length) {
|
||||
throw new Error(`Pattern ${src} matches no files`);
|
||||
}
|
||||
for (const file of files) {
|
||||
fse.copySync(file, dest
|
||||
? `vendor/${flatPkg}/${dest}`
|
||||
: `vendor/${path.relative('node_modules', file).replace(pkg + '/', flatPkg + '/')}`);
|
||||
const relSrc = path.relative(`node_modules/${pkg}`, file).replace(/\\/g, '/');
|
||||
copied += dest && dest !== relSrc
|
||||
? `* ${dest}: ${
|
||||
keepDirs || getFileName(dest) !== getFileName(relSrc)
|
||||
? relSrc
|
||||
: relSrc.replace(/[^/]+$/, '*')
|
||||
}\n`
|
||||
: `* ${relSrc}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {fetched, copied};
|
||||
}
|
||||
|
||||
function buildLicense(pkg, flatPkg) {
|
||||
const LICENSE = `vendor/${flatPkg}/LICENSE`;
|
||||
if (!fs.existsSync(LICENSE)) {
|
||||
const [src] = glob(`node_modules/${pkg}/LICEN[SC]E*`);
|
||||
if (!src) throw new Error(`Cannot find license file for ${pkg}`);
|
||||
fse.copySync(src, LICENSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildReadme(pkg, flatPkg, {fetched, copied}) {
|
||||
const {name, version} = require(`${pkg}/package.json`);
|
||||
fse.outputFileSync(`vendor/${flatPkg}/README.md`, [
|
||||
`## ${name} v${version}`,
|
||||
fetched && `Files downloaded from URL:\n${fetched}`,
|
||||
copied && `Files copied from NPM (node_modules):\n${copied}`,
|
||||
].filter(Boolean).join('\n\n'));
|
||||
}
|
||||
|
||||
function buildThemeList() {
|
||||
fse.outputFileSync('edit/codemirror-themes.js', deindent(`\
|
||||
/* Do not edit. This file is auto-generated by build-vendor.js */
|
||||
'use strict';
|
||||
|
||||
/* exported CODEMIRROR_THEMES */
|
||||
const CODEMIRROR_THEMES = [
|
||||
${
|
||||
themes.map(t => ` '${t.replace(/'/g, '\\$&')}',\n`).join('')
|
||||
}];
|
||||
` + '\n';
|
||||
}
|
||||
|
||||
async function copyLicense(pkg) {
|
||||
try {
|
||||
await fse.access(`vendor/${pkg}/LICENSE`);
|
||||
return;
|
||||
} catch (err) {
|
||||
// pass
|
||||
}
|
||||
for (const file of await glob(`node_modules/${pkg}/LICEN[SC]E*`)) {
|
||||
await fse.copy(file, `vendor/${pkg}/LICENSE`);
|
||||
return;
|
||||
}
|
||||
throw new Error(`cannot find license file for ${pkg}`);
|
||||
}
|
||||
|
||||
async function buildFiles(pkg, patterns) {
|
||||
const fetchedFiles = [];
|
||||
const copiedFiles = [];
|
||||
for (let pattern of patterns) {
|
||||
pattern = pattern.replace('{VERSION}', require(`${pkg}/package.json`).version);
|
||||
const [src, dest] = pattern.split(/\s*→\s*/);
|
||||
if (src.startsWith('http')) {
|
||||
const content = await (await fetch(src)).text();
|
||||
await fse.outputFile(`vendor/${pkg}/${dest}`, content);
|
||||
fetchedFiles.push([src, dest]);
|
||||
} else {
|
||||
let dirty = false;
|
||||
for (const file of await glob(`node_modules/${pkg}/${src}`)) {
|
||||
if (dest) {
|
||||
await fse.copy(file, `vendor/${pkg}/${dest}`);
|
||||
} else {
|
||||
await fse.copy(file, path.join('vendor', path.relative('node_modules', file)));
|
||||
}
|
||||
copiedFiles.push([path.relative(`node_modules/${pkg}`, file), dest]);
|
||||
dirty = true;
|
||||
}
|
||||
if (!dirty) {
|
||||
throw new Error(`Pattern ${src} matches no files`);
|
||||
}
|
||||
fs.readdirSync('vendor/codemirror/theme')
|
||||
.filter(name => name.endsWith('.css'))
|
||||
.map(name => name.replace('.css', ''))
|
||||
.sort()
|
||||
.map(t => ` '${t.replace(/'/g, '\\$&')}',`).join('\n')
|
||||
}
|
||||
}
|
||||
return [fetchedFiles, copiedFiles];
|
||||
];
|
||||
`));
|
||||
}
|
||||
|
||||
function generateReadme(lib, fetched, copied) {
|
||||
const pkg = require(`${lib}/package.json`);
|
||||
let txt = `## ${pkg.name} v${pkg.version}\n\n`;
|
||||
if (fetched.length) {
|
||||
txt += `Following files are downloaded from HTTP:\n\n${generateList(fetched)}\n\n`;
|
||||
}
|
||||
if (copied.length) {
|
||||
txt += `Following files are copied from npm (node_modules):\n\n${generateList(copied)}\n`;
|
||||
}
|
||||
return txt;
|
||||
function deindent(str) {
|
||||
const indent = str.match(/^\s*/)[0];
|
||||
return indent
|
||||
? str.replace(new RegExp('^' + indent, 'gm'), '')
|
||||
: str;
|
||||
}
|
||||
|
||||
function generateList(list) {
|
||||
return list.map(([src, dest]) => {
|
||||
if (dest) {
|
||||
return `* ${dest}: ${src}`;
|
||||
}
|
||||
return `* ${src}`;
|
||||
}).join('\n');
|
||||
function getFileName(path) {
|
||||
return path.split('/').pop();
|
||||
}
|
||||
|
|
193
vendor/codemirror/README.md
vendored
193
vendor/codemirror/README.md
vendored
|
@ -1,99 +1,98 @@
|
|||
## codemirror v5.63.3
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* addon\comment\comment.js
|
||||
* addon\dialog
|
||||
* addon\edit\closebrackets.js
|
||||
* addon\edit\matchbrackets.js
|
||||
* addon\fold\brace-fold.js
|
||||
* addon\fold\comment-fold.js
|
||||
* addon\fold\foldcode.js
|
||||
* addon\fold\foldgutter.css
|
||||
* addon\fold\foldgutter.js
|
||||
* addon\fold\indent-fold.js
|
||||
* addon\hint\css-hint.js
|
||||
* addon\hint\show-hint.css
|
||||
* addon\hint\show-hint.js
|
||||
* addon\lint\css-lint.js
|
||||
* addon\lint\json-lint.js
|
||||
* addon\lint\lint.css
|
||||
* addon\lint\lint.js
|
||||
* addon\scroll\annotatescrollbar.js
|
||||
* addon\search\matchesonscrollbar.css
|
||||
* addon\search\matchesonscrollbar.js
|
||||
* addon\search\searchcursor.js
|
||||
* addon\selection\active-line.js
|
||||
* keymap\emacs.js
|
||||
* keymap\sublime.js
|
||||
* keymap\vim.js
|
||||
* lib\codemirror.css
|
||||
* lib\codemirror.js
|
||||
* mode\css
|
||||
* mode\javascript
|
||||
* mode\stylus
|
||||
* theme\3024-day.css
|
||||
* theme\3024-night.css
|
||||
* theme\abbott.css
|
||||
* theme\abcdef.css
|
||||
* theme\ambiance-mobile.css
|
||||
* theme\ambiance.css
|
||||
* theme\ayu-dark.css
|
||||
* theme\ayu-mirage.css
|
||||
* theme\base16-dark.css
|
||||
* theme\base16-light.css
|
||||
* theme\bespin.css
|
||||
* theme\blackboard.css
|
||||
* theme\cobalt.css
|
||||
* theme\colorforth.css
|
||||
* theme\darcula.css
|
||||
* theme\dracula.css
|
||||
* theme\duotone-dark.css
|
||||
* theme\duotone-light.css
|
||||
* theme\eclipse.css
|
||||
* theme\elegant.css
|
||||
* theme\erlang-dark.css
|
||||
* theme\gruvbox-dark.css
|
||||
* theme\hopscotch.css
|
||||
* theme\icecoder.css
|
||||
* theme\idea.css
|
||||
* theme\isotope.css
|
||||
* theme\juejin.css
|
||||
* theme\lesser-dark.css
|
||||
* theme\liquibyte.css
|
||||
* theme\lucario.css
|
||||
* theme\material-darker.css
|
||||
* theme\material-ocean.css
|
||||
* theme\material-palenight.css
|
||||
* theme\material.css
|
||||
* theme\mbo.css
|
||||
* theme\mdn-like.css
|
||||
* theme\midnight.css
|
||||
* theme\monokai.css
|
||||
* theme\moxer.css
|
||||
* theme\neat.css
|
||||
* theme\neo.css
|
||||
* theme\night.css
|
||||
* theme\nord.css
|
||||
* theme\oceanic-next.css
|
||||
* theme\panda-syntax.css
|
||||
* theme\paraiso-dark.css
|
||||
* theme\paraiso-light.css
|
||||
* theme\pastel-on-dark.css
|
||||
* theme\railscasts.css
|
||||
* theme\rubyblue.css
|
||||
* theme\seti.css
|
||||
* theme\shadowfox.css
|
||||
* theme\solarized.css
|
||||
* theme\ssms.css
|
||||
* theme\the-matrix.css
|
||||
* theme\tomorrow-night-bright.css
|
||||
* theme\tomorrow-night-eighties.css
|
||||
* theme\ttcn.css
|
||||
* theme\twilight.css
|
||||
* theme\vibrant-ink.css
|
||||
* theme\xq-dark.css
|
||||
* theme\xq-light.css
|
||||
* theme\yeti.css
|
||||
* theme\yonce.css
|
||||
* theme\zenburn.css
|
||||
Files copied from NPM (node_modules):
|
||||
* addon/comment/comment.js
|
||||
* addon/dialog
|
||||
* addon/edit/closebrackets.js
|
||||
* addon/edit/matchbrackets.js
|
||||
* addon/fold/brace-fold.js
|
||||
* addon/fold/comment-fold.js
|
||||
* addon/fold/foldcode.js
|
||||
* addon/fold/foldgutter.css
|
||||
* addon/fold/foldgutter.js
|
||||
* addon/fold/indent-fold.js
|
||||
* addon/hint/css-hint.js
|
||||
* addon/hint/show-hint.css
|
||||
* addon/hint/show-hint.js
|
||||
* addon/lint/css-lint.js
|
||||
* addon/lint/json-lint.js
|
||||
* addon/lint/lint.css
|
||||
* addon/lint/lint.js
|
||||
* addon/scroll/annotatescrollbar.js
|
||||
* addon/search/matchesonscrollbar.css
|
||||
* addon/search/matchesonscrollbar.js
|
||||
* addon/search/searchcursor.js
|
||||
* addon/selection/active-line.js
|
||||
* keymap/emacs.js
|
||||
* keymap/sublime.js
|
||||
* keymap/vim.js
|
||||
* lib/codemirror.css
|
||||
* lib/codemirror.js
|
||||
* mode/css
|
||||
* mode/javascript
|
||||
* mode/stylus
|
||||
* theme/3024-day.css
|
||||
* theme/3024-night.css
|
||||
* theme/abbott.css
|
||||
* theme/abcdef.css
|
||||
* theme/ambiance-mobile.css
|
||||
* theme/ambiance.css
|
||||
* theme/ayu-dark.css
|
||||
* theme/ayu-mirage.css
|
||||
* theme/base16-dark.css
|
||||
* theme/base16-light.css
|
||||
* theme/bespin.css
|
||||
* theme/blackboard.css
|
||||
* theme/cobalt.css
|
||||
* theme/colorforth.css
|
||||
* theme/darcula.css
|
||||
* theme/dracula.css
|
||||
* theme/duotone-dark.css
|
||||
* theme/duotone-light.css
|
||||
* theme/eclipse.css
|
||||
* theme/elegant.css
|
||||
* theme/erlang-dark.css
|
||||
* theme/gruvbox-dark.css
|
||||
* theme/hopscotch.css
|
||||
* theme/icecoder.css
|
||||
* theme/idea.css
|
||||
* theme/isotope.css
|
||||
* theme/juejin.css
|
||||
* theme/lesser-dark.css
|
||||
* theme/liquibyte.css
|
||||
* theme/lucario.css
|
||||
* theme/material-darker.css
|
||||
* theme/material-ocean.css
|
||||
* theme/material-palenight.css
|
||||
* theme/material.css
|
||||
* theme/mbo.css
|
||||
* theme/mdn-like.css
|
||||
* theme/midnight.css
|
||||
* theme/monokai.css
|
||||
* theme/moxer.css
|
||||
* theme/neat.css
|
||||
* theme/neo.css
|
||||
* theme/night.css
|
||||
* theme/nord.css
|
||||
* theme/oceanic-next.css
|
||||
* theme/panda-syntax.css
|
||||
* theme/paraiso-dark.css
|
||||
* theme/paraiso-light.css
|
||||
* theme/pastel-on-dark.css
|
||||
* theme/railscasts.css
|
||||
* theme/rubyblue.css
|
||||
* theme/seti.css
|
||||
* theme/shadowfox.css
|
||||
* theme/solarized.css
|
||||
* theme/ssms.css
|
||||
* theme/the-matrix.css
|
||||
* theme/tomorrow-night-bright.css
|
||||
* theme/tomorrow-night-eighties.css
|
||||
* theme/ttcn.css
|
||||
* theme/twilight.css
|
||||
* theme/vibrant-ink.css
|
||||
* theme/xq-dark.css
|
||||
* theme/xq-light.css
|
||||
* theme/yeti.css
|
||||
* theme/yonce.css
|
||||
* theme/zenburn.css
|
||||
|
|
5
vendor/db-to-cloud/README.md
vendored
5
vendor/db-to-cloud/README.md
vendored
|
@ -1,5 +1,4 @@
|
|||
## db-to-cloud v0.7.0
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* db-to-cloud.min.js: dist\db-to-cloud.min.js
|
||||
Files copied from NPM (node_modules):
|
||||
* db-to-cloud.min.js: dist/*
|
||||
|
|
22
vendor/draggable-list/LICENSE
vendored
Normal file
22
vendor/draggable-list/LICENSE
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 eight
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
4
vendor/draggable-list/README.md
vendored
Normal file
4
vendor/draggable-list/README.md
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
## @eight04/draggable-list v0.3.0
|
||||
|
||||
Files copied from NPM (node_modules):
|
||||
* draggable-list.iife.min.js: dist/*
|
1
vendor/draggable-list/draggable-list.iife.min.js
vendored
Normal file
1
vendor/draggable-list/draggable-list.iife.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
var DraggableList=function(){"use strict";const t="draggable-list-transformed";return function(e,{bound:r,scrollContainer:n}={}){for(const t of e.children)t.draggable=!0;new MutationObserver((t=>{for(const e of t)for(const t of e.addedNodes)t.draggable=!0})).observe(e,{childList:!0});let a=null,o=0,s=0,l=null,d=[],i=null,c=!1,g=0;function f(t,r,n){const o={origin:t,startPos:a,currentPos:l,dragTarget:i};n&&Object.assign(o,n),e.dispatchEvent(new CustomEvent(r,{detail:o}))}e.addEventListener("dragstart",(t=>{if(t.target.parentNode!==e)return;i=t.target,c=!1;const r=n?n.scrollLeft:0,u=n?n.scrollTop:0;a={x:t.pageX+r,y:t.pageY+u},o=[...e.children].indexOf(t.target),s=o,l=a,d=[...e.children].map((t=>{const e=t.getBoundingClientRect();return{top:e.top+window.scrollY+u,bottom:e.bottom+window.scrollY+u}})),g=o+1<d.length?d[o+1].top-d[o].top:o>0?d[o].bottom-d[o-1].bottom:0,i.classList.add("draggable-list-target"),e.classList.add("draggable-list-dragging"),f(t,"d:dragstart")})),e.addEventListener("dragenter",(t=>{i&&(t.preventDefault(),f(t,"d:dragmove"))})),e.addEventListener("dragover",(a=>{if(!i)return;a.preventDefault();const c=n?n.scrollLeft:0,u=n?n.scrollTop:0,p={x:a.pageX+c,y:a.pageY+u},m=function(t,e,r,n){if(r<t[0].top&&n)return e;for(let n=0;n<e;n++)if(!(t[n].bottom<r))return n;if(r>t[t.length-1].bottom&&n)return e;for(let n=t.length-1;n>e;n--)if(!(t[n].top>r))return n;return e}(d,o,p.y,r);!function(e,r,n,a,o){function s(r,n,a,o){for(let s=n;s<=a;s++)r&&!e[s].classList.contains(t)?(e[s].classList.add(t),e[s].style.transform=o):!r&&e[s].classList.contains(t)&&(e[s].classList.remove(t),e[s].style="")}a>n?(s(!1,n,Math.min(r-1,a-1)),r<e.length-1&&s(!0,Math.max(n+1,r+1),a,"translateY(".concat(-o,"px)"))):(s(!1,Math.max(r+1,a+1),n),r>0&&s(!0,a,Math.min(n-1,r-1),"translateY(".concat(o,"px)")))}(e.children,o,s,m,g),s=m,l=p,f(a,"d:dragmove")})),document.addEventListener("dragend",(r=>{if(i){for(const r of e.children)r.classList.remove(t),r.style="";i.classList.remove("draggable-list-target"),e.classList.remove("draggable-list-dragging"),f(r,"d:dragend",{originalIndex:o,spliceIndex:s,insertBefore:s<o?e.children[s]:e.children[s+1],dropped:c}),i=null}})),e.addEventListener("drop",(t=>{i&&(c=!0,t.preventDefault())}))}}();
|
5
vendor/jsonlint/README.md
vendored
5
vendor/jsonlint/README.md
vendored
|
@ -1,6 +1,5 @@
|
|||
## jsonlint v1.6.3
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* jsonlint.js: lib\jsonlint.js
|
||||
Files copied from NPM (node_modules):
|
||||
* jsonlint.js: lib/*
|
||||
* LICENSE: README.md
|
||||
|
|
5
vendor/less-bundle/README.md
vendored
5
vendor/less-bundle/README.md
vendored
|
@ -1,5 +1,4 @@
|
|||
## less-bundle v0.1.0
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* less.min.js: dist\less.min.js
|
||||
Files copied from NPM (node_modules):
|
||||
* less.min.js: dist/*
|
||||
|
|
3
vendor/lz-string-unsafe/README.md
vendored
3
vendor/lz-string-unsafe/README.md
vendored
|
@ -1,5 +1,4 @@
|
|||
## lz-string-unsafe v1.4.4-fork-1
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
Files copied from NPM (node_modules):
|
||||
* lz-string-unsafe.min.js
|
||||
|
|
7
vendor/stylelint-bundle/README.md
vendored
7
vendor/stylelint-bundle/README.md
vendored
|
@ -1,9 +1,8 @@
|
|||
## stylelint-bundle v13.8.0
|
||||
|
||||
Following files are downloaded from HTTP:
|
||||
|
||||
Files downloaded from URL:
|
||||
* LICENSE: https://github.com/stylelint/stylelint/raw/13.8.0/LICENSE
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* stylelint-bundle.min.js: dist\stylelint-bundle.min.js
|
||||
Files copied from NPM (node_modules):
|
||||
* stylelint-bundle.min.js: dist/*
|
||||
|
|
5
vendor/stylus-lang-bundle/README.md
vendored
5
vendor/stylus-lang-bundle/README.md
vendored
|
@ -1,5 +1,4 @@
|
|||
## stylus-lang-bundle v0.54.7
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* stylus-renderer.min.js: dist\stylus-renderer.min.js
|
||||
Files copied from NPM (node_modules):
|
||||
* stylus-renderer.min.js: dist/*
|
||||
|
|
5
vendor/usercss-meta/README.md
vendored
5
vendor/usercss-meta/README.md
vendored
|
@ -1,5 +1,4 @@
|
|||
## usercss-meta v0.12.0
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* usercss-meta.min.js: dist\usercss-meta.min.js
|
||||
Files copied from NPM (node_modules):
|
||||
* usercss-meta.min.js: dist/*
|
||||
|
|
5
vendor/webext-launch-web-auth-flow/README.md
vendored
5
vendor/webext-launch-web-auth-flow/README.md
vendored
|
@ -1,5 +1,4 @@
|
|||
## webext-launch-web-auth-flow v0.1.1
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
* webext-launch-web-auth-flow.min.js: dist\webext-launch-web-auth-flow.min.js
|
||||
Files copied from NPM (node_modules):
|
||||
* webext-launch-web-auth-flow.min.js: dist/*
|
||||
|
|
Loading…
Reference in New Issue
Block a user