UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

113 lines (112 loc) 4.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Cursor = void 0; const json_crdt_patch_1 = require("../../../json-crdt-patch"); const constants_1 = require("../slice/constants"); const PersistedSlice_1 = require("../slice/PersistedSlice"); /** * Cursor is a slice that represents an explicitly highlighted place in the * text to the user. The {@link Cursor} is a {@link Range}, it has a `start` * {@link Point} and an `end` {@link Point}. * * The {@link Cursor} can be a caret (collapsed cursor) or a selection (range * expanded cursor). The caret is said to be "collapsed", its `start` and `end` * {@link Point}s are the same. When the selection is said to be "expanded", its * `start` and `end` {@link Point}s are different. * * The `start` {@link Point} is always the one that comes first in the text, it * is less then or equal to the `end` {@link Point} in the spatial (text) order. * * An expanded selection cursor has a *focus* and an *anchor* side. The *focus* * side is the one that moves when the user presses the arrow keys. The *anchor* * side is the one that stays in place when the user presses the arrow keys. The * side of the anchor is determined by the {@link Cursor#anchorSide} property. */ class Cursor extends PersistedSlice_1.PersistedSlice { /** * @todo Remove getter `get` here. */ get anchorSide() { return this.type; } isStartFocused() { return this.type === constants_1.CursorAnchor.End || this.start.cmp(this.end) === 0; } isEndFocused() { return this.type === constants_1.CursorAnchor.Start || this.start.cmp(this.end) === 0; } // ---------------------------------------------------------------- mutations set anchorSide(value) { this.update({ type: value }); } anchor() { return this.anchorSide === constants_1.CursorAnchor.Start ? this.start : this.end; } focus() { return this.anchorSide === constants_1.CursorAnchor.Start ? this.end : this.start; } set(start, end = start, anchorSide = this.anchorSide) { let hasChange = false; if (start.cmp(this.start)) hasChange = true; if (!hasChange && end.cmp(this.end)) hasChange = true; if (!hasChange && anchorSide !== this.anchorSide) hasChange = true; if (!hasChange) return; this.start = start; this.end = end === start ? end.clone() : end; this.update({ range: this, type: anchorSide, }); } /** * Move one of the edges of the cursor to a new point. * * @param point Point to set the edge to. * @param endpoint 0 for "focus", 1 for "anchor". */ setEndpoint(point, endpoint = 0) { if (this.start === this.end) this.end = this.end.clone(); let anchor = this.anchor(); let focus = this.focus(); if (endpoint === 0) focus = point; else anchor = point; if (focus.cmpSpatial(anchor) < 0) this.set(focus, anchor, constants_1.CursorAnchor.End); else this.set(anchor, focus, constants_1.CursorAnchor.Start); } move(move) { const { start, end } = this; const isCaret = start.cmp(end) === 0; start.step(move); if (isCaret) this.set(start); else { end.step(move); this.set(start, end); } } collapseToStart(anchorSide = constants_1.CursorAnchor.Start) { const start = this.start.clone(); start.refAfter(); const end = start.clone(); this.set(start, end, anchorSide); } // ---------------------------------------------------------------- Printable toStringName() { const focusIcon = this.anchorSide === constants_1.CursorAnchor.Start ? '.→|' : '|←.'; return 'Cursor ' + focusIcon + ' ' + (0, json_crdt_patch_1.printTs)(this.chunk.id) + ' #' + this.hash.toString(36); } toStringHeaderName() { const focusIcon = this.anchorSide === constants_1.CursorAnchor.Start ? '.→|' : '|←.'; return `${super.toStringHeaderName()}, ${focusIcon}`; } } exports.Cursor = Cursor;