mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
fix formatting and add name to CONTRIBUTORS
This commit is contained in:
parent
e3e46764d7
commit
d76ba13ceb
3 changed files with 58 additions and 56 deletions
|
@ -234,6 +234,7 @@ Emmanuel Ferdman <https://github.com/emmanuel-ferdman>
|
||||||
Sunong2008 <https://github.com/Sunrongguo2008>
|
Sunong2008 <https://github.com/Sunrongguo2008>
|
||||||
Marvin Kopf <marvinkopf@outlook.com>
|
Marvin Kopf <marvinkopf@outlook.com>
|
||||||
Kevin Nakamura <grinkers@grinkers.net>
|
Kevin Nakamura <grinkers@grinkers.net>
|
||||||
|
Felipe Colona <felipedev202@gmail.com>
|
||||||
|
|
||||||
********************
|
********************
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ export interface InputHandlerAPI {
|
||||||
|
|
||||||
export function getMaxOffset(node: Node) {
|
export function getMaxOffset(node: Node) {
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
if(!node.textContent) return 0;
|
if (!node.textContent) { return 0; }
|
||||||
return node.textContent.length;
|
return node.textContent.length;
|
||||||
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||||
return node.childNodes.length;
|
return node.childNodes.length;
|
||||||
|
@ -57,35 +57,34 @@ export function getMaxOffset(node: Node) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCaretPosition(element: Element) {
|
||||||
function getCaretPosition(element: Element){
|
|
||||||
const selection = getSelection(element)!;
|
const selection = getSelection(element)!;
|
||||||
const range = getRange(selection);
|
const range = getRange(selection);
|
||||||
if(!range) return 0;
|
if (!range) { return 0; }
|
||||||
|
|
||||||
let startNode = range.startContainer;
|
let startNode = range.startContainer;
|
||||||
let startOffset = range.startOffset;
|
let startOffset = range.startOffset;
|
||||||
|
|
||||||
if(!range.collapsed){
|
if (!range.collapsed) {
|
||||||
if(selection.anchorNode) startNode = selection.anchorNode;
|
if (selection.anchorNode) { startNode = selection.anchorNode; }
|
||||||
startOffset = selection.anchorOffset;
|
startOffset = selection.anchorOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(startNode.nodeType == Node.TEXT_NODE){
|
if (startNode.nodeType == Node.TEXT_NODE) {
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
for(const node of element.childNodes){
|
for (const node of element.childNodes) {
|
||||||
if(node === startNode) break;
|
if (node === startNode) { break; }
|
||||||
if(node.textContent && node.nodeType == Node.TEXT_NODE) counter += node.textContent.length;
|
if (node.textContent && node.nodeType == Node.TEXT_NODE) { counter += node.textContent.length; }
|
||||||
if(node.nodeName === "BR") counter++;
|
if (node.nodeName === "BR") { counter++; }
|
||||||
}
|
}
|
||||||
counter += startOffset;
|
counter += startOffset;
|
||||||
return counter;
|
return counter;
|
||||||
} else {
|
} else {
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
for(let i = 0; (i < startOffset) && (i < element.childNodes.length); i++){
|
for (let i = 0; (i < startOffset) && (i < element.childNodes.length); i++) {
|
||||||
const node = element.childNodes[i];
|
const node = element.childNodes[i];
|
||||||
if(node.textContent && node.nodeType == Node.TEXT_NODE) counter += node.textContent.length;
|
if (node.textContent && node.nodeType == Node.TEXT_NODE) { counter += node.textContent.length; }
|
||||||
if(node.nodeName === "BR") counter++;
|
if (node.nodeName === "BR") { counter++; }
|
||||||
}
|
}
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
@ -107,12 +106,12 @@ function useInputHandler(): [InputHandlerAPI, SetupInputHandlerAction] {
|
||||||
const config = {
|
const config = {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true
|
subtree: true,
|
||||||
};
|
};
|
||||||
const observer = new MutationObserver(onMutation);
|
const observer = new MutationObserver(onMutation);
|
||||||
|
|
||||||
function onMutation(mutationsList: MutationRecord[], observer){
|
function onMutation(mutationsList: MutationRecord[]) {
|
||||||
const element = <Element>mutationsList[0].target;
|
const element = <Element> mutationsList[0].target;
|
||||||
undoManager.register(element.innerHTML, getMaxOffset(element));
|
undoManager.register(element.innerHTML, getMaxOffset(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,12 +149,12 @@ function useInputHandler(): [InputHandlerAPI, SetupInputHandlerAction] {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onInput(this: Element, event: Event): Promise<void> {
|
async function onInput(this: Element, event: Event): Promise<void> {
|
||||||
if(!hasSetupObserver) {
|
if (!hasSetupObserver) {
|
||||||
observer.observe(this, config);
|
observer.observe(this, config);
|
||||||
hasSetupObserver = true;
|
hasSetupObserver = true;
|
||||||
}
|
}
|
||||||
const position = getCaretPosition(this);
|
const position = getCaretPosition(this);
|
||||||
undoManager.register(this.innerHTML, position-1);
|
undoManager.register(this.innerHTML, position - 1);
|
||||||
undoManager.clearRedoStack();
|
undoManager.clearRedoStack();
|
||||||
await afterInput.dispatch({ event });
|
await afterInput.dispatch({ event });
|
||||||
}
|
}
|
||||||
|
@ -186,12 +185,10 @@ function useInputHandler(): [InputHandlerAPI, SetupInputHandlerAction] {
|
||||||
specialKey.dispatch({ event, action: "enter" });
|
specialKey.dispatch({ event, action: "enter" });
|
||||||
} else if (event.code === "Tab") {
|
} else if (event.code === "Tab") {
|
||||||
specialKey.dispatch({ event, action: "tab" });
|
specialKey.dispatch({ event, action: "tab" });
|
||||||
}
|
} else if ((event.ctrlKey || event.metaKey) && event.key == "z") {
|
||||||
else if((event.ctrlKey || event.metaKey) && event.key == "z"){
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
undoManager.undo(this);
|
undoManager.undo(this);
|
||||||
}
|
} else if ((event.ctrlKey || event.metaKey) && event.key == "y") {
|
||||||
else if((event.ctrlKey || event.metaKey) && event.key == "y"){
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
undoManager.redo(this);
|
undoManager.redo(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { getMaxOffset } from "./input-handler";
|
||||||
type State = {
|
type State = {
|
||||||
content: string;
|
content: string;
|
||||||
position: number;
|
position: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export class UndoManager {
|
export class UndoManager {
|
||||||
private undoStack: State[] = [];
|
private undoStack: State[] = [];
|
||||||
|
@ -13,34 +13,34 @@ export class UndoManager {
|
||||||
private transactionStart: number = 0;
|
private transactionStart: number = 0;
|
||||||
public register = this.debounce(this.pushToUndo, 500, (position: number) => this.transactionStart = position);
|
public register = this.debounce(this.pushToUndo, 500, (position: number) => this.transactionStart = position);
|
||||||
|
|
||||||
public clearRedoStack(){
|
public clearRedoStack() {
|
||||||
if(this.isUpdating) return;
|
if (this.isUpdating) { return; }
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public pushToUndo(content: string): void {
|
public pushToUndo(content: string): void {
|
||||||
if(this.isUpdating) return;
|
if (this.isUpdating) { return; }
|
||||||
if (this.undoStack.length > 0 && this.undoStack[this.undoStack.length-1].content === content) return;
|
if (this.undoStack.length > 0 && this.undoStack[this.undoStack.length - 1].content === content) { return; }
|
||||||
|
|
||||||
const state = {content, position: this.transactionStart}
|
const state = { content, position: this.transactionStart };
|
||||||
this.undoStack.push(state);
|
this.undoStack.push(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private pushToRedo(content: string): void {
|
private pushToRedo(content: string): void {
|
||||||
if (this.redoStack.length > 0 && this.redoStack[this.redoStack.length-1].content === content) return;
|
if (this.redoStack.length > 0 && this.redoStack[this.redoStack.length - 1].content === content) { return; }
|
||||||
|
|
||||||
const state = {content: content, position: this.transactionStart}
|
const state = { content: content, position: this.transactionStart };
|
||||||
this.redoStack.push(state);
|
this.redoStack.push(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo(element: Element): void{
|
public undo(element: Element): void {
|
||||||
this.isUpdating = true;
|
this.isUpdating = true;
|
||||||
const undoedState = this.undoStack.pop();
|
const undoedState = this.undoStack.pop();
|
||||||
if(undoedState) this.pushToRedo(undoedState.content);
|
if (undoedState) { this.pushToRedo(undoedState.content); }
|
||||||
|
|
||||||
let last: State;
|
let last: State;
|
||||||
if(this.undoStack.length <= 0) last = {content: "", position: 0};
|
if (this.undoStack.length <= 0) { last = { content: "", position: 0 }; }
|
||||||
else last = this.undoStack[this.undoStack.length-1];
|
else { last = this.undoStack[this.undoStack.length - 1]; }
|
||||||
element.innerHTML = last.content;
|
element.innerHTML = last.content;
|
||||||
|
|
||||||
const selection = getSelection(element)!;
|
const selection = getSelection(element)!;
|
||||||
|
@ -49,42 +49,44 @@ export class UndoManager {
|
||||||
let counter = this.transactionStart;
|
let counter = this.transactionStart;
|
||||||
let nodeFound: Node | null = null;
|
let nodeFound: Node | null = null;
|
||||||
let nodeOffset = 0;
|
let nodeOffset = 0;
|
||||||
for(const node of element.childNodes){
|
for (const node of element.childNodes) {
|
||||||
let nodeLength = node.textContent?.length || 0;
|
let nodeLength = node.textContent?.length || 0;
|
||||||
if (counter <= nodeLength) {
|
if (counter <= nodeLength) {
|
||||||
nodeFound = node;
|
nodeFound = node;
|
||||||
nodeOffset = counter;
|
nodeOffset = counter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(node.nodeType !== Node.TEXT_NODE) counter--;
|
if (node.nodeType !== Node.TEXT_NODE) { counter--; }
|
||||||
counter -= nodeLength;
|
counter -= nodeLength;
|
||||||
}
|
}
|
||||||
if(!range){
|
if (!range) {
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!nodeFound){
|
if (!nodeFound) {
|
||||||
if(element.lastChild) range?.setStart(element.lastChild as Node, (element.lastChild?.textContent?.length || 0))
|
if (element.lastChild) {
|
||||||
|
range?.setStart(element.lastChild as Node, element.lastChild?.textContent?.length || 0);
|
||||||
|
}
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
selection.removeAllRanges()
|
selection.removeAllRanges();
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let finalOffset = Math.min(nodeOffset, nodeFound.textContent?.length || 0);
|
let finalOffset = Math.min(nodeOffset, nodeFound.textContent?.length || 0);
|
||||||
if(finalOffset > getMaxOffset(nodeFound)) finalOffset = getMaxOffset(nodeFound);
|
if (finalOffset > getMaxOffset(nodeFound)) { finalOffset = getMaxOffset(nodeFound); }
|
||||||
range.setStart(nodeFound, finalOffset);
|
range.setStart(nodeFound, finalOffset);
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
selection.removeAllRanges()
|
selection.removeAllRanges();
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
|
|
||||||
if(this.undoStack.length > 0) this.transactionStart = this.undoStack[this.undoStack.length-1].position;
|
if (this.undoStack.length > 0) { this.transactionStart = this.undoStack[this.undoStack.length - 1].position; }
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public redo(element: Element): void {
|
public redo(element: Element): void {
|
||||||
const redoedState = this.redoStack.pop();
|
const redoedState = this.redoStack.pop();
|
||||||
if(!redoedState) return;
|
if (!redoedState) { return; }
|
||||||
this.transactionStart = redoedState.position;
|
this.transactionStart = redoedState.position;
|
||||||
this.pushToUndo(redoedState.content);
|
this.pushToUndo(redoedState.content);
|
||||||
|
|
||||||
|
@ -97,36 +99,38 @@ export class UndoManager {
|
||||||
let counter = this.transactionStart;
|
let counter = this.transactionStart;
|
||||||
let nodeFound: Node | null = null;
|
let nodeFound: Node | null = null;
|
||||||
let nodeOffset = 0;
|
let nodeOffset = 0;
|
||||||
for(const node of element.childNodes){
|
for (const node of element.childNodes) {
|
||||||
let nodeLength = node.textContent?.length || 0;
|
let nodeLength = node.textContent?.length || 0;
|
||||||
if (counter <= nodeLength) {
|
if (counter <= nodeLength) {
|
||||||
nodeFound = node;
|
nodeFound = node;
|
||||||
nodeOffset = counter;
|
nodeOffset = counter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(node.nodeName === "BR") counter--;
|
if (node.nodeName === "BR") { counter--; }
|
||||||
counter -= nodeLength;
|
counter -= nodeLength;
|
||||||
}
|
}
|
||||||
if(!range){
|
if (!range) {
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!nodeFound){
|
if (!nodeFound) {
|
||||||
if(element.lastChild) range?.setStart(element.lastChild as Node, (element.lastChild?.textContent?.length || 0))
|
if (element.lastChild) {
|
||||||
|
range?.setStart(element.lastChild as Node, element.lastChild?.textContent?.length || 0);
|
||||||
|
}
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
selection.removeAllRanges()
|
selection.removeAllRanges();
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let finalOffset = Math.min(nodeOffset, nodeFound.textContent?.length || 0);
|
let finalOffset = Math.min(nodeOffset, nodeFound.textContent?.length || 0);
|
||||||
if(finalOffset > getMaxOffset(nodeFound)) finalOffset = getMaxOffset(nodeFound);
|
if (finalOffset > getMaxOffset(nodeFound)) { finalOffset = getMaxOffset(nodeFound); }
|
||||||
range.setStart(nodeFound, finalOffset);
|
range.setStart(nodeFound, finalOffset);
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
selection.removeAllRanges()
|
selection.removeAllRanges();
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
|
|
||||||
if(this.redoStack.length > 0) this.transactionStart = this.redoStack[this.redoStack.length-1].position;
|
if (this.redoStack.length > 0) { this.transactionStart = this.redoStack[this.redoStack.length - 1].position; }
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +139,7 @@ export class UndoManager {
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
const isNewTransaction = timeout === undefined;
|
const isNewTransaction = timeout === undefined;
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
if(isNewTransaction) onTransactionStart.call(this, args[1])
|
if (isNewTransaction) { onTransactionStart.call(this, args[1]); }
|
||||||
|
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
func.call(this, args[0]);
|
func.call(this, args[0]);
|
||||||
|
|
Loading…
Reference in a new issue