also resize in manager/installer
This commit is contained in:
parent
6cf9826277
commit
abe1d3ba1b
|
@ -41,12 +41,6 @@ const editor = {
|
|||
document.documentElement.classList.toggle('is-new-style', !editor.style.id);
|
||||
},
|
||||
|
||||
updateHeaderWidth(w) {
|
||||
w = Math.round(Math.max(200, Math.min(innerWidth / 2, w)));
|
||||
document.documentElement.style.setProperty('--header-width', w + 'px');
|
||||
return w;
|
||||
},
|
||||
|
||||
updateTitle(isDirty = editor.dirty.isDirty()) {
|
||||
const {customName, name} = editor.style;
|
||||
document.title = `${
|
||||
|
@ -71,7 +65,6 @@ const baseInit = (() => {
|
|||
Promise.all([
|
||||
loadTheme(),
|
||||
loadKeymaps(),
|
||||
editor.updateHeaderWidth(prefs.get('editor.headerWidth')),
|
||||
])),
|
||||
]),
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
:root {
|
||||
--fixed-padding: unset;
|
||||
--header-width: 280px;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -8,18 +7,6 @@ body {
|
|||
height: 100vh;
|
||||
font: 12px arial,sans-serif;
|
||||
}
|
||||
body.resizing-h {
|
||||
cursor: e-resize;
|
||||
}
|
||||
body.resizing-v {
|
||||
cursor: n-resize;
|
||||
}
|
||||
body.resizing-h > *,
|
||||
body.resizing-v > * {
|
||||
pointer-events: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
|
@ -135,30 +122,6 @@ label {
|
|||
margin-top: 0.1rem;
|
||||
min-height: 1.4rem;
|
||||
}
|
||||
#header-resizer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 6px;
|
||||
cursor: e-resize;
|
||||
border-width: 0 1px;
|
||||
border-style: solid;
|
||||
color: #8888;
|
||||
border-color: currentColor;
|
||||
pointer-events: auto;
|
||||
}
|
||||
#header-resizer:active {
|
||||
border-color: #888;
|
||||
}
|
||||
#header-resizer::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-right: 2px dotted currentColor;
|
||||
left: 2px;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* basic info */
|
||||
#basic-info {
|
||||
|
@ -1090,7 +1053,6 @@ body.linter-disabled .hidden-unless-compact {
|
|||
padding: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
#header-resizer,
|
||||
.fixed-header #header > *:not(#details-wrapper),
|
||||
.fixed-header #options {
|
||||
display: none !important;
|
||||
|
|
|
@ -55,7 +55,6 @@ baseInit.ready.then(async () => {
|
|||
require([
|
||||
'/edit/autocomplete',
|
||||
'/edit/global-search',
|
||||
'/edit/header-resizer',
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
48
global.css
48
global.css
|
@ -265,6 +265,48 @@ input[type="number"][data-focused-via-click]:focus {
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* header resizer */
|
||||
:root {
|
||||
--header-width: 280px;
|
||||
}
|
||||
#header-resizer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 6px;
|
||||
cursor: e-resize;
|
||||
border-width: 0 1px;
|
||||
border-style: solid;
|
||||
color: #8888;
|
||||
border-color: currentColor;
|
||||
pointer-events: auto;
|
||||
}
|
||||
#header-resizer:active {
|
||||
border-color: #888;
|
||||
}
|
||||
#header-resizer::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-right: 2px dotted currentColor;
|
||||
left: 2px;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
body.resizing-h {
|
||||
cursor: e-resize;
|
||||
}
|
||||
body.resizing-v {
|
||||
cursor: n-resize;
|
||||
}
|
||||
body.resizing-h > *,
|
||||
body.resizing-v > * {
|
||||
pointer-events: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
/* header resizer - end */
|
||||
|
||||
@supports (-moz-appearance: none) {
|
||||
.moz-appearance-bug .svg-icon.checked,
|
||||
.moz-appearance-bug .onoffswitch input,
|
||||
|
@ -318,3 +360,9 @@ input[type="number"][data-focused-via-click]:focus {
|
|||
padding: 2px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 850px) {
|
||||
#header-resizer {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="header-resizer"></div>
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="warnings"></div>
|
||||
|
|
|
@ -29,10 +29,9 @@ input:disabled + span {
|
|||
|
||||
#header,
|
||||
.warnings {
|
||||
flex: 0 0 280px;
|
||||
flex: 0 0 var(--header-width);
|
||||
box-sizing: border-box;
|
||||
padding: 1rem;
|
||||
border-right: 1px dashed #aaa;
|
||||
box-shadow: 0 0 50px -18px black;
|
||||
overflow-wrap: break-word;
|
||||
overflow-y: auto;
|
||||
|
|
126
js/dom-on-load.js
Normal file
126
js/dom-on-load.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* global $ $$ focusAccessibility getEventKeyName */// dom.js
|
||||
/* global debounce */// toolbox.js
|
||||
/* global t */// localization.js
|
||||
'use strict';
|
||||
|
||||
/** DOM housekeeping after a page finished loading */
|
||||
|
||||
(() => {
|
||||
splitLongTooltips();
|
||||
addTooltipsToEllipsized();
|
||||
window.on('mousedown', suppressFocusRingOnClick, {passive: true});
|
||||
window.on('keydown', keepFocusRingOnTabbing, {passive: true});
|
||||
window.on('keypress', clickDummyLinkOnEnter);
|
||||
window.on('wheel', changeFocusedInputOnWheel, {capture: true, passive: false});
|
||||
window.on('click', showTooltipNote);
|
||||
window.on('resize', () => debounce(addTooltipsToEllipsized, 100));
|
||||
// Removing transition-suppressor rule
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function changeFocusedInputOnWheel(event) {
|
||||
const el = document.activeElement;
|
||||
if (!el || el !== event.target && !el.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
const isSelect = el.tagName === 'SELECT';
|
||||
if (isSelect || el.tagName === 'INPUT' && el.type === 'range') {
|
||||
const key = isSelect ? 'selectedIndex' : 'valueAsNumber';
|
||||
const old = el[key];
|
||||
const rawVal = old + Math.sign(event.deltaY) * (el.step || 1);
|
||||
el[key] = Math.max(el.min || 0, Math.min(el.max || el.length - 1, rawVal));
|
||||
if (el[key] !== old) {
|
||||
el.dispatchEvent(new Event('change', {bubbles: true}));
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
/** Displays a full text tooltip on buttons with ellipsis overflow and no inherent title */
|
||||
function addTooltipsToEllipsized() {
|
||||
for (const btn of document.getElementsByTagName('button')) {
|
||||
if (btn.title && !btn.titleIsForEllipsis) {
|
||||
continue;
|
||||
}
|
||||
const width = btn.offsetWidth;
|
||||
if (!width || btn.preresizeClientWidth === width) {
|
||||
continue;
|
||||
}
|
||||
btn.preresizeClientWidth = width;
|
||||
if (btn.scrollWidth > width) {
|
||||
const text = btn.textContent;
|
||||
btn.title = text.includes('\u00AD') ? text.replace(/\u00AD/g, '') : text;
|
||||
btn.titleIsForEllipsis = true;
|
||||
} else if (btn.title) {
|
||||
btn.title = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clickDummyLinkOnEnter(e) {
|
||||
if (getEventKeyName(e) === 'Enter') {
|
||||
const a = e.target.closest('a');
|
||||
const isDummy = a && !a.href && a.tabIndex === 0;
|
||||
if (isDummy) a.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
}
|
||||
}
|
||||
|
||||
function keepFocusRingOnTabbing(event) {
|
||||
if (event.key === 'Tab' && !event.ctrlKey && !event.altKey && !event.metaKey) {
|
||||
focusAccessibility.lastFocusedViaClick = false;
|
||||
setTimeout(() => {
|
||||
let el = document.activeElement;
|
||||
if (el) {
|
||||
el = el.closest('[data-focused-via-click]');
|
||||
if (el) delete el.dataset.focusedViaClick;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function suppressFocusRingOnClick({target}) {
|
||||
const el = focusAccessibility.closest(target);
|
||||
if (el) {
|
||||
focusAccessibility.lastFocusedViaClick = true;
|
||||
if (el.dataset.focusedViaClick === undefined) {
|
||||
el.dataset.focusedViaClick = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
166
js/dom.js
166
js/dom.js
|
@ -1,6 +1,5 @@
|
|||
/* global FIREFOX debounce */// toolbox.js
|
||||
/* global FIREFOX */// toolbox.js
|
||||
/* global prefs */
|
||||
/* global t */// localization.js
|
||||
'use strict';
|
||||
|
||||
/* exported
|
||||
|
@ -9,6 +8,7 @@
|
|||
$remove
|
||||
$$remove
|
||||
animateElement
|
||||
focusAccessibility
|
||||
getEventKeyName
|
||||
messageBoxProxy
|
||||
moveFocus
|
||||
|
@ -427,6 +427,8 @@ async function waitForSheet({
|
|||
//#endregion
|
||||
//#region Internals
|
||||
|
||||
const dom = {};
|
||||
|
||||
(() => {
|
||||
|
||||
const Collapsible = {
|
||||
|
@ -459,42 +461,31 @@ async function waitForSheet({
|
|||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.on('mousedown', suppressFocusRingOnClick, {passive: true});
|
||||
window.on('keydown', keepFocusRingOnTabbing, {passive: true});
|
||||
|
||||
const lazyScripts = [
|
||||
'/js/dom-on-load',
|
||||
];
|
||||
const elHtml = document.documentElement;
|
||||
if (!/^Win\d+/.test(navigator.platform)) {
|
||||
document.documentElement.classList.add('non-windows');
|
||||
elHtml.classList.add('non-windows');
|
||||
}
|
||||
// set language for a) CSS :lang pseudo and b) hyphenation
|
||||
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();
|
||||
await prefs.ready;
|
||||
waitForSelector('details[data-pref]', {recur: Collapsible.bindEvents});
|
||||
});
|
||||
|
||||
onDOMready().then(() => {
|
||||
splitLongTooltips();
|
||||
debounce(addTooltipsToEllipsized, 500);
|
||||
window.on('resize', () => debounce(addTooltipsToEllipsized, 100));
|
||||
});
|
||||
|
||||
window.on('load', () => {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, {once: true});
|
||||
|
||||
function addFaviconFF() {
|
||||
elHtml.setAttribute('lang', chrome.i18n.getUILanguage());
|
||||
// set header width and export stuff via `dom.headerResizer`
|
||||
if (/^.(edit|manage|install)/.test(location.pathname)) {
|
||||
const prefId = `${RegExp.$1 === 'edit' ? 'editor' : RegExp.$1}.headerWidth`;
|
||||
const HR = dom.headerResizer = {
|
||||
prefId,
|
||||
setDomProp(width) {
|
||||
width = Math.round(Math.max(200, Math.min(innerWidth / 2, width)));
|
||||
elHtml.style.setProperty('--header-width', width + 'px');
|
||||
return width;
|
||||
},
|
||||
};
|
||||
prefs.ready.then(() => HR.setDomProp(prefs.get(prefId)));
|
||||
lazyScripts.push('/js/header-resizer');
|
||||
}
|
||||
// add favicon in FF
|
||||
if (FIREFOX) {
|
||||
const iconset = ['', 'light/'][prefs.get('iconset')] || '';
|
||||
for (const size of [38, 32, 19, 16]) {
|
||||
document.head.appendChild($create('link', {
|
||||
|
@ -504,105 +495,12 @@ async function waitForSheet({
|
|||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function changeFocusedInputOnWheel(event) {
|
||||
const el = document.activeElement;
|
||||
if (!el || el !== event.target && !el.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
const isSelect = el.tagName === 'SELECT';
|
||||
if (isSelect || el.tagName === 'INPUT' && el.type === 'range') {
|
||||
const key = isSelect ? 'selectedIndex' : 'valueAsNumber';
|
||||
const old = el[key];
|
||||
const rawVal = old + Math.sign(event.deltaY) * (el.step || 1);
|
||||
el[key] = Math.max(el.min || 0, Math.min(el.max || el.length - 1, rawVal));
|
||||
if (el[key] !== old) {
|
||||
el.dispatchEvent(new Event('change', {bubbles: true}));
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
/** Displays a full text tooltip on buttons with ellipsis overflow and no inherent title */
|
||||
function addTooltipsToEllipsized() {
|
||||
for (const btn of document.getElementsByTagName('button')) {
|
||||
if (btn.title && !btn.titleIsForEllipsis) {
|
||||
continue;
|
||||
}
|
||||
const width = btn.offsetWidth;
|
||||
if (!width || btn.preresizeClientWidth === width) {
|
||||
continue;
|
||||
}
|
||||
btn.preresizeClientWidth = width;
|
||||
if (btn.scrollWidth > width) {
|
||||
const text = btn.textContent;
|
||||
btn.title = text.includes('\u00AD') ? text.replace(/\u00AD/g, '') : text;
|
||||
btn.titleIsForEllipsis = true;
|
||||
} else if (btn.title) {
|
||||
btn.title = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clickDummyLinkOnEnter(e) {
|
||||
if (getEventKeyName(e) === 'Enter') {
|
||||
const a = e.target.closest('a');
|
||||
const isDummy = a && !a.href && a.tabIndex === 0;
|
||||
if (isDummy) a.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
}
|
||||
}
|
||||
|
||||
function keepFocusRingOnTabbing(event) {
|
||||
if (event.key === 'Tab' && !event.ctrlKey && !event.altKey && !event.metaKey) {
|
||||
focusAccessibility.lastFocusedViaClick = false;
|
||||
setTimeout(() => {
|
||||
let el = document.activeElement;
|
||||
if (el) {
|
||||
el = el.closest('[data-focused-via-click]');
|
||||
if (el) delete el.dataset.focusedViaClick;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function suppressFocusRingOnClick({target}) {
|
||||
const el = focusAccessibility.closest(target);
|
||||
if (el) {
|
||||
focusAccessibility.lastFocusedViaClick = true;
|
||||
if (el.dataset.focusedViaClick === undefined) {
|
||||
el.dataset.focusedViaClick = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
prefs.ready.then(() => {
|
||||
waitForSelector('details[data-pref]', {recur: Collapsible.bindEvents});
|
||||
});
|
||||
window.on('load', () => {
|
||||
require(lazyScripts);
|
||||
}, {once: true});
|
||||
})();
|
||||
|
||||
//#endregion
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
/* global $ $$ */// dom.js
|
||||
/* global editor */
|
||||
/* global $ $$ dom */// dom.js
|
||||
/* global debounce */// toolbox.js
|
||||
/* global prefs */
|
||||
'use strict';
|
||||
|
||||
(function HeaderResizer() {
|
||||
const PREF_ID = 'editor.headerWidth';
|
||||
(() => {
|
||||
const HR = dom.headerResizer;
|
||||
const el = $('#header-resizer');
|
||||
let curW, offset, active;
|
||||
prefs.subscribe(PREF_ID, (key, val) => {
|
||||
prefs.subscribe(HR.prefId, (key, val) => {
|
||||
if (!active && val !== curW) {
|
||||
getCurWidth();
|
||||
setWidth(val);
|
||||
|
@ -43,11 +42,11 @@
|
|||
}
|
||||
|
||||
function save() {
|
||||
prefs.set(PREF_ID, curW);
|
||||
prefs.set(HR.prefId, curW);
|
||||
}
|
||||
|
||||
function setWidth(w) {
|
||||
const delta = (w = editor.updateHeaderWidth(w)) - curW;
|
||||
const delta = (w = HR.setDomProp(w)) - curW;
|
||||
if (delta) {
|
||||
curW = w;
|
||||
for (const el of $$('.CodeMirror-linewidget[style*="width:"]')) {
|
|
@ -99,7 +99,6 @@
|
|||
|
||||
'editor.appliesToLineWidget': true, // show applies-to line widget on the editor
|
||||
'editor.livePreview': true,
|
||||
'editor.headerWidth': 280,
|
||||
|
||||
// show CSS colors as clickable colored rectangles
|
||||
'editor.colorpicker': true,
|
||||
|
@ -124,6 +123,10 @@
|
|||
'badgeDisabled': '#8B0000', // badge background color when disabled
|
||||
'badgeNormal': '#006666', // badge background color
|
||||
|
||||
'editor.headerWidth': 280,
|
||||
'install.headerWidth': 280,
|
||||
'manage.headerWidth': 280,
|
||||
|
||||
'popupWidth': 246, // popup width in pixels
|
||||
|
||||
'updateInterval': 24, // user-style automatic update interval, hours (0 = disable)
|
||||
|
|
|
@ -354,6 +354,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="header-resizer"></div>
|
||||
</div>
|
||||
|
||||
<div id="installed"></div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
:root {
|
||||
--header-width: 280px;
|
||||
--name-padding-left: 20px;
|
||||
--name-padding-right: 40px;
|
||||
--actions-width: 75px;
|
||||
|
@ -52,7 +51,6 @@ a:hover {
|
|||
position: fixed;
|
||||
top: 0;
|
||||
padding: 1rem;
|
||||
border-right: 1px dashed #AAA;
|
||||
box-shadow: 0 0 50px -18px black;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
|
|
Loading…
Reference in New Issue
Block a user