recognize usercss @updateURL
* installation URL is preferred - same behavior as before * @updateURL is used when the style was drag'n'dropped into the manage page because there's no real URL in this case * install-usercss page shows the new update URL, which is set as per the above, under the checkbox that enables updates
This commit is contained in:
parent
0659ff6233
commit
f337e18515
|
@ -78,8 +78,8 @@ var usercssHelper = (() => {
|
|||
);
|
||||
}
|
||||
|
||||
function openInstallPage(tab, {url = tab.url, direct} = {}) {
|
||||
if (direct) {
|
||||
function openInstallPage(tab, {url = tab.url, direct, downloaded} = {}) {
|
||||
if (direct && !downloaded) {
|
||||
prefetchCodeForInstallation(tab.id, url);
|
||||
}
|
||||
return wrapReject(openURL({
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
<input type="checkbox">
|
||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
<span></span>
|
||||
<p></p>
|
||||
</label>
|
||||
<label class="live-reload">
|
||||
<input type="checkbox">
|
||||
|
|
|
@ -193,6 +193,17 @@ h2.installed.active {
|
|||
min-width: 0;
|
||||
}
|
||||
|
||||
.set-update-url {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.set-update-url p {
|
||||
word-break: break-all;
|
||||
opacity: .5;
|
||||
width: 100%;
|
||||
margin: .25em 0 .25em;
|
||||
}
|
||||
|
||||
.external {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -283,24 +283,28 @@
|
|||
};
|
||||
|
||||
// set updateUrl
|
||||
const setUpdate = $('.set-update-url input[type=checkbox]');
|
||||
const updateUrl = new URL(params.get('updateUrl'));
|
||||
const checker = $('.set-update-url input[type=checkbox]');
|
||||
// prefer the installation URL unless drag'n'dropped on the manage page
|
||||
const installationUrl = (params.get('updateUrl') || '').replace(/^blob.+/, '');
|
||||
const updateUrl = new URL(installationUrl || style.updateUrl || 'foo:bar');
|
||||
$('.set-update-url > span').textContent = t('installUpdateFromLabel');
|
||||
if (dup && dup.updateUrl === updateUrl.href) {
|
||||
setUpdate.checked = true;
|
||||
checker.checked = true;
|
||||
// there is no way to "unset" updateUrl, you can only overwrite it.
|
||||
setUpdate.disabled = true;
|
||||
checker.disabled = true;
|
||||
} else if (updateUrl.protocol === 'foo:') {
|
||||
// drag'n'dropped on the manage page and the style doesn't have @updateURL
|
||||
checker.disabled = true;
|
||||
} else if (updateUrl.protocol !== 'file:') {
|
||||
setUpdate.checked = true;
|
||||
checker.checked = true;
|
||||
style.updateUrl = updateUrl.href;
|
||||
}
|
||||
setUpdate.onchange = e => {
|
||||
if (e.target.checked) {
|
||||
style.updateUrl = updateUrl.href;
|
||||
} else {
|
||||
delete style.updateUrl;
|
||||
}
|
||||
checker.onchange = () => {
|
||||
style.updateUrl = checker.checked ? updateUrl.href : null;
|
||||
};
|
||||
checker.onchange();
|
||||
$('.set-update-url p').textContent = updateUrl.href.length < 300 ? updateUrl.href :
|
||||
updateUrl.href.slice(0, 300) + '...';
|
||||
|
||||
if (!port) {
|
||||
return;
|
||||
|
|
120
js/usercss.js
120
js/usercss.js
|
@ -3,25 +3,34 @@
|
|||
|
||||
// eslint-disable-next-line no-var
|
||||
var usercss = (() => {
|
||||
// true for global, false for private
|
||||
const METAS = {
|
||||
__proto__: null,
|
||||
author: true,
|
||||
advanced: false,
|
||||
description: true,
|
||||
homepageURL: false,
|
||||
// icon: false,
|
||||
license: false,
|
||||
name: true,
|
||||
namespace: false,
|
||||
// noframes: false,
|
||||
preprocessor: false,
|
||||
supportURL: false,
|
||||
'var': false,
|
||||
version: false
|
||||
};
|
||||
|
||||
// true = global
|
||||
// false or 0 = private
|
||||
// <string> = global key name
|
||||
// <function> = (style, newValue)
|
||||
const KNOWN_META = new Map([
|
||||
['author', true],
|
||||
['advanced', 0],
|
||||
['description', true],
|
||||
['homepageURL', 'url'],
|
||||
['icon', 0],
|
||||
['license', 0],
|
||||
['name', true],
|
||||
['namespace', 0],
|
||||
//['noframes', 0],
|
||||
['preprocessor', 0],
|
||||
['supportURL', 0],
|
||||
['updateURL', (style, newValue) => {
|
||||
// always preserve locally installed style's updateUrl
|
||||
if (!/^file:/.test(style.updateUrl)) {
|
||||
style.updateUrl = newValue;
|
||||
}
|
||||
}],
|
||||
['var', 0],
|
||||
['version', 0],
|
||||
]);
|
||||
const MANDATORY_META = ['name', 'namespace', 'version'];
|
||||
const META_VARS = ['text', 'color', 'checkbox', 'select', 'dropdown', 'image'];
|
||||
const META_URLS = [...KNOWN_META.keys()].filter(k => k.endsWith('URL'));
|
||||
|
||||
const BUILDER = {
|
||||
default: {
|
||||
|
@ -221,7 +230,7 @@ var usercss = (() => {
|
|||
}
|
||||
}
|
||||
state.usercssData.vars[result.name] = result;
|
||||
validVar(result);
|
||||
validateVar(result);
|
||||
}
|
||||
|
||||
function createOption(label, value) {
|
||||
|
@ -407,28 +416,39 @@ var usercss = (() => {
|
|||
function doParse() {
|
||||
let match;
|
||||
while ((match = re.exec(text))) {
|
||||
state.key = match[1];
|
||||
if (!(state.key in METAS)) {
|
||||
const key = state.key = match[1];
|
||||
const route = KNOWN_META.get(key);
|
||||
if (route === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (state.key === 'var' || state.key === 'advanced') {
|
||||
if (state.key === 'advanced') {
|
||||
if (key === 'var' || key === 'advanced') {
|
||||
if (key === 'advanced') {
|
||||
state.maybeUSO = true;
|
||||
}
|
||||
parseVar(state);
|
||||
} else {
|
||||
parseStringToEnd(state);
|
||||
usercssData[state.key] = state.value;
|
||||
usercssData[key] = state.value;
|
||||
}
|
||||
if (state.key === 'version') {
|
||||
usercssData[state.key] = normalizeVersion(usercssData[state.key]);
|
||||
validVersion(usercssData[state.key]);
|
||||
let value = state.value;
|
||||
if (key === 'version') {
|
||||
value = usercssData[key] = normalizeVersion(value);
|
||||
validateVersion(value);
|
||||
}
|
||||
if (METAS[state.key]) {
|
||||
style[state.key] = usercssData[state.key];
|
||||
if (META_URLS.includes(key)) {
|
||||
validateUrl(key, value);
|
||||
}
|
||||
switch (typeof route) {
|
||||
case 'function':
|
||||
route(style, value);
|
||||
break;
|
||||
case 'string':
|
||||
style[route] = value;
|
||||
break;
|
||||
default:
|
||||
if (route) {
|
||||
style[key] = value;
|
||||
}
|
||||
if (state.key === 'homepageURL' || state.key === 'supportURL') {
|
||||
validUrl(usercssData[state.key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,12 +466,8 @@ var usercss = (() => {
|
|||
if (state.maybeUSO && !usercssData.preprocessor) {
|
||||
usercssData.preprocessor = 'uso';
|
||||
}
|
||||
if (usercssData.homepageURL) {
|
||||
style.url = usercssData.homepageURL;
|
||||
}
|
||||
|
||||
validate(style);
|
||||
|
||||
validateStyle(style);
|
||||
return style;
|
||||
}
|
||||
|
||||
|
@ -505,42 +521,32 @@ var usercss = (() => {
|
|||
return va[prop];
|
||||
}
|
||||
|
||||
function validate(style) {
|
||||
const {usercssData: data} = style;
|
||||
// mandatory fields
|
||||
for (const prop of ['name', 'namespace', 'version']) {
|
||||
function validateStyle({usercssData: data}) {
|
||||
for (const prop of MANDATORY_META) {
|
||||
if (!data[prop]) {
|
||||
throw new Error(chrome.i18n.getMessage('styleMissingMeta', prop));
|
||||
}
|
||||
}
|
||||
// validate version
|
||||
validVersion(data.version);
|
||||
|
||||
// validate URLs
|
||||
validUrl(data.homepageURL);
|
||||
validUrl(data.supportURL);
|
||||
|
||||
// validate vars
|
||||
for (const key of Object.keys(data.vars)) {
|
||||
validVar(data.vars[key]);
|
||||
}
|
||||
validateVersion(data.version);
|
||||
META_URLS.forEach(k => validateUrl(k, data[k]));
|
||||
Object.keys(data.vars).forEach(k => validateVar(data.vars[k]));
|
||||
}
|
||||
|
||||
function validVersion(version) {
|
||||
function validateVersion(version) {
|
||||
semverCompare(version, '0.0.0');
|
||||
}
|
||||
|
||||
function validUrl(url) {
|
||||
function validateUrl(key, url) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
url = new URL(url);
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
||||
throw new Error(`${url.protocol} is not a valid protocol`);
|
||||
if (!/^https?:/.test(url.protocol)) {
|
||||
throw new Error(`${url.protocol} is not a valid protocol in ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
function validVar(va, value = 'default') {
|
||||
function validateVar(va, value = 'default') {
|
||||
if (va.type === 'select' || va.type === 'dropdown') {
|
||||
if (va.options.every(o => o.name !== va[value])) {
|
||||
throw new Error(chrome.i18n.getMessage('styleMetaErrorSelectValueMismatch'));
|
||||
|
@ -560,7 +566,7 @@ var usercss = (() => {
|
|||
if (oldVars[key] && oldVars[key].value) {
|
||||
vars[key].value = oldVars[key].value;
|
||||
try {
|
||||
validVar(vars[key], 'value');
|
||||
validateVar(vars[key], 'value');
|
||||
} catch (e) {
|
||||
vars[key].value = null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user