mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 23:42:23 -04:00
Improve space behavior
This commit is contained in:
parent
ab429ec413
commit
6ccf75a077
3 changed files with 91 additions and 39 deletions
|
@ -117,9 +117,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
const splitOff = activeName.slice(end);
|
const splitOff = activeName.slice(end);
|
||||||
|
|
||||||
activeName = current;
|
activeName = current;
|
||||||
|
// await tag to update its name, so it can normalize correctly
|
||||||
|
await tick();
|
||||||
|
|
||||||
appendTagAndFocusAt(index, splitOff);
|
appendTagAndFocusAt(index, splitOff);
|
||||||
active = null;
|
active = null;
|
||||||
|
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
if (index === active) {
|
if (index === active) {
|
||||||
|
@ -273,7 +275,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeyup(_event: KeyboardEvent): void {
|
function onKeyup(): void {
|
||||||
if (activeName.length === 0) {
|
if (activeName.length === 0) {
|
||||||
autocomplete.hide();
|
autocomplete.hide();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
function isCollapsed(): boolean {
|
||||||
|
return input.selectionStart === input.selectionEnd;
|
||||||
|
}
|
||||||
|
|
||||||
function caretAtStart(): boolean {
|
function caretAtStart(): boolean {
|
||||||
return input.selectionStart === 0 && input.selectionEnd === 0;
|
return input.selectionStart === 0 && input.selectionEnd === 0;
|
||||||
}
|
}
|
||||||
|
@ -34,10 +38,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
return name.length === 0;
|
return name.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalize(): void {
|
|
||||||
name = normalizeTagname(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function joinWithPreviousTag(event: Event): Promise<void> {
|
async function joinWithPreviousTag(event: Event): Promise<void> {
|
||||||
const length = input.value.length;
|
const length = input.value.length;
|
||||||
dispatch("tagjoinprevious");
|
dispatch("tagjoinprevious");
|
||||||
|
@ -48,12 +48,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onBackspace(event: KeyboardEvent): Promise<void> {
|
async function maybeDeleteDelimiter(event: Event, position: number): Promise<void> {
|
||||||
|
if (position > name.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nameUptoCaret = name.slice(0, position);
|
||||||
|
|
||||||
|
if (nameUptoCaret.endsWith("::")) {
|
||||||
|
name = name.slice(0, position - 2) + name.slice(position, name.length);
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
setPosition(position - 2);
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBackspace(event: KeyboardEvent): void {
|
||||||
if (caretAtStart()) {
|
if (caretAtStart()) {
|
||||||
joinWithPreviousTag(event);
|
joinWithPreviousTag(event);
|
||||||
} else if (name.endsWith("::")) {
|
} else {
|
||||||
name = name.slice(0, -2);
|
maybeDeleteDelimiter(event, input.selectionStart!);
|
||||||
event.preventDefault();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,19 +82,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onDelete(event: KeyboardEvent): Promise<void> {
|
function onDelete(event: KeyboardEvent): void {
|
||||||
if (caretAtEnd()) {
|
if (caretAtEnd()) {
|
||||||
joinWithNextTag(event);
|
joinWithNextTag(event);
|
||||||
} else if (name.endsWith("::")) {
|
} else {
|
||||||
name = name.slice(0, -2);
|
maybeDeleteDelimiter(event, input.selectionStart! + 2);
|
||||||
event.preventDefault();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBlur(event: Event): void {
|
function onBlur(): void {
|
||||||
event.preventDefault();
|
name = normalizeTagname(name);
|
||||||
|
|
||||||
normalize();
|
|
||||||
if (name.length === 0) {
|
if (name.length === 0) {
|
||||||
dispatch("tagdelete");
|
dispatch("tagdelete");
|
||||||
}
|
}
|
||||||
|
@ -88,54 +101,91 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEnter(event: Event): void {
|
function onEnter(event: Event): void {
|
||||||
event.preventDefault();
|
|
||||||
dispatch("tagsplit", { start: input.selectionStart, end: input.selectionEnd });
|
dispatch("tagsplit", { start: input.selectionStart, end: input.selectionEnd });
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onDelimiter(event: Event, single: boolean = false): Promise<void> {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const positionStart = input.selectionStart!;
|
||||||
|
const positionEnd = input.selectionEnd!;
|
||||||
|
|
||||||
|
const before = name.slice(0, positionStart);
|
||||||
|
if (before.endsWith("::")) {
|
||||||
|
event.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = `${before}${single ? ":" : "::"}${name.slice(positionEnd, name.length)}`;
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
setPosition(positionStart + (single ? 1 : 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeMovePastDelimiter(event: Event, forwards: boolean): void {
|
||||||
|
const position = input.selectionStart!;
|
||||||
|
|
||||||
|
const before = name.slice(0, position);
|
||||||
|
const after = name.slice(position, name.length);
|
||||||
|
|
||||||
|
if (!forwards && before.endsWith("::")) {
|
||||||
|
setPosition(position - 2);
|
||||||
|
event.preventDefault();
|
||||||
|
} else if (forwards && after.startsWith("::")) {
|
||||||
|
setPosition(position + 2);
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onKeydown(event: KeyboardEvent): void {
|
function onKeydown(event: KeyboardEvent): void {
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
case "Enter":
|
case "Enter":
|
||||||
onEnter(event);
|
onEnter(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Space":
|
case "Space":
|
||||||
// TODO
|
onDelimiter(event);
|
||||||
name += "::";
|
|
||||||
event.preventDefault();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Backspace":
|
case "Backspace":
|
||||||
onBackspace(event);
|
if (isCollapsed()) {
|
||||||
|
onBackspace(event);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Delete":
|
case "Delete":
|
||||||
onDelete(event);
|
if (isCollapsed()) {
|
||||||
|
onDelete(event);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ArrowLeft":
|
case "ArrowLeft":
|
||||||
if (!caretAtStart()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
normalize();
|
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
joinWithPreviousTag(event);
|
joinWithPreviousTag(event);
|
||||||
} else {
|
} else if (caretAtStart()) {
|
||||||
event.preventDefault();
|
|
||||||
dispatch("tagmoveprevious");
|
dispatch("tagmoveprevious");
|
||||||
|
event.preventDefault();
|
||||||
|
} else if (isCollapsed()) {
|
||||||
|
maybeMovePastDelimiter(event, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
if (!caretAtEnd()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
joinWithNextTag(event);
|
joinWithNextTag(event);
|
||||||
} else {
|
} else if (caretAtEnd()) {
|
||||||
event.preventDefault();
|
|
||||||
dispatch("tagmovenext");
|
dispatch("tagmovenext");
|
||||||
|
event.preventDefault();
|
||||||
|
} else if (isCollapsed()) {
|
||||||
|
maybeMovePastDelimiter(event, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.key === ":") {
|
||||||
|
onDelimiter(event, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPaste(event: ClipboardEvent): void {
|
function onPaste(event: ClipboardEvent): void {
|
||||||
|
@ -175,7 +225,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
size="1"
|
size="1"
|
||||||
on:focus
|
on:focus
|
||||||
on:blur={onBlur}
|
on:blur|preventDefault={onBlur}
|
||||||
on:keydown={onKeydown}
|
on:keydown={onKeydown}
|
||||||
on:keydown
|
on:keydown
|
||||||
on:keyup
|
on:keyup
|
||||||
|
|
|
@ -5,10 +5,10 @@ export function normalizeTagname(tagname: string): string {
|
||||||
let trimmed = tagname.trim();
|
let trimmed = tagname.trim();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (trimmed.startsWith("::")) {
|
if (trimmed.startsWith(":")) {
|
||||||
trimmed = trimmed.slice(2).trimStart();
|
trimmed = trimmed.slice(1).trimStart();
|
||||||
} else if (trimmed.endsWith("::")) {
|
} else if (trimmed.endsWith(":")) {
|
||||||
trimmed = trimmed.slice(0, -2).trimEnd();
|
trimmed = trimmed.slice(0, -1).trimEnd();
|
||||||
} else {
|
} else {
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue