UNPKG

collaborative-input

Version:

Collaborative input and textarea bindings to JSON CRDT

159 lines 6.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InputEditor = void 0; class InputEditor { constructor(str, input) { this.str = str; this.input = input; this.onInput = (event) => { this.emitChange(event); }; this.onSelectionChange = () => { this.onselection(); }; input.addEventListener('input', this.onInput); document.addEventListener('selectionchange', this.onSelectionChange); } get() { return this.input.value; } getLength() { return this.input.value.length; } set(text) { this.input.value = text; } ins(position, text) { const selection = this.getSelection(); const value = this.get(); const next = value.slice(0, position) + text + value.slice(position); this.set(next); if (selection) { let [start, end] = selection; const length = text.length; if (start >= position) start += length; if (end > position) end += length; this.setSelection(start, end, selection[2]); } } del(position, length) { const selection = this.getSelection(); const value = this.get(); const next = value.slice(0, position) + value.slice(position + length); this.set(next); if (selection) { let [start, end] = selection; if (start >= position) start = Math.max(position, start - length); if (end >= position) end = Math.max(position, end - length); this.setSelection(start, end, selection[2]); } } getSelection() { const input = this.input; const { selectionStart, selectionEnd, selectionDirection } = input; const direction = selectionDirection === 'backward' ? -1 : selectionDirection === 'forward' ? 1 : 0; return [ typeof selectionStart === 'number' ? selectionStart : -1, typeof selectionEnd === 'number' ? selectionEnd : -1, direction, ]; } setSelection(start, end, direction) { const input = this.input; input.selectionStart = start > -1 ? start : null; input.selectionEnd = end > -1 ? end : null; input.selectionDirection = direction === -1 ? 'backward' : direction === 1 ? 'forward' : 'none'; } emitChange(event) { var _a, _b; if (event.isComposing) return; switch (event.inputType) { case 'insertText': { const data = event.data; if (!data || data.length !== 1) break; const { selectionStart, selectionEnd } = this.input; if (selectionStart === null || selectionEnd === null) break; if (selectionStart !== selectionEnd) break; if (selectionStart <= 0) break; const selection = this.selection; if (selectionStart - data.length !== selection.start) break; if (typeof selection.end !== 'number' || typeof selection.end !== 'number') break; const remove = selection.end - selection.start; const change = [selection.start, remove, data]; this.onchange([change]); return; } case 'deleteContentBackward': { const { start, end } = this.selection; if (typeof start !== 'number' || typeof end !== 'number') break; const change = start === end ? [start - 1, 1, ''] : [start, end - start, '']; this.onchange([change]); return; } case 'deleteContentForward': { const { start, end } = this.selection; if (typeof start !== 'number' || typeof end !== 'number') break; const change = start === end ? [start, 1, ''] : [start, end - start, '']; this.onchange([change]); return; } case 'deleteByCut': { const { start, end } = this.selection; if (typeof start !== 'number' || typeof end !== 'number') break; if (start === end) break; const min = Math.min(start, end); const max = Math.max(start, end); const view = this.str().view(); const input = this.input; const value = input.value; if (view.length - value.length !== max - min) break; const change = [min, max - min, '']; this.onchange([change]); return; } case 'insertFromPaste': { const { start, end } = this.selection; if (typeof start !== 'number' || typeof end !== 'number') break; const min = Math.min(start, end); const max = Math.max(start, end); const view = this.str().view(); const input = this.input; const value = input.value; const newMax = Math.max((_a = input.selectionStart) !== null && _a !== void 0 ? _a : 0, (_b = input.selectionEnd) !== null && _b !== void 0 ? _b : 0); if (newMax <= min) break; const remove = max - min; const insert = value.slice(min, newMax); if (value.length !== view.length - remove + insert.length) return; const change = [min, remove, insert]; this.onchange([change]); return; } } this.onchange(); } dispose() { this.input.removeEventListener('input', this.onInput); document.removeEventListener('selectionchange', this.onSelectionChange); } } exports.InputEditor = InputEditor; //# sourceMappingURL=InputEditor.js.map