add upDownKeyJumps option, remove left/right

This commit is contained in:
tophf 2022-10-03 01:13:29 +03:00
parent b22bbaaec0
commit 79dff2775b
7 changed files with 70 additions and 58 deletions

View File

@ -186,6 +186,10 @@
"message": "Theme",
"description": "Label for the style editor's CSS theme."
},
"cm_arrowKeysTraverse": {
"message": "Arrow keys ↑↓ traverse sections",
"description": "Label for the option in the editor."
},
"colorpickerPaletteHint": {
"message": "Right-click a swatch to cycle through its source lines"
},

View File

@ -338,6 +338,12 @@
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
</label>
</div>
<div class="option sectioned-only">
<label i18n="cm_arrowKeysTraverse">
<input id="editor.arrowKeysTraverse" type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
</label>
</div>
<div class="option">
<label i18n="cm_colorpicker">
<input id="editor.colorpicker" type="checkbox">

View File

@ -67,6 +67,7 @@
k.slice('editor.'.length);
const prefKeys = prefs.knownKeys.filter(k =>
k !== 'editor.colorpicker' && // handled in colorpicker-helper.js
k !== 'editor.arrowKeysTraverse' && // handled in sections-editor.js
prefToCmOpt(k) in CodeMirror.defaults);
const {insertTab, insertSoftTab} = CodeMirror.commands;

View File

@ -75,8 +75,8 @@ html:not(.is-new-style) #heading::before {
right: 24px;
}
/************ checkbox & select************/
.options-column > div[class="option"] {
margin-bottom: 4px;
.options-column > .option {
margin-bottom: .25rem;
}
.options-column > .usercss-only {
@ -107,6 +107,8 @@ label {
}
#sections {
padding-left: var(--header-width);
}
.usercss #sections {
min-height: 0;
height: 100%;
}

View File

@ -31,6 +31,7 @@ function createSection(originalSection, genId, si) {
value: originalSection.code,
});
el.CodeMirror = cm; // used by getAssociatedEditor
cm.el = el;
editor.applyScrollInfo(cm, si);
const changeListeners = new Set();
@ -114,49 +115,10 @@ function createSection(originalSection, genId, si) {
changeGeneration = newGeneration;
emitSectionChange('code');
});
cm.display.wrapper.on('keydown', event => handleKeydown(cm, event), true);
$('.test-regexp', el).onclick = () => updateRegexpTester(true);
initBeautifyButton($('.beautify-section', el), [cm]);
}
function handleKeydown(cm, event) {
if (event.shiftKey || event.altKey || event.metaKey) {
return;
}
const {key} = event;
const {line, ch} = cm.getCursor();
switch (key) {
case 'ArrowLeft':
if (line || ch) {
return;
}
// fallthrough
case 'ArrowUp':
cm = line === 0 && editor.prevEditor(cm, false);
if (!cm) {
return;
}
event.preventDefault();
event.stopPropagation();
cm.setCursor(cm.doc.size - 1, key === 'ArrowLeft' ? 1e20 : ch);
break;
case 'ArrowRight':
if (line < cm.doc.size - 1 || ch < cm.getLine(line).length - 1) {
return;
}
// fallthrough
case 'ArrowDown':
cm = line === cm.doc.size - 1 && editor.nextEditor(cm, false);
if (!cm) {
return;
}
event.preventDefault();
event.stopPropagation();
cm.setCursor(0, 0);
break;
}
}
async function updateRegexpTester(toggle) {
const isLoaded = typeof regexpTester === 'object' ||
toggle && await require(['/edit/regexp-tester']); /* global regexpTester */

View File

@ -6,6 +6,7 @@
/* global createSection */// sections-editor-section.js
/* global editor */
/* global linterMan */
/* global prefs */
/* global styleSectionsEqual */ // sections-util.js
/* global t */// localization.js
'use strict';
@ -21,6 +22,7 @@ function SectionsEditor() {
let sectionOrder = '';
let headerOffset; // in compact mode the header is at the top so it reduces the available height
let cmExtrasHeight; // resize grip + borders
let upDownJumps;
updateMeta();
rerouteHotkeys.toggle(true); // enabled initially because we don't always focus a CodeMirror
@ -30,6 +32,10 @@ function SectionsEditor() {
$('#from-mozilla').on('click', () => showMozillaFormatImport());
document.on('wheel', scrollEntirePageOnCtrlShift, {passive: false});
CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow';
prefs.subscribe('editor.arrowKeysTraverse', (_, val) => {
for (const {cm} of sections) handleKeydownSetup(cm, val);
upDownJumps = val;
}, {runNow: true});
/** @namespace Editor */
Object.assign(editor, {
@ -70,15 +76,15 @@ function SectionsEditor() {
}
},
nextEditor(cm, cycle = true) {
return cycle || cm !== findLast(sections, s => !s.removed).cm
? nextPrevEditor(cm, 1)
nextEditor(cm, upDown) {
return !upDown || cm !== findLast(sections, s => !s.removed).cm
? nextPrevEditor(cm, 1, upDown)
: null;
},
prevEditor(cm, cycle = true) {
return cycle || cm !== sections.find(s => !s.removed).cm
? nextPrevEditor(cm, -1)
prevEditor(cm, upDown) {
return !upDown || cm !== sections.find(s => !s.removed).cm
? nextPrevEditor(cm, -1, upDown)
: null;
},
@ -112,14 +118,16 @@ function SectionsEditor() {
editor.useSavedStyle(newStyle);
},
scrollToEditor(cm) {
const {el} = sections.find(s => s.cm === cm);
const r = el.getBoundingClientRect();
const h = window.innerHeight;
if (r.bottom > h && r.top > 0 ||
r.bottom < h && r.top < 0) {
window.scrollBy(0, (r.top + r.bottom - h) / 2 | 0);
}
scrollToEditor(cm, partial) {
const cc = partial && cm.cursorCoords(true, 'window');
const {top: y1, bottom: y2} = cm.el.getBoundingClientRect();
const rc = container.getBoundingClientRect();
const rcY1 = Math.max(rc.top, 0);
const rcY2 = Math.min(rc.bottom, innerHeight);
const bad = partial
? cc.top < rcY1 || cc.top > rcY2 - 30
: y1 >= rcY1 ^ y2 <= rcY2;
if (bad) window.scrollBy(0, (y1 + y2 - rcY2 + rcY1) / 2 | 0);
},
});
@ -291,10 +299,36 @@ function SectionsEditor() {
}
}
function nextPrevEditor(cm, direction) {
function handleKeydown(event) {
if (event.shiftKey || event.altKey || event.metaKey ||
event.key !== 'ArrowUp' && event.key !== 'ArrowDown') {
return;
}
let pos;
let cm = this.CodeMirror;
const {line, ch} = cm.getCursor();
if (event.key === 'ArrowUp') {
cm = line === 0 && editor.prevEditor(cm, true);
pos = cm && [cm.doc.size - 1, ch];
} else {
cm = line === cm.doc.size - 1 && editor.nextEditor(cm, true);
pos = cm && [0, 0];
}
if (cm) {
cm.setCursor(...pos);
event.preventDefault();
event.stopPropagation();
}
}
function handleKeydownSetup(cm, state) {
cm.display.wrapper[state ? 'on' : 'off']('keydown', handleKeydown, true);
}
function nextPrevEditor(cm, direction, upDown) {
const editors = editor.getEditors();
cm = editors[(editors.indexOf(cm) + direction + editors.length) % editors.length];
editor.scrollToEditor(cm);
editor.scrollToEditor(cm, upDown);
cm.focus();
return cm;
}
@ -577,6 +611,9 @@ function SectionsEditor() {
cm.focus();
editor.scrollToEditor(cm);
}
if (upDownJumps) {
handleKeydownSetup(cm, true);
}
updateSectionOrder();
updateLivePreview();
section.onChange(updateLivePreview);

View File

@ -99,7 +99,7 @@
// "Delete" item in context menu for browsers that don't have it
'editor.contextDelete': false,
'editor.selectByTokens': true,
'editor.arrowKeysTraverse': true,
'editor.appliesToLineWidget': true, // show applies-to line widget on the editor
'editor.autosaveDraft': 10, // seconds
'editor.livePreview': true,