collaborative-input
Version:
Collaborative input and textarea bindings to JSON CRDT
159 lines • 6.26 kB
JavaScript
"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