import type { BlockAPI, Caret } from '../../../../types/api'; import { Module } from '../../__module'; import { resolveBlock } from '../../utils/api'; /** * @class CaretAPI * provides with methods to work with caret */ export class CaretAPI extends Module { /** * Available methods * @returns {Caret} */ public get methods(): Caret { return { setToFirstBlock: this.setToFirstBlock, setToLastBlock: this.setToLastBlock, setToPreviousBlock: this.setToPreviousBlock, setToNextBlock: this.setToNextBlock, setToBlock: this.setToBlock, focus: this.focus, updateLastCaretAfterPosition: this.updateLastCaretAfterPosition, }; } /** * Sets caret to the first Block * @param {string} position - position where to set caret * @param {number} offset - caret offset * @returns {boolean} */ private setToFirstBlock = (position: string = this.Blok.Caret.positions.DEFAULT, offset = 0): boolean => { if (!this.Blok.BlockManager.firstBlock) { return false; } this.Blok.Caret.setToBlock(this.Blok.BlockManager.firstBlock, position, offset); return true; }; /** * Sets caret to the last Block * @param {string} position - position where to set caret * @param {number} offset - caret offset * @returns {boolean} */ private setToLastBlock = (position: string = this.Blok.Caret.positions.DEFAULT, offset = 0): boolean => { if (!this.Blok.BlockManager.lastBlock) { return false; } this.Blok.Caret.setToBlock(this.Blok.BlockManager.lastBlock, position, offset); return true; }; /** * Sets caret to the previous Block * @param {string} position - position where to set caret * @param {number} offset - caret offset * @returns {boolean} */ private setToPreviousBlock = ( position: string = this.Blok.Caret.positions.DEFAULT, offset = 0 ): boolean => { if (!this.Blok.BlockManager.previousBlock) { return false; } this.Blok.Caret.setToBlock(this.Blok.BlockManager.previousBlock, position, offset); return true; }; /** * Sets caret to the next Block * @param {string} position - position where to set caret * @param {number} offset - caret offset * @returns {boolean} */ private setToNextBlock = (position: string = this.Blok.Caret.positions.DEFAULT, offset = 0): boolean => { if (!this.Blok.BlockManager.nextBlock) { return false; } this.Blok.Caret.setToBlock(this.Blok.BlockManager.nextBlock, position, offset); return true; }; /** * Sets caret to the Block by passed index * @param blockOrIdOrIndex - either BlockAPI or Block id or Block index * @param position - position where to set caret * @param offset - caret offset * @returns {boolean} */ private setToBlock = ( blockOrIdOrIndex: BlockAPI | BlockAPI['id'] | number, position: string = this.Blok.Caret.positions.DEFAULT, offset = 0 ): boolean => { const block = resolveBlock(blockOrIdOrIndex, this.Blok); if (block === undefined) { return false; } this.Blok.Caret.setToBlock(block, position, offset); return true; }; /** * Sets caret to the Blok * @param {boolean} atEnd - if true, set Caret to the end of the Blok * @returns {boolean} */ private focus = (atEnd = false): boolean => { if (atEnd) { return this.setToLastBlock(this.Blok.Caret.positions.END); } return this.setToFirstBlock(this.Blok.Caret.positions.START); }; /** * Updates the "after" position of the most recent caret undo entry. * Call this after moving the caret asynchronously (e.g., via requestAnimationFrame) * to ensure redo operations restore the caret to the correct location. */ private updateLastCaretAfterPosition = (): void => { this.Blok.YjsManager.updateLastCaretAfterPosition(); }; }