mirror of
https://github.com/codex-team/editor.js
synced 2026-03-18 08:29:52 +01:00
Implement navigatePrevious()
This commit is contained in:
parent
3004167132
commit
d6f0cc0603
3 changed files with 117 additions and 24 deletions
2
dist/editor.js.map
vendored
2
dist/editor.js.map
vendored
File diff suppressed because one or more lines are too long
|
|
@ -363,7 +363,7 @@ export default class BlockEvents extends Module {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Caret.navigatePrevious()) {
|
||||
if (Caret.navigatePrevious(false)) {
|
||||
Toolbar.close();
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +413,7 @@ export default class BlockEvents extends Module {
|
|||
}
|
||||
|
||||
const navigateNext = isDownPressed || (event.keyCode === _.keyCodes.RIGHT && !this.isRtl);
|
||||
const isNavigated = navigateNext ? this.Editor.Caret.navigateNext(isDownPressed) : this.Editor.Caret.navigatePrevious();
|
||||
const isNavigated = navigateNext ? this.Editor.Caret.navigateNext(isDownPressed) : this.Editor.Caret.navigatePrevious(false);
|
||||
|
||||
if (isNavigated) {
|
||||
/**
|
||||
|
|
@ -462,16 +462,17 @@ export default class BlockEvents extends Module {
|
|||
this.Editor.BlockManager.clearFocused();
|
||||
this.Editor.Toolbar.close();
|
||||
|
||||
const isUpPressed = event.keyCode === _.keyCodes.UP;
|
||||
const shouldEnableCBS = this.Editor.Caret.isAtStart || this.Editor.BlockSelection.anyBlockSelected;
|
||||
|
||||
if (event.shiftKey && event.keyCode === _.keyCodes.UP && shouldEnableCBS) {
|
||||
if (event.shiftKey && isUpPressed && shouldEnableCBS) {
|
||||
this.Editor.CrossBlockSelection.toggleBlockSelectedState(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const navigatePrevious = event.keyCode === _.keyCodes.UP || (event.keyCode === _.keyCodes.LEFT && !this.isRtl);
|
||||
const isNavigated = navigatePrevious ? this.Editor.Caret.navigatePrevious() : this.Editor.Caret.navigateNext(false);
|
||||
const navigatePrevious = isUpPressed || (event.keyCode === _.keyCodes.LEFT && !this.isRtl);
|
||||
const isNavigated = navigatePrevious ? this.Editor.Caret.navigatePrevious(isUpPressed) : this.Editor.Caret.navigateNext(false);
|
||||
|
||||
if (isNavigated) {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -433,27 +433,22 @@ export default class Caret extends Module {
|
|||
* Before moving caret, we should check if caret position is start of the Plugins node
|
||||
* Using {@link Dom#getDeepestNode} to get a last node and match with current selection
|
||||
*
|
||||
* @param {boolean} isUpPressed - Is Up key pressed
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public navigatePrevious(): boolean {
|
||||
const { currentBlock, previousContentfulBlock } = this.Editor.BlockManager;
|
||||
public navigatePrevious(isUpPressed: boolean): boolean {
|
||||
const shouldNavigateToPrevious = this.isAtStart || (isUpPressed && !this.isPreviousLineExisted());
|
||||
const previous = shouldNavigateToPrevious && this.detectPrevious();
|
||||
|
||||
if (!currentBlock) {
|
||||
return false;
|
||||
}
|
||||
if (previous) {
|
||||
const position = isUpPressed ? this.positions.DEFAULT : this.positions.END;
|
||||
|
||||
const { previousInput } = currentBlock;
|
||||
|
||||
if (!previousContentfulBlock && !previousInput) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isAtStart) {
|
||||
/** If previous Tool`s input exists, focus on it. Otherwise set caret to the previous Block */
|
||||
if (!previousInput) {
|
||||
this.setToBlock(previousContentfulBlock, this.positions.END);
|
||||
if (previous.previousInput) {
|
||||
this.setToInput(previous.previousInput, position, previous.upOffset);
|
||||
} else {
|
||||
this.setToInput(previousInput, this.positions.END);
|
||||
this.setToBlock(previous.previousBlock, position, previous.upOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -543,7 +538,7 @@ export default class Caret extends Module {
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO: JSDoc
|
||||
* Detect next position from current position
|
||||
*/
|
||||
private detectNext(): {
|
||||
nextBlock: Block;
|
||||
|
|
@ -574,8 +569,10 @@ export default class Caret extends Module {
|
|||
|
||||
const currentBoundingClientRect = Selection.get().getRangeAt(0)
|
||||
.getBoundingClientRect();
|
||||
|
||||
const range = new Range();
|
||||
const treeWalker = document.createTreeWalker(nextInput ?? nextBlock.firstInput, NodeFilter.SHOW_TEXT);
|
||||
const root = nextInput ?? nextBlock.firstInput;
|
||||
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
||||
|
||||
let node = treeWalker.firstChild();
|
||||
let offset = 0;
|
||||
|
|
@ -612,6 +609,65 @@ export default class Caret extends Module {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect previous position from current position
|
||||
*/
|
||||
private detectPrevious(): {
|
||||
previousBlock: Block;
|
||||
previousInput: HTMLElement;
|
||||
upOffset?: number;
|
||||
} | false {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
const previousInput = BlockManager.currentBlock.previousInput;
|
||||
const previousBlock = BlockManager.previousContentfulBlock;
|
||||
|
||||
if (!previousBlock && !previousInput) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentBoundingClientRect = Selection.get().getRangeAt(0)
|
||||
.getBoundingClientRect();
|
||||
|
||||
const range = new Range();
|
||||
const root = previousInput ?? previousBlock.firstInput;
|
||||
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
||||
|
||||
let node = treeWalker.lastChild();
|
||||
let offset = root.textContent.length - 1;
|
||||
let prevX: number | undefined;
|
||||
|
||||
while (node) {
|
||||
if (!(node instanceof Text)) {
|
||||
throw new Error('Unexpected node type');
|
||||
}
|
||||
|
||||
for (let index = node.length - 1; index >= 0; index--) {
|
||||
range.setStart(node, index);
|
||||
|
||||
const boundingClientRect = range.getBoundingClientRect();
|
||||
|
||||
if (prevX !== undefined && Math.abs(currentBoundingClientRect.x - prevX) < Math.abs(currentBoundingClientRect.x - boundingClientRect.x)) {
|
||||
return {
|
||||
previousBlock,
|
||||
previousInput,
|
||||
upOffset: offset + 1,
|
||||
};
|
||||
}
|
||||
|
||||
offset--;
|
||||
prevX = boundingClientRect.x;
|
||||
}
|
||||
|
||||
node = treeWalker.previousNode();
|
||||
}
|
||||
|
||||
return {
|
||||
previousBlock,
|
||||
previousInput,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all first-level (first child of [contenteditabel]) siblings from passed node
|
||||
* Then you can check it for emptiness
|
||||
|
|
@ -657,13 +713,14 @@ export default class Caret extends Module {
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO: JSDoc
|
||||
* Judge if next line is existed
|
||||
*/
|
||||
private isNextLineExisted(): boolean {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
const currentBoundingClientRect = Selection.get().getRangeAt(0)
|
||||
.getBoundingClientRect();
|
||||
|
||||
const range = new Range();
|
||||
const treeWalker = document.createTreeWalker(BlockManager.currentBlock.currentInput, NodeFilter.SHOW_TEXT);
|
||||
|
||||
|
|
@ -689,4 +746,39 @@ export default class Caret extends Module {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Judge if previous line is existed
|
||||
*/
|
||||
private isPreviousLineExisted(): boolean {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
const currentBoundingClientRect = Selection.get().getRangeAt(0)
|
||||
.getBoundingClientRect();
|
||||
|
||||
const range = new Range();
|
||||
const treeWalker = document.createTreeWalker(BlockManager.currentBlock.currentInput, NodeFilter.SHOW_TEXT);
|
||||
|
||||
let node = treeWalker.lastChild();
|
||||
|
||||
while (node) {
|
||||
if (!(node instanceof Text)) {
|
||||
throw new Error('Unexpected node type');
|
||||
}
|
||||
|
||||
for (let index = node.length - 1; index >= 0; index--) {
|
||||
range.setStart(node, index);
|
||||
|
||||
const boundingClientRect = range.getBoundingClientRect();
|
||||
|
||||
if (boundingClientRect.y < currentBoundingClientRect.y) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
node = treeWalker.previousNode();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue