Merge branch 'master' into new-uso-urls

This commit is contained in:
tophf 2021-08-12 16:57:07 +03:00
commit 4435a44291
15 changed files with 181 additions and 106 deletions

View File

@ -625,6 +625,18 @@
"message": "Get styles",
"description": "Help link text on the manage page e.g. https://userstyles.org"
},
"linkGetStylesInfo": {
"message": "This archive site was created by a userstyle community member to back up the slow and unresponsive userstyles.org. The archive updates its contents approximately once a day.",
"description": "Info shown when clicking the (i) icon of the uso-archive link in the manager"
},
"linkGetShareStyles": {
"message": "Get and share styles",
"description": "Link text for https://userstyles.world/ on the manage page"
},
"linkGetShareStylesInfo": {
"message": "The new community-driven userstyles.world site is created by userstyle authors in order to replace userstyles.org, which has been so slow and unresponsive for the past year that many authors stopped updating their styles.",
"description": "Info shown when clicking the (i) icon of the userstyles.world link in the manager"
},
"linkStylusWiki": {
"message": "Wiki",
"description": "Wiki link text on the manage page e.g. https://github.com/openstyles/stylus/wiki"
@ -633,10 +645,6 @@
"message": "Translate",
"description": "Transifex link text on the manage page"
},
"linkUSW": {
"message": "Upload and discover styles on userstyles.world",
"description": "Link text for https://userstyles.world/ on the manage page"
},
"linterCSSLintIncompatible": {
"message": "CSSLint doesn't support $preprocessorname$ preprocessor",
"placeholders": {

View File

@ -35,6 +35,9 @@
<div class="actions">
<h2 class="installed" i18n-text="installButtonInstalled"></h2>
<button class="install" i18n-text="installButton"></button>
<a class="configure-usercss" i18n-title="configureStyle" tabindex="0">
<svg class="svg-icon config"><use xlink:href="#svg-icon-config"></use></svg>
</a>
<p id="live-reload-install-hint" hidden></p>
<label class="set-update-url">
<input type="checkbox">
@ -74,6 +77,12 @@
<symbol id="svg-icon-checked" viewBox="0 0 1000 1000">
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,6.8L352.3,609.2L184.4,386.9c-3.2-4.2-8-7-13.2-7.8c-5.3-0.8-10.6,0.6-14.9,3.9L18,487.5c-8.8,6.7-10.6,19.3-3.9,28.1L325,927.2c3.6,4.8,9.3,7.7,15.3,8c0.2,0,0.5,0,0.7,0c5.8,0,11.3-2.5,15.1-6.8L985,212.6C992.3,204.3,991.5,191.6,983.2,184.3z"/>
</symbol>
<symbol id="svg-icon-select-arrow" viewBox="0 0 1792 1792">
<path fill-rule="evenodd" d="M1408 704q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45z"/>
</symbol>
<symbol id="svg-icon-config" viewBox="0 0 16 16">
<path d="M13.3,12.8l1.5-2.6l-2.2-1.5c0-0.2,0.1-0.5,0.1-0.7c0-0.2,0-0.5-0.1-0.7l2.2-1.5l-1.5-2.6l-2.4,1.2 c-0.4-0.3-0.8-0.5-1.2-0.7L9.5,1h-3L6.3,3.7C5.9,3.8,5.5,4.1,5.1,4.4L2.7,3.2L1.2,5.8l2.2,1.5c0,0.2-0.1,0.5-0.1,0.7 c0,0.2,0,0.5,0.1,0.7l-2.2,1.5l1.5,2.6l2.4-1.2c0.4,0.3,0.8,0.5,1.2,0.7L6.5,15h3l0.2-2.7c0.4-0.2,0.8-0.4,1.2-0.7L13.3,12.8z M8,10.3c-1.3,0-2.3-1-2.3-2.3c0-1.3,1-2.3,2.3-2.3c1.3,0,2.3,1,2.3,2.3C10.3,9.3,9.3,10.3,8,10.3z"/>
</symbol>
</svg>
<script src="js/dlg/message-box.js"></script>

View File

@ -305,6 +305,20 @@ label {
animation: none;
}
.configure-usercss .svg-icon.config {
width: 20px;
height: 20px;
margin-top: -3px;
}
#message-box.config-dialog {
width: 0;
height: 0;
background: none;
}
#message-box.config-dialog > div {
box-shadow: 5px 5px 50px rgba(0, 0, 0, 0.75); /* copied from message-box.css + darkened the color */
}
/************ reponsive layouts ************/
@media (max-width: 850px) {
@ -417,6 +431,10 @@ label {
flex-shrink: 0;
margin-right: 1em;
}
#message-box.config-dialog > div {
top: auto;
bottom: 3rem;
}
}
/* Retina-specific stuff here */

View File

@ -1,6 +1,6 @@
/* global $ $create $createLink $$remove */
/* global $ $create $createLink $$remove showSpinner */// dom.js
/* global API */// msg.js
/* global closeCurrentTab */// toolbox.js
/* global closeCurrentTab deepEqual */// toolbox.js
/* global messageBox */
/* global prefs */
/* global preinit */
@ -13,20 +13,16 @@ let installed;
let installedDup;
let liveReload;
let tabId;
let vars;
// "History back" in Firefox (for now) restores the old DOM including the messagebox,
// which stays after installing since we don't want to wait for the fadeout animation before resolving.
document.on('visibilitychange', () => {
if (messageBox.element) messageBox.element.remove();
$$remove('#message-box:not(.config-dialog)');
if (installed) liveReload.onToggled();
});
setTimeout(() => {
if (!cm) {
$('#header').appendChild($create('.lds-spinner',
new Array(12).fill($create('div')).map(e => e.cloneNode())));
}
}, 200);
setTimeout(() => !cm && showSpinner($('#header')), 200);
/*
* Preinit starts to download as early as possible,
@ -187,11 +183,29 @@ function updateMeta(style, dup = installedDup) {
$('.external-link').appendChild(externalLink);
}
Object.assign($('.configure-usercss'), {
hidden: !data.vars,
onclick: openConfigDialog,
});
if (!data.vars) {
$$remove('#message-box.config-dialog');
} else if (!deepEqual(data.vars, vars)) {
vars = data.vars;
// Use the user-customized vars from the installed style
for (const [dk, dv] of Object.entries(dup && dupData.vars || {})) {
const v = vars[dk];
if (v && v.type === dv.type) {
v.value = dv.value;
}
}
openConfigDialog();
}
$('#header').dataset.arrivedFast = performance.now() < 500;
$('#header').classList.add('meta-init');
$('#header').classList.remove('meta-init-error');
setTimeout(() => $$remove('.lds-spinner'), 1000);
setTimeout(() => $$remove('.lds-spinner'), 1000);
showError('');
requestAnimationFrame(adjustCodeHeight);
@ -233,6 +247,11 @@ function updateMeta(style, dup = installedDup) {
)),
]));
}
async function openConfigDialog() {
await require(['/js/dlg/config-dialog']); /* global configDialog */
configDialog(style);
}
}
function showError(err) {

View File

@ -2,12 +2,12 @@
--onoffswitch-width: 60px;
}
#stylus-manage .config-dialog #message-box-contents {
padding: 2em 16px;
.config-dialog {
--pad: 16px;
}
#stylus-popup .config-dialog #message-box-contents {
padding: 8px 16px;
.config-dialog #message-box-contents {
padding: var(--pad);
}
#stylus-popup .config-dialog > div {
@ -33,7 +33,7 @@
display: flex;
padding: .75em 0;
align-items: center;
margin-right: -16px; /* for .config-reset-icon */
margin-right: calc(-1 * var(--pad)); /* for .config-reset-icon */
}
.config-body .select-resizer {
@ -120,14 +120,14 @@
}
.config-reset-icon {
height: 16px;
height: var(--pad);
}
.config-reset-icon .svg-icon {
cursor: pointer;
fill: #aaa;
width: 16px;
height: 16px;
width: var(--pad);
height: var(--pad);
padding: 0 1px;
box-sizing: border-box;
flex-shrink: 0;
@ -139,7 +139,7 @@
#config-autosave-wrapper {
position: relative;
padding: 0 0 0 16px;
padding: 0 0 0 var(--pad);
display: inline-flex;
}

View File

@ -28,8 +28,9 @@ async function configDialog(style) {
let varsInitial = getInitialValues(varsHash);
const elements = [];
const colorpicker = window.colorpicker();
const isPopup = location.href.includes('popup.html');
const isInstaller = location.pathname.startsWith('/install-usercss.html');
const isPopup = location.pathname.startsWith('/popup.html');
const colorpicker = ((window.CodeMirror || {}).prototype || window).colorpicker();
const buttons = {};
buildConfigForm();
@ -122,7 +123,7 @@ async function configDialog(style) {
buttons.close.textContent = t(someDirty ? 'confirmCancel' : 'confirmClose');
}
async function save({anyChangeIsDirty = false} = {}, bgStyle) {
async function save({anyChangeIsDirty = false} = {}) {
for (let delay = 1; saving && delay < 1000; delay *= 2) {
await new Promise(resolve => setTimeout(resolve, delay));
}
@ -132,15 +133,13 @@ async function configDialog(style) {
if (!vars.some(va => va.dirty || anyChangeIsDirty && va.value !== va.savedValue)) {
return;
}
if (!bgStyle) {
bgStyle = await API.styles.get(style.id).catch(() => ({}));
}
const bgStyle = !isInstaller && await API.styles.get(style.id).catch(() => ({}));
style = style.sections ? Object.assign({}, style) : style;
style.enabled = true;
style.sourceCode = null;
style.sections = null;
const styleVars = style.usercssData.vars;
const bgVars = (bgStyle.usercssData || {}).vars || {};
const bgVars = isInstaller ? styleVars : (bgStyle.usercssData || {}).vars || {};
const invalid = [];
let numValid = 0;
for (const va of vars) {
@ -184,7 +183,7 @@ async function configDialog(style) {
}
saving = true;
try {
const newVars = await API.usercss.configVars(style.id, style.usercssData.vars);
const newVars = isInstaller ? styleVars : await API.usercss.configVars(style.id, styleVars);
varsInitial = getInitialValues(newVars);
vars.forEach(va => onchange({target: va.input, justSaved: true}));
renderValues();

View File

@ -40,10 +40,9 @@ messageBox.show = async ({
}) => {
await require(['/js/dlg/message-box.css']);
if (!messageBox.listeners) initOwnListeners();
bindGlobalListeners();
createElement();
bindGlobalListeners();
document.body.appendChild(messageBox.element);
bindElementLiseners();
messageBox._originalFocus = document.activeElement;
// focus the first focusable child but skip the first external link which is usually `feedback`
@ -54,6 +53,9 @@ messageBox.show = async ({
if (focusAccessibility.lastFocusedViaClick && document.activeElement) {
document.activeElement.dataset.focusedViaClick = '';
}
if (document.activeElement === messageBox._originalFocus) {
document.body.focus();
}
if (typeof onshow === 'function') {
onshow(messageBox.element);
@ -132,15 +134,9 @@ messageBox.show = async ({
listening = false;
},
mouseMove(event) {
const x = clamp(event.clientX, 30, innerWidth - 30) - clickX;
const y = clamp(event.clientY, 30, innerHeight - 30) - clickY;
offsetX = x;
offsetY = y;
$('#message-box > div').style.transform =
`translateX(${x}px)
translateY(${y}px)`;
offsetX = clamp(event.clientX, 30, innerWidth - 30) - clickX;
offsetY = clamp(event.clientY, 30, innerHeight - 30) - clickY;
messageBox.element.firstChild.style.transform = `translate(${offsetX}px,${offsetY}px)`;
},
};
}
@ -164,7 +160,7 @@ messageBox.show = async ({
messageBox.element =
$create({id, className}, [
$create([
$create(`#${id}-title`, title),
$create(`#${id}-title`, {onmousedown: messageBox.listeners.mouseDown}, title),
$create(`#${id}-close-icon`, {onclick: messageBox.listeners.closeIcon},
$create('SVG:svg.svg-icon', {viewBox: '0 0 20 20'},
$create('SVG:path', {d: 'M11.69,10l4.55,4.55-1.69,1.69L10,11.69,' +
@ -191,16 +187,11 @@ messageBox.show = async ({
window.on('keydown', messageBox.listeners.key, true);
}
function bindElementLiseners() {
$('#message-box-title').on('mousedown', messageBox.listeners.mouseDown, {passive: 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);
$('#message-box-title').off('mousedown', messageBox.listeners.mouseDown);
}
function removeSelf() {

View File

@ -1,5 +1,6 @@
/* global FIREFOX debounce */// toolbox.js
/* global prefs */
/* global t */// localization.js
'use strict';
/* exported
@ -259,7 +260,7 @@ function moveFocus(rootElement, step) {
const activeIndex = step ? Math.max(step < 0 ? 0 : -1, elements.indexOf(activeEl)) : -1;
const num = elements.length;
if (!step) step = 1;
for (let i = 1; i < num; i++) {
for (let i = 1; i <= num; i++) {
const el = elements[(activeIndex + i * step + num) % num];
if (!el.disabled && el.tabIndex >= 0) {
el.focus();
@ -443,6 +444,7 @@ async function waitForSheet({
document.documentElement.setAttribute('lang', chrome.i18n.getUILanguage());
document.on('keypress', clickDummyLinkOnEnter);
document.on('wheel', changeFocusedInputOnWheel, {capture: true, passive: false});
document.on('click', showTooltipNote);
Promise.resolve().then(async () => {
if (!chrome.app) addFaviconFF();
@ -451,6 +453,7 @@ async function waitForSheet({
});
onDOMready().then(() => {
splitLongTooltips();
debounce(addTooltipsToEllipsized, 500);
window.on('resize', () => debounce(addTooltipsToEllipsized, 100));
});
@ -546,6 +549,34 @@ async function waitForSheet({
}
}
}
function showTooltipNote(event) {
const el = event.target.closest('[data-cmd=note]');
if (el) {
event.preventDefault();
window.messageBoxProxy.show({
className: 'note center-dialog',
contents: el.dataset.title || el.title,
buttons: [t('confirmClose')],
});
}
}
function splitLongTooltips() {
for (const el of $$('[title]')) {
el.dataset.title = el.title;
el.title = el.title.replace(/<\/?\w+>/g, ''); // strip html tags
if (el.title.length < 50) {
continue;
}
const newTitle = el.title
.split('\n')
.map(s => s.replace(/([^.][.。?!]|.{50,60},)\s+/g, '$1\n'))
.map(s => s.replace(/(.{50,80}(?=.{40,}))\s+/g, '$1\n'))
.join('\n');
if (newTitle !== el.title) el.title = newTitle;
}
}
})();
//#endregion

View File

@ -329,13 +329,21 @@
</details>
<div id="manage-text">
<span><a href="https://33kk.github.io/uso-archive/" target="_blank" i18n-text="linkGetStyles"></a></span>
<span>
<a href="https://userstyles.world/" target="_blank" i18n-text="linkGetShareStyles"></a>
<a tabindex="0" i18n-title="linkGetShareStylesInfo" data-cmd="note">
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
</a>
</span>
<span>
<a href="https://33kk.github.io/uso-archive/" target="_blank" i18n-text="linkGetStyles"></a>
<a tabindex="0" i18n-title="linkGetStylesInfo" data-cmd="note">
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
</a>
</span>
<span><a href="https://add0n.com/stylus.html#features" target="_blank" i18n-text="linkGetHelp"></a></span>
<span><a href="https://github.com/openstyles/stylus/wiki" target="_blank" i18n-text="linkStylusWiki"></a></span>
<span><a href="https://www.transifex.com/github-7/Stylus" target="_blank" i18n-text="linkTranslate"></a></span>
<span><a href="https://userstyles.world/" target="_blank" i18n-text-append="linkUSW" id="link-usw">
<img src="https://userstyles.world/favicon.ico">
</a></span>
</div>
</div>
</div>
@ -354,7 +362,6 @@
</symbol>
<symbol id="svg-icon-help" viewBox="0 0 14 16">
<title i18n-text="helpAlt"></title>
<path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path>
</symbol>

View File

@ -36,7 +36,7 @@ function initFilters() {
$('#search-help').onclick = event => {
event.preventDefault();
messageBoxProxy.show({
className: 'help-text',
className: 'help-text center-dialog',
title: t('search'),
contents:
$create('ul',

View File

@ -432,33 +432,17 @@ a:hover {
#manage-text {
display: flex;
flex-wrap: wrap;
align-items: baseline;
padding-top: .35rem;
}
#manage-text > * {
display: flex;
align-items: center;
}
#manage-text > :not(:last-child):after {
content: "|";
margin: 0 .5em;
}
#link-usw {
display: flex;
align-items: center;
margin-top: .5em;
}
#link-usw img {
max-width: 2.5em;
max-height: 2.5em;
margin-right: .75em;
filter: grayscale(1);
transition: filter .5s;
}
#link-usw:hover img {
filter: none;
}
.newUI .entry .svg-icon.checked,
.newUI .entry:hover .svg-icon.checked {
fill: #000;

View File

@ -189,7 +189,7 @@ const sorter = (() => {
async function showHelp(event) {
event.preventDefault();
messageBoxProxy.show({
className: 'help-text',
className: 'help-text center-dialog',
title: t('sortStylesHelpTitle'),
contents:
$create('div',

View File

@ -25,7 +25,6 @@
setupLivePrefs();
setupRadioButtons();
$$('input[min], input[max]').forEach(enforceInputRange);
setTimeout(splitLongTooltips);
if (CHROME_POPUP_BORDER_BUG) {
const borderOption = $('.chrome-no-popup-border');
@ -87,15 +86,6 @@ document.onclick = e => {
.filter(input => prefs.knownKeys.includes(input.id))
.forEach(input => prefs.reset(input.id));
break;
case 'note': {
e.preventDefault();
messageBoxProxy.show({
className: 'note',
contents: target.dataset.title,
buttons: [t('confirmClose')],
});
}
}
};
@ -229,22 +219,6 @@ function setupRadioButtons() {
});
}
function splitLongTooltips() {
for (const el of $$('[title]')) {
el.dataset.title = el.title;
el.title = el.title.replace(/<\/?\w+>/g, ''); // strip html tags
if (el.title.length < 50) {
continue;
}
const newTitle = el.title
.split('\n')
.map(s => s.replace(/([^.][.。?!]|.{50,60},)\s+/g, '$1\n'))
.map(s => s.replace(/(.{50,80}(?=.{40,}))\s+/g, '$1\n'))
.join('\n');
if (newTitle !== el.title) el.title = newTitle;
}
}
function customizeHotkeys() {
// command name -> i18n id
const hotkeys = new Map([

View File

@ -76,8 +76,9 @@ body.search-results-shown {
}
.search-result-title {
display: flex;
align-items: center;
margin-bottom: .5em;
display: block;
color: #555;
overflow-wrap: break-word;
}
@ -196,7 +197,8 @@ body.search-results-shown {
color: darkred;
}
.search-result-meta [data-type="rating"][data-class="none"] dd {
/* Keeping an empty rule so customizers can easily tweak it */
search-result-meta [data-type="rating"][data-class="none"] dd {
}
.search-result-meta [data-type="weekly"],
@ -228,6 +230,28 @@ body.search-results-shown {
cursor: help;
}
[data-error],
[data-error]:hover {
border: calc(var(--pad) / 2) solid red;
border-radius: var(--pad);
padding: calc(var(--pad) / 2);
background: hsl(0, 90%, 85%);
}
[data-error]::after {
content: attr(data-error);
display: block;
color: hsl(0, 100%, 8%);
font-weight: bold;
padding-top: var(--pad);
hyphens: auto;
}
[data-error] .search-result-description {
display: none;
}
[data-error] .search-result-meta {
background: hsla(0, 100%, 90%, .80);
}
.search-results-nav {
flex-direction: row;
text-align: center;

View File

@ -54,6 +54,13 @@
let totalPages = 1;
let ready;
let imgType = '.jpg';
// detect WebP support
$create('img', {
src: 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=',
onload: () => (imgType = '.webp'),
});
const $class = sel => (sel instanceof Node ? sel : $(sel)).classList;
const show = sel => $class(sel).remove('hidden');
const hide = sel => $class(sel).add('hidden');
@ -301,7 +308,9 @@
// screenshot
const elShot = $('.search-result-screenshot', entry);
if (isUsw) {
elShot.src = /^https?:/i.test(shotName) ? shotName : BLANK_PIXEL;
elShot.src = !/^https?:/i.test(shotName) ? BLANK_PIXEL :
imgType !== '.jpg' ? shotName.replace(/\.jpg$/, imgType) :
shotName;
} else {
const auto = URLS.uso + `auto_style_screenshots/${id}${USO_AUTO_PIC_SUFFIX}`;
Object.assign(elShot, {
@ -432,6 +441,7 @@
saveScrollPosition(entry);
installButton.disabled = true;
entry.style.setProperty('pointer-events', 'none', 'important');
delete entry.dataset.error;
if (!isUsw) {
// FIXME: move this to background page and create an API like installUSOStyle
result.pingbackTimer = setTimeout(download, PINGBACK_DELAY,
@ -445,7 +455,8 @@
const style = await API.usercss.install({sourceCode, updateUrl});
renderFullInfo(entry, style);
} catch (reason) {
error(`Error while downloading usoID:${id}\nReason: ${reason}`);
entry.dataset.error = `${t('genericError')}: ${reason}`;
entry.scrollIntoView({behavior: 'smooth', block: 'nearest'});
}
$remove('.lds-spinner', entry);
installButton.disabled = false;