resizable header panel (#1378)
This commit is contained in:
parent
cce483dd22
commit
8ddeef221b
|
@ -501,6 +501,10 @@
|
||||||
"gettingStyles": {
|
"gettingStyles": {
|
||||||
"message": "Getting all styles..."
|
"message": "Getting all styles..."
|
||||||
},
|
},
|
||||||
|
"headerResizerHint": {
|
||||||
|
"message": "Hold Shift to resize only in this type of UI, i.e. editor, manager, installer",
|
||||||
|
"description": "Tooltip for the header panel resizer"
|
||||||
|
},
|
||||||
"helpAlt": {
|
"helpAlt": {
|
||||||
"message": "Help",
|
"message": "Help",
|
||||||
"description": "Alternate text for help buttons"
|
"description": "Alternate text for help buttons"
|
||||||
|
|
|
@ -466,6 +466,7 @@
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="header-resizer" i18n-title="headerResizerHint"></div>
|
||||||
<div id="footer" class="hidden">
|
<div id="footer" class="hidden">
|
||||||
<a href="https://github.com/openstyles/stylus/wiki/Usercss"
|
<a href="https://github.com/openstyles/stylus/wiki/Usercss"
|
||||||
i18n-text="externalUsercssDocument"
|
i18n-text="externalUsercssDocument"
|
||||||
|
|
|
@ -90,13 +90,12 @@ label {
|
||||||
|
|
||||||
/************ header ************/
|
/************ header ************/
|
||||||
#header {
|
#header {
|
||||||
width: 280px;
|
width: var(--header-width);
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-right: 1px dashed #AAA;
|
|
||||||
box-shadow: 0 0 3rem -1.2rem black;
|
box-shadow: 0 0 3rem -1.2rem black;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
@ -107,7 +106,7 @@ label {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
#sections {
|
#sections {
|
||||||
padding-left: 280px;
|
padding-left: var(--header-width);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -745,7 +744,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
||||||
}
|
}
|
||||||
#help-popup.big {
|
#help-popup.big {
|
||||||
box-shadow: rgba(0, 0, 0, 0.45) 0px 0px 0px 100000px !important;
|
box-shadow: rgba(0, 0, 0, 0.45) 0px 0px 0px 100000px !important;
|
||||||
left: calc(280px - 3rem);
|
left: calc(var(--header-width) - 3rem);
|
||||||
}
|
}
|
||||||
#help-popup.big .CodeMirror {
|
#help-popup.big .CodeMirror {
|
||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
|
|
|
@ -381,8 +381,7 @@ function createResizeGrip(cm) {
|
||||||
cm.display.lineDiv.offsetParent.offsetTop +
|
cm.display.lineDiv.offsetParent.offsetTop +
|
||||||
/* borders */
|
/* borders */
|
||||||
wrapper.offsetHeight - wrapper.clientHeight;
|
wrapper.offsetHeight - wrapper.clientHeight;
|
||||||
wrapper.style.pointerEvents = 'none';
|
document.body.classList.add('resizing-v');
|
||||||
document.body.style.cursor = 's-resize';
|
|
||||||
document.on('mousemove', resize);
|
document.on('mousemove', resize);
|
||||||
document.on('mouseup', resizeStop);
|
document.on('mouseup', resizeStop);
|
||||||
|
|
||||||
|
@ -398,8 +397,7 @@ function createResizeGrip(cm) {
|
||||||
function resizeStop() {
|
function resizeStop() {
|
||||||
document.off('mouseup', resizeStop);
|
document.off('mouseup', resizeStop);
|
||||||
document.off('mousemove', resize);
|
document.off('mousemove', resize);
|
||||||
wrapper.style.pointerEvents = '';
|
document.body.classList.remove('resizing-v');
|
||||||
document.body.style.cursor = '';
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
48
global.css
48
global.css
|
@ -265,6 +265,48 @@ input[type="number"][data-focused-via-click]:focus {
|
||||||
box-shadow: none;
|
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) {
|
@supports (-moz-appearance: none) {
|
||||||
.moz-appearance-bug .svg-icon.checked,
|
.moz-appearance-bug .svg-icon.checked,
|
||||||
.moz-appearance-bug .onoffswitch input,
|
.moz-appearance-bug .onoffswitch input,
|
||||||
|
@ -318,3 +360,9 @@ input[type="number"][data-focused-via-click]:focus {
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 850px) {
|
||||||
|
#header-resizer {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="header-resizer" i18n-title="headerResizerHint"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="warnings"></div>
|
<div class="warnings"></div>
|
||||||
|
|
|
@ -29,10 +29,9 @@ input:disabled + span {
|
||||||
|
|
||||||
#header,
|
#header,
|
||||||
.warnings {
|
.warnings {
|
||||||
flex: 0 0 280px;
|
flex: 0 0 var(--header-width);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-right: 1px dashed #aaa;
|
|
||||||
box-shadow: 0 0 50px -18px black;
|
box-shadow: 0 0 50px -18px black;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
124
js/dom-on-load.js
Normal file
124
js/dom-on-load.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
163
js/dom.js
163
js/dom.js
|
@ -1,6 +1,5 @@
|
||||||
/* global FIREFOX debounce */// toolbox.js
|
/* global FIREFOX */// toolbox.js
|
||||||
/* global prefs */
|
/* global prefs */
|
||||||
/* global t */// localization.js
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/* exported
|
/* exported
|
||||||
|
@ -9,9 +8,11 @@
|
||||||
$remove
|
$remove
|
||||||
$$remove
|
$$remove
|
||||||
animateElement
|
animateElement
|
||||||
|
focusAccessibility
|
||||||
getEventKeyName
|
getEventKeyName
|
||||||
messageBoxProxy
|
messageBoxProxy
|
||||||
moveFocus
|
moveFocus
|
||||||
|
onDOMready
|
||||||
scrollElementIntoView
|
scrollElementIntoView
|
||||||
setupLivePrefs
|
setupLivePrefs
|
||||||
showSpinner
|
showSpinner
|
||||||
|
@ -427,6 +428,8 @@ async function waitForSheet({
|
||||||
//#endregion
|
//#endregion
|
||||||
//#region Internals
|
//#region Internals
|
||||||
|
|
||||||
|
const dom = {};
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
|
|
||||||
const Collapsible = {
|
const Collapsible = {
|
||||||
|
@ -459,42 +462,33 @@ async function waitForSheet({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const lazyScripts = [
|
||||||
window.on('mousedown', suppressFocusRingOnClick, {passive: true});
|
'/js/dom-on-load',
|
||||||
window.on('keydown', keepFocusRingOnTabbing, {passive: true});
|
];
|
||||||
|
const elHtml = document.documentElement;
|
||||||
if (!/^Win\d+/.test(navigator.platform)) {
|
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
|
// set language for a) CSS :lang pseudo and b) hyphenation
|
||||||
document.documentElement.setAttribute('lang', chrome.i18n.getUILanguage());
|
elHtml.setAttribute('lang', chrome.i18n.getUILanguage());
|
||||||
document.on('keypress', clickDummyLinkOnEnter);
|
// set up header width resizer
|
||||||
document.on('wheel', changeFocusedInputOnWheel, {capture: true, passive: false});
|
const HW = 'headerWidth.';
|
||||||
document.on('click', showTooltipNote);
|
const HWprefId = HW + location.pathname.match(/^.(\w*)/)[1];
|
||||||
|
if (prefs.knownKeys.includes(HWprefId)) {
|
||||||
Promise.resolve().then(async () => {
|
Object.assign(dom, {
|
||||||
if (!chrome.app) addFaviconFF();
|
HW,
|
||||||
await prefs.ready;
|
HWprefId,
|
||||||
waitForSelector('details[data-pref]', {recur: Collapsible.bindEvents});
|
setHWProp(width) {
|
||||||
|
width = Math.round(Math.max(200, Math.min(innerWidth / 3, Number(width) || 0)));
|
||||||
|
elHtml.style.setProperty('--header-width', width + 'px');
|
||||||
|
return width;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
prefs.ready.then(() => dom.setHWProp(prefs.get(HWprefId)));
|
||||||
onDOMready().then(() => {
|
lazyScripts.push('/js/header-resizer');
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
// add favicon in FF
|
||||||
}, {once: true});
|
if (FIREFOX) {
|
||||||
|
|
||||||
function addFaviconFF() {
|
|
||||||
const iconset = ['', 'light/'][prefs.get('iconset')] || '';
|
const iconset = ['', 'light/'][prefs.get('iconset')] || '';
|
||||||
for (const size of [38, 32, 19, 16]) {
|
for (const size of [38, 32, 19, 16]) {
|
||||||
document.head.appendChild($create('link', {
|
document.head.appendChild($create('link', {
|
||||||
|
@ -504,105 +498,12 @@ async function waitForSheet({
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
prefs.ready.then(() => {
|
||||||
function changeFocusedInputOnWheel(event) {
|
waitForSelector('details[data-pref]', {recur: Collapsible.bindEvents});
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
window.on('load', () => {
|
||||||
}
|
require(lazyScripts);
|
||||||
|
}, {once: true});
|
||||||
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
|
//#endregion
|
||||||
|
|
48
js/header-resizer.js
Normal file
48
js/header-resizer.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* global $ $$ dom */// dom.js
|
||||||
|
/* global prefs */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
let curW = $('#header').offsetWidth;
|
||||||
|
let offset, perPage;
|
||||||
|
prefs.subscribe(dom.HWprefId, (key, val) => setWidth(val));
|
||||||
|
$('#header-resizer').onmousedown = e => {
|
||||||
|
if (e.button) return;
|
||||||
|
offset = curW - e.clientX;
|
||||||
|
perPage = e.shiftKey;
|
||||||
|
document.body.classList.add('resizing-h');
|
||||||
|
document.on('mousemove', resize);
|
||||||
|
document.on('mouseup', resizeStop);
|
||||||
|
};
|
||||||
|
|
||||||
|
function resize(e) {
|
||||||
|
setWidth(offset + e.clientX);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeStop() {
|
||||||
|
document.off('mouseup', resizeStop);
|
||||||
|
document.off('mousemove', resize);
|
||||||
|
document.body.classList.remove('resizing-h');
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
if (perPage) {
|
||||||
|
prefs.set(dom.HWprefId, curW);
|
||||||
|
} else {
|
||||||
|
for (const k of prefs.knownKeys) {
|
||||||
|
if (k.startsWith(dom.HW)) prefs.set(k, curW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setWidth(w) {
|
||||||
|
const delta = (w = dom.setHWProp(w)) - curW;
|
||||||
|
if (delta) {
|
||||||
|
curW = w;
|
||||||
|
for (const el of $$('.CodeMirror-linewidget[style*="width:"]')) {
|
||||||
|
el.style.width = parseFloat(el.style.width) - delta + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
|
@ -123,6 +123,12 @@
|
||||||
'badgeDisabled': '#8B0000', // badge background color when disabled
|
'badgeDisabled': '#8B0000', // badge background color when disabled
|
||||||
'badgeNormal': '#006666', // badge background color
|
'badgeNormal': '#006666', // badge background color
|
||||||
|
|
||||||
|
/* Using separate values instead of a single {} to ensure type control.
|
||||||
|
* Sub-key is the first word in the html's file name. */
|
||||||
|
'headerWidth.edit': 280,
|
||||||
|
'headerWidth.install': 280,
|
||||||
|
'headerWidth.manage': 280,
|
||||||
|
|
||||||
'popupWidth': 246, // popup width in pixels
|
'popupWidth': 246, // popup width in pixels
|
||||||
|
|
||||||
'updateInterval': 24, // user-style automatic update interval, hours (0 = disable)
|
'updateInterval': 24, // user-style automatic update interval, hours (0 = disable)
|
||||||
|
|
|
@ -354,6 +354,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="header-resizer" i18n-title="headerResizerHint"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="installed"></div>
|
<div id="installed"></div>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
:root {
|
:root {
|
||||||
--header-width: 280px;
|
|
||||||
--name-padding-left: 20px;
|
--name-padding-left: 20px;
|
||||||
--name-padding-right: 40px;
|
--name-padding-right: 40px;
|
||||||
--actions-width: 75px;
|
--actions-width: 75px;
|
||||||
|
@ -52,7 +51,6 @@ a:hover {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-right: 1px dashed #AAA;
|
|
||||||
box-shadow: 0 0 50px -18px black;
|
box-shadow: 0 0 50px -18px black;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user