first commit
This commit is contained in:
12
public/assets/quill/core/composition.d.ts
vendored
Normal file
12
public/assets/quill/core/composition.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import type Scroll from '../blots/scroll.js';
|
||||
import Emitter from './emitter.js';
|
||||
declare class Composition {
|
||||
private scroll;
|
||||
private emitter;
|
||||
isComposing: boolean;
|
||||
constructor(scroll: Scroll, emitter: Emitter);
|
||||
private setupListeners;
|
||||
private handleCompositionStart;
|
||||
private handleCompositionEnd;
|
||||
}
|
||||
export default Composition;
|
||||
44
public/assets/quill/core/composition.js
Normal file
44
public/assets/quill/core/composition.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import Embed from '../blots/embed.js';
|
||||
import Emitter from './emitter.js';
|
||||
class Composition {
|
||||
isComposing = false;
|
||||
constructor(scroll, emitter) {
|
||||
this.scroll = scroll;
|
||||
this.emitter = emitter;
|
||||
this.setupListeners();
|
||||
}
|
||||
setupListeners() {
|
||||
this.scroll.domNode.addEventListener('compositionstart', event => {
|
||||
if (!this.isComposing) {
|
||||
this.handleCompositionStart(event);
|
||||
}
|
||||
});
|
||||
this.scroll.domNode.addEventListener('compositionend', event => {
|
||||
if (this.isComposing) {
|
||||
// Webkit makes DOM changes after compositionend, so we use microtask to
|
||||
// ensure the order.
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=31902
|
||||
queueMicrotask(() => {
|
||||
this.handleCompositionEnd(event);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
handleCompositionStart(event) {
|
||||
const blot = event.target instanceof Node ? this.scroll.find(event.target, true) : null;
|
||||
if (blot && !(blot instanceof Embed)) {
|
||||
this.emitter.emit(Emitter.events.COMPOSITION_BEFORE_START, event);
|
||||
this.scroll.batchStart();
|
||||
this.emitter.emit(Emitter.events.COMPOSITION_START, event);
|
||||
this.isComposing = true;
|
||||
}
|
||||
}
|
||||
handleCompositionEnd(event) {
|
||||
this.emitter.emit(Emitter.events.COMPOSITION_BEFORE_END, event);
|
||||
this.scroll.batchEnd();
|
||||
this.emitter.emit(Emitter.events.COMPOSITION_END, event);
|
||||
this.isComposing = false;
|
||||
}
|
||||
}
|
||||
export default Composition;
|
||||
//# sourceMappingURL=composition.js.map
|
||||
1
public/assets/quill/core/composition.js.map
Normal file
1
public/assets/quill/core/composition.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"composition.js","names":["Embed","Emitter","Composition","isComposing","constructor","scroll","emitter","setupListeners","domNode","addEventListener","event","handleCompositionStart","queueMicrotask","handleCompositionEnd","blot","target","Node","find","emit","events","COMPOSITION_BEFORE_START","batchStart","COMPOSITION_START","COMPOSITION_BEFORE_END","batchEnd","COMPOSITION_END"],"sources":["../../src/core/composition.ts"],"sourcesContent":["import Embed from '../blots/embed.js';\nimport type Scroll from '../blots/scroll.js';\nimport Emitter from './emitter.js';\n\nclass Composition {\n isComposing = false;\n\n constructor(\n private scroll: Scroll,\n private emitter: Emitter,\n ) {\n this.setupListeners();\n }\n\n private setupListeners() {\n this.scroll.domNode.addEventListener('compositionstart', (event) => {\n if (!this.isComposing) {\n this.handleCompositionStart(event);\n }\n });\n\n this.scroll.domNode.addEventListener('compositionend', (event) => {\n if (this.isComposing) {\n // Webkit makes DOM changes after compositionend, so we use microtask to\n // ensure the order.\n // https://bugs.webkit.org/show_bug.cgi?id=31902\n queueMicrotask(() => {\n this.handleCompositionEnd(event);\n });\n }\n });\n }\n\n private handleCompositionStart(event: CompositionEvent) {\n const blot =\n event.target instanceof Node\n ? this.scroll.find(event.target, true)\n : null;\n\n if (blot && !(blot instanceof Embed)) {\n this.emitter.emit(Emitter.events.COMPOSITION_BEFORE_START, event);\n this.scroll.batchStart();\n this.emitter.emit(Emitter.events.COMPOSITION_START, event);\n this.isComposing = true;\n }\n }\n\n private handleCompositionEnd(event: CompositionEvent) {\n this.emitter.emit(Emitter.events.COMPOSITION_BEFORE_END, event);\n this.scroll.batchEnd();\n this.emitter.emit(Emitter.events.COMPOSITION_END, event);\n this.isComposing = false;\n }\n}\n\nexport default Composition;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,mBAAmB;AAErC,OAAOC,OAAO,MAAM,cAAc;AAElC,MAAMC,WAAW,CAAC;EAChBC,WAAW,GAAG,KAAK;EAEnBC,WAAWA,CACDC,MAAc,EACdC,OAAgB,EACxB;IAAA,KAFQD,MAAc,GAAdA,MAAc;IAAA,KACdC,OAAgB,GAAhBA,OAAgB;IAExB,IAAI,CAACC,cAAc,CAAC,CAAC;EACvB;EAEQA,cAAcA,CAAA,EAAG;IACvB,IAAI,CAACF,MAAM,CAACG,OAAO,CAACC,gBAAgB,CAAC,kBAAkB,EAAGC,KAAK,IAAK;MAClE,IAAI,CAAC,IAAI,CAACP,WAAW,EAAE;QACrB,IAAI,CAACQ,sBAAsB,CAACD,KAAK,CAAC;MACpC;IACF,CAAC,CAAC;IAEF,IAAI,CAACL,MAAM,CAACG,OAAO,CAACC,gBAAgB,CAAC,gBAAgB,EAAGC,KAAK,IAAK;MAChE,IAAI,IAAI,CAACP,WAAW,EAAE;QACpB;QACA;QACA;QACAS,cAAc,CAAC,MAAM;UACnB,IAAI,CAACC,oBAAoB,CAACH,KAAK,CAAC;QAClC,CAAC,CAAC;MACJ;IACF,CAAC,CAAC;EACJ;EAEQC,sBAAsBA,CAACD,KAAuB,EAAE;IACtD,MAAMI,IAAI,GACRJ,KAAK,CAACK,MAAM,YAAYC,IAAI,GACxB,IAAI,CAACX,MAAM,CAACY,IAAI,CAACP,KAAK,CAACK,MAAM,EAAE,IAAI,CAAC,GACpC,IAAI;IAEV,IAAID,IAAI,IAAI,EAAEA,IAAI,YAAYd,KAAK,CAAC,EAAE;MACpC,IAAI,CAACM,OAAO,CAACY,IAAI,CAACjB,OAAO,CAACkB,MAAM,CAACC,wBAAwB,EAAEV,KAAK,CAAC;MACjE,IAAI,CAACL,MAAM,CAACgB,UAAU,CAAC,CAAC;MACxB,IAAI,CAACf,OAAO,CAACY,IAAI,CAACjB,OAAO,CAACkB,MAAM,CAACG,iBAAiB,EAAEZ,KAAK,CAAC;MAC1D,IAAI,CAACP,WAAW,GAAG,IAAI;IACzB;EACF;EAEQU,oBAAoBA,CAACH,KAAuB,EAAE;IACpD,IAAI,CAACJ,OAAO,CAACY,IAAI,CAACjB,OAAO,CAACkB,MAAM,CAACI,sBAAsB,EAAEb,KAAK,CAAC;IAC/D,IAAI,CAACL,MAAM,CAACmB,QAAQ,CAAC,CAAC;IACtB,IAAI,CAAClB,OAAO,CAACY,IAAI,CAACjB,OAAO,CAACkB,MAAM,CAACM,eAAe,EAAEf,KAAK,CAAC;IACxD,IAAI,CAACP,WAAW,GAAG,KAAK;EAC1B;AACF;AAEA,eAAeD,WAAW","ignoreList":[]}
|
||||
28
public/assets/quill/core/editor.d.ts
vendored
Normal file
28
public/assets/quill/core/editor.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import Delta from 'quill-delta';
|
||||
import type Scroll from '../blots/scroll.js';
|
||||
import { Range } from './selection.js';
|
||||
type SelectionInfo = {
|
||||
newRange: Range;
|
||||
oldRange: Range;
|
||||
};
|
||||
declare class Editor {
|
||||
scroll: Scroll;
|
||||
delta: Delta;
|
||||
constructor(scroll: Scroll);
|
||||
applyDelta(delta: Delta): Delta;
|
||||
deleteText(index: number, length: number): Delta;
|
||||
formatLine(index: number, length: number, formats?: Record<string, unknown>): Delta;
|
||||
formatText(index: number, length: number, formats?: Record<string, unknown>): Delta;
|
||||
getContents(index: number, length: number): Delta;
|
||||
getDelta(): Delta;
|
||||
getFormat(index: number, length?: number): Record<string, unknown>;
|
||||
getHTML(index: number, length: number): string;
|
||||
getText(index: number, length: number): string;
|
||||
insertContents(index: number, contents: Delta): Delta;
|
||||
insertEmbed(index: number, embed: string, value: unknown): Delta;
|
||||
insertText(index: number, text: string, formats?: Record<string, unknown>): Delta;
|
||||
isBlank(): boolean;
|
||||
removeFormat(index: number, length: number): Delta;
|
||||
update(change: Delta | null, mutations?: MutationRecord[], selectionInfo?: SelectionInfo | undefined): Delta;
|
||||
}
|
||||
export default Editor;
|
||||
404
public/assets/quill/core/editor.js
Normal file
404
public/assets/quill/core/editor.js
Normal file
@@ -0,0 +1,404 @@
|
||||
import { cloneDeep, isEqual, merge } from 'lodash-es';
|
||||
import { LeafBlot, EmbedBlot, Scope, ParentBlot } from 'parchment';
|
||||
import Delta, { AttributeMap, Op } from 'quill-delta';
|
||||
import Block, { BlockEmbed, bubbleFormats } from '../blots/block.js';
|
||||
import Break from '../blots/break.js';
|
||||
import CursorBlot from '../blots/cursor.js';
|
||||
import TextBlot, { escapeText } from '../blots/text.js';
|
||||
import { Range } from './selection.js';
|
||||
const ASCII = /^[ -~]*$/;
|
||||
class Editor {
|
||||
constructor(scroll) {
|
||||
this.scroll = scroll;
|
||||
this.delta = this.getDelta();
|
||||
}
|
||||
applyDelta(delta) {
|
||||
this.scroll.update();
|
||||
let scrollLength = this.scroll.length();
|
||||
this.scroll.batchStart();
|
||||
const normalizedDelta = normalizeDelta(delta);
|
||||
const deleteDelta = new Delta();
|
||||
const normalizedOps = splitOpLines(normalizedDelta.ops.slice());
|
||||
normalizedOps.reduce((index, op) => {
|
||||
const length = Op.length(op);
|
||||
let attributes = op.attributes || {};
|
||||
let isImplicitNewlinePrepended = false;
|
||||
let isImplicitNewlineAppended = false;
|
||||
if (op.insert != null) {
|
||||
deleteDelta.retain(length);
|
||||
if (typeof op.insert === 'string') {
|
||||
const text = op.insert;
|
||||
isImplicitNewlineAppended = !text.endsWith('\n') && (scrollLength <= index || !!this.scroll.descendant(BlockEmbed, index)[0]);
|
||||
this.scroll.insertAt(index, text);
|
||||
const [line, offset] = this.scroll.line(index);
|
||||
let formats = merge({}, bubbleFormats(line));
|
||||
if (line instanceof Block) {
|
||||
const [leaf] = line.descendant(LeafBlot, offset);
|
||||
if (leaf) {
|
||||
formats = merge(formats, bubbleFormats(leaf));
|
||||
}
|
||||
}
|
||||
attributes = AttributeMap.diff(formats, attributes) || {};
|
||||
} else if (typeof op.insert === 'object') {
|
||||
const key = Object.keys(op.insert)[0]; // There should only be one key
|
||||
if (key == null) return index;
|
||||
const isInlineEmbed = this.scroll.query(key, Scope.INLINE) != null;
|
||||
if (isInlineEmbed) {
|
||||
if (scrollLength <= index || !!this.scroll.descendant(BlockEmbed, index)[0]) {
|
||||
isImplicitNewlineAppended = true;
|
||||
}
|
||||
} else if (index > 0) {
|
||||
const [leaf, offset] = this.scroll.descendant(LeafBlot, index - 1);
|
||||
if (leaf instanceof TextBlot) {
|
||||
const text = leaf.value();
|
||||
if (text[offset] !== '\n') {
|
||||
isImplicitNewlinePrepended = true;
|
||||
}
|
||||
} else if (leaf instanceof EmbedBlot && leaf.statics.scope === Scope.INLINE_BLOT) {
|
||||
isImplicitNewlinePrepended = true;
|
||||
}
|
||||
}
|
||||
this.scroll.insertAt(index, key, op.insert[key]);
|
||||
if (isInlineEmbed) {
|
||||
const [leaf] = this.scroll.descendant(LeafBlot, index);
|
||||
if (leaf) {
|
||||
const formats = merge({}, bubbleFormats(leaf));
|
||||
attributes = AttributeMap.diff(formats, attributes) || {};
|
||||
}
|
||||
}
|
||||
}
|
||||
scrollLength += length;
|
||||
} else {
|
||||
deleteDelta.push(op);
|
||||
if (op.retain !== null && typeof op.retain === 'object') {
|
||||
const key = Object.keys(op.retain)[0];
|
||||
if (key == null) return index;
|
||||
this.scroll.updateEmbedAt(index, key, op.retain[key]);
|
||||
}
|
||||
}
|
||||
Object.keys(attributes).forEach(name => {
|
||||
this.scroll.formatAt(index, length, name, attributes[name]);
|
||||
});
|
||||
const prependedLength = isImplicitNewlinePrepended ? 1 : 0;
|
||||
const addedLength = isImplicitNewlineAppended ? 1 : 0;
|
||||
scrollLength += prependedLength + addedLength;
|
||||
deleteDelta.retain(prependedLength);
|
||||
deleteDelta.delete(addedLength);
|
||||
return index + length + prependedLength + addedLength;
|
||||
}, 0);
|
||||
deleteDelta.reduce((index, op) => {
|
||||
if (typeof op.delete === 'number') {
|
||||
this.scroll.deleteAt(index, op.delete);
|
||||
return index;
|
||||
}
|
||||
return index + Op.length(op);
|
||||
}, 0);
|
||||
this.scroll.batchEnd();
|
||||
this.scroll.optimize();
|
||||
return this.update(normalizedDelta);
|
||||
}
|
||||
deleteText(index, length) {
|
||||
this.scroll.deleteAt(index, length);
|
||||
return this.update(new Delta().retain(index).delete(length));
|
||||
}
|
||||
formatLine(index, length) {
|
||||
let formats = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
this.scroll.update();
|
||||
Object.keys(formats).forEach(format => {
|
||||
this.scroll.lines(index, Math.max(length, 1)).forEach(line => {
|
||||
line.format(format, formats[format]);
|
||||
});
|
||||
});
|
||||
this.scroll.optimize();
|
||||
const delta = new Delta().retain(index).retain(length, cloneDeep(formats));
|
||||
return this.update(delta);
|
||||
}
|
||||
formatText(index, length) {
|
||||
let formats = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
Object.keys(formats).forEach(format => {
|
||||
this.scroll.formatAt(index, length, format, formats[format]);
|
||||
});
|
||||
const delta = new Delta().retain(index).retain(length, cloneDeep(formats));
|
||||
return this.update(delta);
|
||||
}
|
||||
getContents(index, length) {
|
||||
return this.delta.slice(index, index + length);
|
||||
}
|
||||
getDelta() {
|
||||
return this.scroll.lines().reduce((delta, line) => {
|
||||
return delta.concat(line.delta());
|
||||
}, new Delta());
|
||||
}
|
||||
getFormat(index) {
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
let lines = [];
|
||||
let leaves = [];
|
||||
if (length === 0) {
|
||||
this.scroll.path(index).forEach(path => {
|
||||
const [blot] = path;
|
||||
if (blot instanceof Block) {
|
||||
lines.push(blot);
|
||||
} else if (blot instanceof LeafBlot) {
|
||||
leaves.push(blot);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
lines = this.scroll.lines(index, length);
|
||||
leaves = this.scroll.descendants(LeafBlot, index, length);
|
||||
}
|
||||
const [lineFormats, leafFormats] = [lines, leaves].map(blots => {
|
||||
const blot = blots.shift();
|
||||
if (blot == null) return {};
|
||||
let formats = bubbleFormats(blot);
|
||||
while (Object.keys(formats).length > 0) {
|
||||
const blot = blots.shift();
|
||||
if (blot == null) return formats;
|
||||
formats = combineFormats(bubbleFormats(blot), formats);
|
||||
}
|
||||
return formats;
|
||||
});
|
||||
return {
|
||||
...lineFormats,
|
||||
...leafFormats
|
||||
};
|
||||
}
|
||||
getHTML(index, length) {
|
||||
const [line, lineOffset] = this.scroll.line(index);
|
||||
if (line) {
|
||||
const lineLength = line.length();
|
||||
const isWithinLine = line.length() >= lineOffset + length;
|
||||
if (isWithinLine && !(lineOffset === 0 && length === lineLength)) {
|
||||
return convertHTML(line, lineOffset, length, true);
|
||||
}
|
||||
return convertHTML(this.scroll, index, length, true);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
getText(index, length) {
|
||||
return this.getContents(index, length).filter(op => typeof op.insert === 'string').map(op => op.insert).join('');
|
||||
}
|
||||
insertContents(index, contents) {
|
||||
const normalizedDelta = normalizeDelta(contents);
|
||||
const change = new Delta().retain(index).concat(normalizedDelta);
|
||||
this.scroll.insertContents(index, normalizedDelta);
|
||||
return this.update(change);
|
||||
}
|
||||
insertEmbed(index, embed, value) {
|
||||
this.scroll.insertAt(index, embed, value);
|
||||
return this.update(new Delta().retain(index).insert({
|
||||
[embed]: value
|
||||
}));
|
||||
}
|
||||
insertText(index, text) {
|
||||
let formats = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
text = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
||||
this.scroll.insertAt(index, text);
|
||||
Object.keys(formats).forEach(format => {
|
||||
this.scroll.formatAt(index, text.length, format, formats[format]);
|
||||
});
|
||||
return this.update(new Delta().retain(index).insert(text, cloneDeep(formats)));
|
||||
}
|
||||
isBlank() {
|
||||
if (this.scroll.children.length === 0) return true;
|
||||
if (this.scroll.children.length > 1) return false;
|
||||
const blot = this.scroll.children.head;
|
||||
if (blot?.statics.blotName !== Block.blotName) return false;
|
||||
const block = blot;
|
||||
if (block.children.length > 1) return false;
|
||||
return block.children.head instanceof Break;
|
||||
}
|
||||
removeFormat(index, length) {
|
||||
const text = this.getText(index, length);
|
||||
const [line, offset] = this.scroll.line(index + length);
|
||||
let suffixLength = 0;
|
||||
let suffix = new Delta();
|
||||
if (line != null) {
|
||||
suffixLength = line.length() - offset;
|
||||
suffix = line.delta().slice(offset, offset + suffixLength - 1).insert('\n');
|
||||
}
|
||||
const contents = this.getContents(index, length + suffixLength);
|
||||
const diff = contents.diff(new Delta().insert(text).concat(suffix));
|
||||
const delta = new Delta().retain(index).concat(diff);
|
||||
return this.applyDelta(delta);
|
||||
}
|
||||
update(change) {
|
||||
let mutations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
||||
let selectionInfo = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
|
||||
const oldDelta = this.delta;
|
||||
if (mutations.length === 1 && mutations[0].type === 'characterData' &&
|
||||
// @ts-expect-error Fix me later
|
||||
mutations[0].target.data.match(ASCII) && this.scroll.find(mutations[0].target)) {
|
||||
// Optimization for character changes
|
||||
const textBlot = this.scroll.find(mutations[0].target);
|
||||
const formats = bubbleFormats(textBlot);
|
||||
const index = textBlot.offset(this.scroll);
|
||||
// @ts-expect-error Fix me later
|
||||
const oldValue = mutations[0].oldValue.replace(CursorBlot.CONTENTS, '');
|
||||
const oldText = new Delta().insert(oldValue);
|
||||
// @ts-expect-error
|
||||
const newText = new Delta().insert(textBlot.value());
|
||||
const relativeSelectionInfo = selectionInfo && {
|
||||
oldRange: shiftRange(selectionInfo.oldRange, -index),
|
||||
newRange: shiftRange(selectionInfo.newRange, -index)
|
||||
};
|
||||
const diffDelta = new Delta().retain(index).concat(oldText.diff(newText, relativeSelectionInfo));
|
||||
change = diffDelta.reduce((delta, op) => {
|
||||
if (op.insert) {
|
||||
return delta.insert(op.insert, formats);
|
||||
}
|
||||
return delta.push(op);
|
||||
}, new Delta());
|
||||
this.delta = oldDelta.compose(change);
|
||||
} else {
|
||||
this.delta = this.getDelta();
|
||||
if (!change || !isEqual(oldDelta.compose(change), this.delta)) {
|
||||
change = oldDelta.diff(this.delta, selectionInfo);
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
}
|
||||
function convertListHTML(items, lastIndent, types) {
|
||||
if (items.length === 0) {
|
||||
const [endTag] = getListType(types.pop());
|
||||
if (lastIndent <= 0) {
|
||||
return `</li></${endTag}>`;
|
||||
}
|
||||
return `</li></${endTag}>${convertListHTML([], lastIndent - 1, types)}`;
|
||||
}
|
||||
const [{
|
||||
child,
|
||||
offset,
|
||||
length,
|
||||
indent,
|
||||
type
|
||||
}, ...rest] = items;
|
||||
const [tag, attribute] = getListType(type);
|
||||
if (indent > lastIndent) {
|
||||
types.push(type);
|
||||
if (indent === lastIndent + 1) {
|
||||
return `<${tag}><li${attribute}>${convertHTML(child, offset, length)}${convertListHTML(rest, indent, types)}`;
|
||||
}
|
||||
return `<${tag}><li>${convertListHTML(items, lastIndent + 1, types)}`;
|
||||
}
|
||||
const previousType = types[types.length - 1];
|
||||
if (indent === lastIndent && type === previousType) {
|
||||
return `</li><li${attribute}>${convertHTML(child, offset, length)}${convertListHTML(rest, indent, types)}`;
|
||||
}
|
||||
const [endTag] = getListType(types.pop());
|
||||
return `</li></${endTag}>${convertListHTML(items, lastIndent - 1, types)}`;
|
||||
}
|
||||
function convertHTML(blot, index, length) {
|
||||
let isRoot = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
||||
if ('html' in blot && typeof blot.html === 'function') {
|
||||
return blot.html(index, length);
|
||||
}
|
||||
if (blot instanceof TextBlot) {
|
||||
const escapedText = escapeText(blot.value().slice(index, index + length));
|
||||
return escapedText.replaceAll(' ', ' ');
|
||||
}
|
||||
if (blot instanceof ParentBlot) {
|
||||
// TODO fix API
|
||||
if (blot.statics.blotName === 'list-container') {
|
||||
const items = [];
|
||||
blot.children.forEachAt(index, length, (child, offset, childLength) => {
|
||||
const formats = 'formats' in child && typeof child.formats === 'function' ? child.formats() : {};
|
||||
items.push({
|
||||
child,
|
||||
offset,
|
||||
length: childLength,
|
||||
indent: formats.indent || 0,
|
||||
type: formats.list
|
||||
});
|
||||
});
|
||||
return convertListHTML(items, -1, []);
|
||||
}
|
||||
const parts = [];
|
||||
blot.children.forEachAt(index, length, (child, offset, childLength) => {
|
||||
parts.push(convertHTML(child, offset, childLength));
|
||||
});
|
||||
if (isRoot || blot.statics.blotName === 'list') {
|
||||
return parts.join('');
|
||||
}
|
||||
const {
|
||||
outerHTML,
|
||||
innerHTML
|
||||
} = blot.domNode;
|
||||
const [start, end] = outerHTML.split(`>${innerHTML}<`);
|
||||
// TODO cleanup
|
||||
if (start === '<table') {
|
||||
return `<table style="border: 1px solid #000;">${parts.join('')}<${end}`;
|
||||
}
|
||||
return `${start}>${parts.join('')}<${end}`;
|
||||
}
|
||||
return blot.domNode instanceof Element ? blot.domNode.outerHTML : '';
|
||||
}
|
||||
function combineFormats(formats, combined) {
|
||||
return Object.keys(combined).reduce((merged, name) => {
|
||||
if (formats[name] == null) return merged;
|
||||
const combinedValue = combined[name];
|
||||
if (combinedValue === formats[name]) {
|
||||
merged[name] = combinedValue;
|
||||
} else if (Array.isArray(combinedValue)) {
|
||||
if (combinedValue.indexOf(formats[name]) < 0) {
|
||||
merged[name] = combinedValue.concat([formats[name]]);
|
||||
} else {
|
||||
// If style already exists, don't add to an array, but don't lose other styles
|
||||
merged[name] = combinedValue;
|
||||
}
|
||||
} else {
|
||||
merged[name] = [combinedValue, formats[name]];
|
||||
}
|
||||
return merged;
|
||||
}, {});
|
||||
}
|
||||
function getListType(type) {
|
||||
const tag = type === 'ordered' ? 'ol' : 'ul';
|
||||
switch (type) {
|
||||
case 'checked':
|
||||
return [tag, ' data-list="checked"'];
|
||||
case 'unchecked':
|
||||
return [tag, ' data-list="unchecked"'];
|
||||
default:
|
||||
return [tag, ''];
|
||||
}
|
||||
}
|
||||
function normalizeDelta(delta) {
|
||||
return delta.reduce((normalizedDelta, op) => {
|
||||
if (typeof op.insert === 'string') {
|
||||
const text = op.insert.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
||||
return normalizedDelta.insert(text, op.attributes);
|
||||
}
|
||||
return normalizedDelta.push(op);
|
||||
}, new Delta());
|
||||
}
|
||||
function shiftRange(_ref, amount) {
|
||||
let {
|
||||
index,
|
||||
length
|
||||
} = _ref;
|
||||
return new Range(index + amount, length);
|
||||
}
|
||||
function splitOpLines(ops) {
|
||||
const split = [];
|
||||
ops.forEach(op => {
|
||||
if (typeof op.insert === 'string') {
|
||||
const lines = op.insert.split('\n');
|
||||
lines.forEach((line, index) => {
|
||||
if (index) split.push({
|
||||
insert: '\n',
|
||||
attributes: op.attributes
|
||||
});
|
||||
if (line) split.push({
|
||||
insert: line,
|
||||
attributes: op.attributes
|
||||
});
|
||||
});
|
||||
} else {
|
||||
split.push(op);
|
||||
}
|
||||
});
|
||||
return split;
|
||||
}
|
||||
export default Editor;
|
||||
//# sourceMappingURL=editor.js.map
|
||||
1
public/assets/quill/core/editor.js.map
Normal file
1
public/assets/quill/core/editor.js.map
Normal file
File diff suppressed because one or more lines are too long
33
public/assets/quill/core/emitter.d.ts
vendored
Normal file
33
public/assets/quill/core/emitter.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
declare class Emitter extends EventEmitter<string> {
|
||||
static events: {
|
||||
readonly EDITOR_CHANGE: "editor-change";
|
||||
readonly SCROLL_BEFORE_UPDATE: "scroll-before-update";
|
||||
readonly SCROLL_BLOT_MOUNT: "scroll-blot-mount";
|
||||
readonly SCROLL_BLOT_UNMOUNT: "scroll-blot-unmount";
|
||||
readonly SCROLL_OPTIMIZE: "scroll-optimize";
|
||||
readonly SCROLL_UPDATE: "scroll-update";
|
||||
readonly SCROLL_EMBED_UPDATE: "scroll-embed-update";
|
||||
readonly SELECTION_CHANGE: "selection-change";
|
||||
readonly TEXT_CHANGE: "text-change";
|
||||
readonly COMPOSITION_BEFORE_START: "composition-before-start";
|
||||
readonly COMPOSITION_START: "composition-start";
|
||||
readonly COMPOSITION_BEFORE_END: "composition-before-end";
|
||||
readonly COMPOSITION_END: "composition-end";
|
||||
};
|
||||
static sources: {
|
||||
readonly API: "api";
|
||||
readonly SILENT: "silent";
|
||||
readonly USER: "user";
|
||||
};
|
||||
protected domListeners: Record<string, {
|
||||
node: Node;
|
||||
handler: Function;
|
||||
}[]>;
|
||||
constructor();
|
||||
emit(...args: unknown[]): boolean;
|
||||
handleDOM(event: Event, ...args: unknown[]): void;
|
||||
listenDOM(eventName: string, node: Node, handler: EventListener): void;
|
||||
}
|
||||
export type EmitterSource = (typeof Emitter.sources)[keyof typeof Emitter.sources];
|
||||
export default Emitter;
|
||||
78
public/assets/quill/core/emitter.js
Normal file
78
public/assets/quill/core/emitter.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import instances from './instances.js';
|
||||
import logger from './logger.js';
|
||||
const debug = logger('quill:events');
|
||||
const EVENTS = ['selectionchange', 'mousedown', 'mouseup', 'click'];
|
||||
EVENTS.forEach(eventName => {
|
||||
document.addEventListener(eventName, function () {
|
||||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
Array.from(document.querySelectorAll('.ql-container')).forEach(node => {
|
||||
const quill = instances.get(node);
|
||||
if (quill && quill.emitter) {
|
||||
quill.emitter.handleDOM(...args);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
class Emitter extends EventEmitter {
|
||||
static events = {
|
||||
EDITOR_CHANGE: 'editor-change',
|
||||
SCROLL_BEFORE_UPDATE: 'scroll-before-update',
|
||||
SCROLL_BLOT_MOUNT: 'scroll-blot-mount',
|
||||
SCROLL_BLOT_UNMOUNT: 'scroll-blot-unmount',
|
||||
SCROLL_OPTIMIZE: 'scroll-optimize',
|
||||
SCROLL_UPDATE: 'scroll-update',
|
||||
SCROLL_EMBED_UPDATE: 'scroll-embed-update',
|
||||
SELECTION_CHANGE: 'selection-change',
|
||||
TEXT_CHANGE: 'text-change',
|
||||
COMPOSITION_BEFORE_START: 'composition-before-start',
|
||||
COMPOSITION_START: 'composition-start',
|
||||
COMPOSITION_BEFORE_END: 'composition-before-end',
|
||||
COMPOSITION_END: 'composition-end'
|
||||
};
|
||||
static sources = {
|
||||
API: 'api',
|
||||
SILENT: 'silent',
|
||||
USER: 'user'
|
||||
};
|
||||
constructor() {
|
||||
super();
|
||||
this.domListeners = {};
|
||||
this.on('error', debug.error);
|
||||
}
|
||||
emit() {
|
||||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
args[_key2] = arguments[_key2];
|
||||
}
|
||||
debug.log.call(debug, ...args);
|
||||
// @ts-expect-error
|
||||
return super.emit(...args);
|
||||
}
|
||||
handleDOM(event) {
|
||||
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
||||
args[_key3 - 1] = arguments[_key3];
|
||||
}
|
||||
(this.domListeners[event.type] || []).forEach(_ref => {
|
||||
let {
|
||||
node,
|
||||
handler
|
||||
} = _ref;
|
||||
if (event.target === node || node.contains(event.target)) {
|
||||
handler(event, ...args);
|
||||
}
|
||||
});
|
||||
}
|
||||
listenDOM(eventName, node, handler) {
|
||||
if (!this.domListeners[eventName]) {
|
||||
this.domListeners[eventName] = [];
|
||||
}
|
||||
this.domListeners[eventName].push({
|
||||
node,
|
||||
handler
|
||||
});
|
||||
}
|
||||
}
|
||||
export default Emitter;
|
||||
//# sourceMappingURL=emitter.js.map
|
||||
1
public/assets/quill/core/emitter.js.map
Normal file
1
public/assets/quill/core/emitter.js.map
Normal file
File diff suppressed because one or more lines are too long
3
public/assets/quill/core/instances.d.ts
vendored
Normal file
3
public/assets/quill/core/instances.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import type Quill from '../core.js';
|
||||
declare const _default: WeakMap<Node, Quill>;
|
||||
export default _default;
|
||||
2
public/assets/quill/core/instances.js
Normal file
2
public/assets/quill/core/instances.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export default new WeakMap();
|
||||
//# sourceMappingURL=instances.js.map
|
||||
1
public/assets/quill/core/instances.js.map
Normal file
1
public/assets/quill/core/instances.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"instances.js","names":["WeakMap"],"sources":["../../src/core/instances.ts"],"sourcesContent":["import type Quill from '../core.js';\n\nexport default new WeakMap<Node, Quill>();\n"],"mappings":"AAEA,eAAe,IAAIA,OAAO,CAAc,CAAC","ignoreList":[]}
|
||||
7
public/assets/quill/core/logger.d.ts
vendored
Normal file
7
public/assets/quill/core/logger.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
declare const levels: readonly ["error", "warn", "log", "info"];
|
||||
export type DebugLevel = (typeof levels)[number];
|
||||
declare function namespace(ns: string): Record<DebugLevel, (...args: unknown[]) => void>;
|
||||
declare namespace namespace {
|
||||
var level: (newLevel: false | "error" | "warn" | "log" | "info") => void;
|
||||
}
|
||||
export default namespace;
|
||||
24
public/assets/quill/core/logger.js
Normal file
24
public/assets/quill/core/logger.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const levels = ['error', 'warn', 'log', 'info'];
|
||||
let level = 'warn';
|
||||
function debug(method) {
|
||||
if (level) {
|
||||
if (levels.indexOf(method) <= levels.indexOf(level)) {
|
||||
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
console[method](...args); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
}
|
||||
function namespace(ns) {
|
||||
return levels.reduce((logger, method) => {
|
||||
logger[method] = debug.bind(console, method, ns);
|
||||
return logger;
|
||||
}, {});
|
||||
}
|
||||
namespace.level = newLevel => {
|
||||
level = newLevel;
|
||||
};
|
||||
debug.level = namespace.level;
|
||||
export default namespace;
|
||||
//# sourceMappingURL=logger.js.map
|
||||
1
public/assets/quill/core/logger.js.map
Normal file
1
public/assets/quill/core/logger.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"logger.js","names":["levels","level","debug","method","indexOf","_len","arguments","length","args","Array","_key","console","namespace","ns","reduce","logger","bind","newLevel"],"sources":["../../src/core/logger.ts"],"sourcesContent":["const levels = ['error', 'warn', 'log', 'info'] as const;\nexport type DebugLevel = (typeof levels)[number];\nlet level: DebugLevel | false = 'warn';\n\nfunction debug(method: DebugLevel, ...args: unknown[]) {\n if (level) {\n if (levels.indexOf(method) <= levels.indexOf(level)) {\n console[method](...args); // eslint-disable-line no-console\n }\n }\n}\n\nfunction namespace(\n ns: string,\n): Record<DebugLevel, (...args: unknown[]) => void> {\n return levels.reduce(\n (logger, method) => {\n logger[method] = debug.bind(console, method, ns);\n return logger;\n },\n {} as Record<DebugLevel, (...args: unknown[]) => void>,\n );\n}\n\nnamespace.level = (newLevel: DebugLevel | false) => {\n level = newLevel;\n};\ndebug.level = namespace.level;\n\nexport default namespace;\n"],"mappings":"AAAA,MAAMA,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAU;AAExD,IAAIC,KAAyB,GAAG,MAAM;AAEtC,SAASC,KAAKA,CAACC,MAAkB,EAAsB;EACrD,IAAIF,KAAK,EAAE;IACT,IAAID,MAAM,CAACI,OAAO,CAACD,MAAM,CAAC,IAAIH,MAAM,CAACI,OAAO,CAACH,KAAK,CAAC,EAAE;MAAA,SAAAI,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAFnBC,IAAI,OAAAC,KAAA,CAAAJ,IAAA,OAAAA,IAAA,WAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;QAAJF,IAAI,CAAAE,IAAA,QAAAJ,SAAA,CAAAI,IAAA;MAAA;MAGpCC,OAAO,CAACR,MAAM,CAAC,CAAC,GAAGK,IAAI,CAAC,CAAC,CAAC;IAC5B;EACF;AACF;AAEA,SAASI,SAASA,CAChBC,EAAU,EACwC;EAClD,OAAOb,MAAM,CAACc,MAAM,CAClB,CAACC,MAAM,EAAEZ,MAAM,KAAK;IAClBY,MAAM,CAACZ,MAAM,CAAC,GAAGD,KAAK,CAACc,IAAI,CAACL,OAAO,EAAER,MAAM,EAAEU,EAAE,CAAC;IAChD,OAAOE,MAAM;EACf,CAAC,EACD,CAAC,CACH,CAAC;AACH;AAEAH,SAAS,CAACX,KAAK,GAAIgB,QAA4B,IAAK;EAClDhB,KAAK,GAAGgB,QAAQ;AAClB,CAAC;AACDf,KAAK,CAACD,KAAK,GAAGW,SAAS,CAACX,KAAK;AAE7B,eAAeW,SAAS","ignoreList":[]}
|
||||
8
public/assets/quill/core/module.d.ts
vendored
Normal file
8
public/assets/quill/core/module.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import type Quill from './quill.js';
|
||||
declare abstract class Module<T extends {} = {}> {
|
||||
quill: Quill;
|
||||
protected options: Partial<T>;
|
||||
static DEFAULTS: {};
|
||||
constructor(quill: Quill, options?: Partial<T>);
|
||||
}
|
||||
export default Module;
|
||||
10
public/assets/quill/core/module.js
Normal file
10
public/assets/quill/core/module.js
Normal file
@@ -0,0 +1,10 @@
|
||||
class Module {
|
||||
static DEFAULTS = {};
|
||||
constructor(quill) {
|
||||
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
this.quill = quill;
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
export default Module;
|
||||
//# sourceMappingURL=module.js.map
|
||||
1
public/assets/quill/core/module.js.map
Normal file
1
public/assets/quill/core/module.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"module.js","names":["Module","DEFAULTS","constructor","quill","options","arguments","length","undefined"],"sources":["../../src/core/module.ts"],"sourcesContent":["import type Quill from './quill.js';\n\nabstract class Module<T extends {} = {}> {\n static DEFAULTS = {};\n\n constructor(\n public quill: Quill,\n protected options: Partial<T> = {},\n ) {}\n}\n\nexport default Module;\n"],"mappings":"AAEA,MAAeA,MAAM,CAAoB;EACvC,OAAOC,QAAQ,GAAG,CAAC,CAAC;EAEpBC,WAAWA,CACFC,KAAY,EAEnB;IAAA,IADUC,OAAmB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;IAAA,KAD3BF,KAAY,GAAZA,KAAY;IAAA,KACTC,OAAmB,GAAnBA,OAAmB;EAC5B;AACL;AAEA,eAAeJ,MAAM","ignoreList":[]}
|
||||
218
public/assets/quill/core/quill.d.ts
vendored
Normal file
218
public/assets/quill/core/quill.d.ts
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
import * as Parchment from 'parchment';
|
||||
import type { Op } from 'quill-delta';
|
||||
import Delta from 'quill-delta';
|
||||
import type { BlockEmbed } from '../blots/block.js';
|
||||
import type Block from '../blots/block.js';
|
||||
import type Scroll from '../blots/scroll.js';
|
||||
import type Clipboard from '../modules/clipboard.js';
|
||||
import type History from '../modules/history.js';
|
||||
import type Keyboard from '../modules/keyboard.js';
|
||||
import type Uploader from '../modules/uploader.js';
|
||||
import Editor from './editor.js';
|
||||
import Emitter from './emitter.js';
|
||||
import type { EmitterSource } from './emitter.js';
|
||||
import type { DebugLevel } from './logger.js';
|
||||
import Module from './module.js';
|
||||
import Selection, { Range } from './selection.js';
|
||||
import type { Bounds } from './selection.js';
|
||||
import Composition from './composition.js';
|
||||
import Theme from './theme.js';
|
||||
import type { ThemeConstructor } from './theme.js';
|
||||
import type { Rect } from './utils/scrollRectIntoView.js';
|
||||
declare const globalRegistry: Parchment.Registry;
|
||||
/**
|
||||
* Options for initializing a Quill instance
|
||||
*/
|
||||
export interface QuillOptions {
|
||||
theme?: string;
|
||||
debug?: DebugLevel | boolean;
|
||||
registry?: Parchment.Registry;
|
||||
/**
|
||||
* Whether to disable the editing
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
/**
|
||||
* Placeholder text to display when the editor is empty
|
||||
* @default ""
|
||||
*/
|
||||
placeholder?: string;
|
||||
bounds?: HTMLElement | string | null;
|
||||
modules?: Record<string, unknown>;
|
||||
/**
|
||||
* A list of formats that are recognized and can exist within the editor contents.
|
||||
* `null` means all formats are allowed.
|
||||
* @default null
|
||||
*/
|
||||
formats?: string[] | null;
|
||||
}
|
||||
/**
|
||||
* Similar to QuillOptions, but with all properties expanded to their default values,
|
||||
* and all selectors resolved to HTMLElements.
|
||||
*/
|
||||
export interface ExpandedQuillOptions extends Omit<QuillOptions, 'theme' | 'formats'> {
|
||||
theme: ThemeConstructor;
|
||||
registry: Parchment.Registry;
|
||||
container: HTMLElement;
|
||||
modules: Record<string, unknown>;
|
||||
bounds?: HTMLElement | null;
|
||||
readOnly: boolean;
|
||||
}
|
||||
declare class Quill {
|
||||
static DEFAULTS: {
|
||||
bounds: null;
|
||||
modules: {
|
||||
clipboard: boolean;
|
||||
keyboard: boolean;
|
||||
history: boolean;
|
||||
uploader: boolean;
|
||||
};
|
||||
placeholder: string;
|
||||
readOnly: false;
|
||||
registry: Parchment.Registry;
|
||||
theme: string;
|
||||
};
|
||||
static events: {
|
||||
readonly EDITOR_CHANGE: "editor-change";
|
||||
readonly SCROLL_BEFORE_UPDATE: "scroll-before-update";
|
||||
readonly SCROLL_BLOT_MOUNT: "scroll-blot-mount";
|
||||
readonly SCROLL_BLOT_UNMOUNT: "scroll-blot-unmount";
|
||||
readonly SCROLL_OPTIMIZE: "scroll-optimize";
|
||||
readonly SCROLL_UPDATE: "scroll-update";
|
||||
readonly SCROLL_EMBED_UPDATE: "scroll-embed-update";
|
||||
readonly SELECTION_CHANGE: "selection-change";
|
||||
readonly TEXT_CHANGE: "text-change";
|
||||
readonly COMPOSITION_BEFORE_START: "composition-before-start";
|
||||
readonly COMPOSITION_START: "composition-start";
|
||||
readonly COMPOSITION_BEFORE_END: "composition-before-end";
|
||||
readonly COMPOSITION_END: "composition-end";
|
||||
};
|
||||
static sources: {
|
||||
readonly API: "api";
|
||||
readonly SILENT: "silent";
|
||||
readonly USER: "user";
|
||||
};
|
||||
static version: string;
|
||||
static imports: Record<string, unknown>;
|
||||
static debug(limit: DebugLevel | boolean): void;
|
||||
static find(node: Node, bubble?: boolean): Parchment.Blot | Quill | null;
|
||||
static import(name: 'core/module'): typeof Module;
|
||||
static import(name: `themes/${string}`): typeof Theme;
|
||||
static import(name: 'parchment'): typeof Parchment;
|
||||
static import(name: 'delta'): typeof Delta;
|
||||
static import(name: string): unknown;
|
||||
static register(targets: Record<string, Parchment.RegistryDefinition | Record<string, unknown> | Theme | Module | Function>, overwrite?: boolean): void;
|
||||
static register(target: Parchment.RegistryDefinition, overwrite?: boolean): void;
|
||||
static register(path: string, target: any, overwrite?: boolean): void;
|
||||
container: HTMLElement;
|
||||
root: HTMLDivElement;
|
||||
scroll: Scroll;
|
||||
emitter: Emitter;
|
||||
protected allowReadOnlyEdits: boolean;
|
||||
editor: Editor;
|
||||
composition: Composition;
|
||||
selection: Selection;
|
||||
theme: Theme;
|
||||
keyboard: Keyboard;
|
||||
clipboard: Clipboard;
|
||||
history: History;
|
||||
uploader: Uploader;
|
||||
options: ExpandedQuillOptions;
|
||||
constructor(container: HTMLElement | string, options?: QuillOptions);
|
||||
addContainer(container: string, refNode?: Node | null): HTMLDivElement;
|
||||
addContainer(container: HTMLElement, refNode?: Node | null): HTMLElement;
|
||||
blur(): void;
|
||||
deleteText(range: Range, source?: EmitterSource): Delta;
|
||||
deleteText(index: number, length: number, source?: EmitterSource): Delta;
|
||||
disable(): void;
|
||||
editReadOnly<T>(modifier: () => T): T;
|
||||
enable(enabled?: boolean): void;
|
||||
focus(options?: {
|
||||
preventScroll?: boolean;
|
||||
}): void;
|
||||
format(name: string, value: unknown, source?: EmitterSource): Delta;
|
||||
formatLine(index: number, length: number, formats: Record<string, unknown>, source?: EmitterSource): Delta;
|
||||
formatLine(index: number, length: number, name: string, value?: unknown, source?: EmitterSource): Delta;
|
||||
formatText(range: Range, name: string, value: unknown, source?: EmitterSource): Delta;
|
||||
formatText(index: number, length: number, name: string, value: unknown, source?: EmitterSource): Delta;
|
||||
formatText(index: number, length: number, formats: Record<string, unknown>, source?: EmitterSource): Delta;
|
||||
getBounds(index: number | Range, length?: number): Bounds | null;
|
||||
getContents(index?: number, length?: number): Delta;
|
||||
getFormat(index?: number, length?: number): {
|
||||
[format: string]: unknown;
|
||||
};
|
||||
getFormat(range?: Range): {
|
||||
[format: string]: unknown;
|
||||
};
|
||||
getIndex(blot: Parchment.Blot): number;
|
||||
getLength(): number;
|
||||
getLeaf(index: number): [Parchment.LeafBlot | null, number];
|
||||
getLine(index: number): [Block | BlockEmbed | null, number];
|
||||
getLines(range: Range): (Block | BlockEmbed)[];
|
||||
getLines(index?: number, length?: number): (Block | BlockEmbed)[];
|
||||
getModule(name: string): unknown;
|
||||
getSelection(focus: true): Range;
|
||||
getSelection(focus?: boolean): Range | null;
|
||||
getSemanticHTML(range: Range): string;
|
||||
getSemanticHTML(index?: number, length?: number): string;
|
||||
getText(range?: Range): string;
|
||||
getText(index?: number, length?: number): string;
|
||||
hasFocus(): boolean;
|
||||
insertEmbed(index: number, embed: string, value: unknown, source?: EmitterSource): Delta;
|
||||
insertText(index: number, text: string, source?: EmitterSource): Delta;
|
||||
insertText(index: number, text: string, formats: Record<string, unknown>, source?: EmitterSource): Delta;
|
||||
insertText(index: number, text: string, name: string, value: unknown, source?: EmitterSource): Delta;
|
||||
isEnabled(): boolean;
|
||||
off(...args: Parameters<(typeof Emitter)['prototype']['off']>): Emitter;
|
||||
on(event: (typeof Emitter)['events']['TEXT_CHANGE'], handler: (delta: Delta, oldContent: Delta, source: EmitterSource) => void): Emitter;
|
||||
on(event: (typeof Emitter)['events']['SELECTION_CHANGE'], handler: (range: Range, oldRange: Range, source: EmitterSource) => void): Emitter;
|
||||
on(event: (typeof Emitter)['events']['EDITOR_CHANGE'], handler: (...args: [
|
||||
(typeof Emitter)['events']['TEXT_CHANGE'],
|
||||
Delta,
|
||||
Delta,
|
||||
EmitterSource
|
||||
] | [
|
||||
(typeof Emitter)['events']['SELECTION_CHANGE'],
|
||||
Range,
|
||||
Range,
|
||||
EmitterSource
|
||||
]) => void): Emitter;
|
||||
on(event: string, ...args: unknown[]): Emitter;
|
||||
once(...args: Parameters<(typeof Emitter)['prototype']['once']>): Emitter;
|
||||
removeFormat(index: number, length: number, source?: EmitterSource): Delta;
|
||||
scrollRectIntoView(rect: Rect): void;
|
||||
/**
|
||||
* @deprecated Use Quill#scrollSelectionIntoView() instead.
|
||||
*/
|
||||
scrollIntoView(): void;
|
||||
/**
|
||||
* Scroll the current selection into the visible area.
|
||||
* If the selection is already visible, no scrolling will occur.
|
||||
*/
|
||||
scrollSelectionIntoView(): void;
|
||||
setContents(delta: Delta | Op[], source?: EmitterSource): Delta;
|
||||
setSelection(range: Range | null, source?: EmitterSource): void;
|
||||
setSelection(index: number, source?: EmitterSource): void;
|
||||
setSelection(index: number, length?: number, source?: EmitterSource): void;
|
||||
setSelection(index: number, source?: EmitterSource): void;
|
||||
setText(text: string, source?: EmitterSource): Delta;
|
||||
update(source?: EmitterSource): void;
|
||||
updateContents(delta: Delta | Op[], source?: EmitterSource): Delta;
|
||||
}
|
||||
declare function expandConfig(containerOrSelector: HTMLElement | string, options: QuillOptions): ExpandedQuillOptions;
|
||||
type NormalizedIndexLength = [
|
||||
number,
|
||||
number,
|
||||
Record<string, unknown>,
|
||||
EmitterSource
|
||||
];
|
||||
declare function overload(index: number, source?: EmitterSource): NormalizedIndexLength;
|
||||
declare function overload(index: number, length: number, source?: EmitterSource): NormalizedIndexLength;
|
||||
declare function overload(index: number, length: number, format: string, value: unknown, source?: EmitterSource): NormalizedIndexLength;
|
||||
declare function overload(index: number, length: number, format: Record<string, unknown>, source?: EmitterSource): NormalizedIndexLength;
|
||||
declare function overload(range: Range, source?: EmitterSource): NormalizedIndexLength;
|
||||
declare function overload(range: Range, format: string, value: unknown, source?: EmitterSource): NormalizedIndexLength;
|
||||
declare function overload(range: Range, format: Record<string, unknown>, source?: EmitterSource): NormalizedIndexLength;
|
||||
export type { Bounds, DebugLevel, EmitterSource };
|
||||
export { Parchment, Range };
|
||||
export { globalRegistry, expandConfig, overload, Quill as default };
|
||||
628
public/assets/quill/core/quill.js
Normal file
628
public/assets/quill/core/quill.js
Normal file
@@ -0,0 +1,628 @@
|
||||
import { merge } from 'lodash-es';
|
||||
import * as Parchment from 'parchment';
|
||||
import Delta from 'quill-delta';
|
||||
import Editor from './editor.js';
|
||||
import Emitter from './emitter.js';
|
||||
import instances from './instances.js';
|
||||
import logger from './logger.js';
|
||||
import Module from './module.js';
|
||||
import Selection, { Range } from './selection.js';
|
||||
import Composition from './composition.js';
|
||||
import Theme from './theme.js';
|
||||
import scrollRectIntoView from './utils/scrollRectIntoView.js';
|
||||
import createRegistryWithFormats from './utils/createRegistryWithFormats.js';
|
||||
const debug = logger('quill');
|
||||
const globalRegistry = new Parchment.Registry();
|
||||
Parchment.ParentBlot.uiClass = 'ql-ui';
|
||||
|
||||
/**
|
||||
* Options for initializing a Quill instance
|
||||
*/
|
||||
|
||||
/**
|
||||
* Similar to QuillOptions, but with all properties expanded to their default values,
|
||||
* and all selectors resolved to HTMLElements.
|
||||
*/
|
||||
|
||||
class Quill {
|
||||
static DEFAULTS = {
|
||||
bounds: null,
|
||||
modules: {
|
||||
clipboard: true,
|
||||
keyboard: true,
|
||||
history: true,
|
||||
uploader: true
|
||||
},
|
||||
placeholder: '',
|
||||
readOnly: false,
|
||||
registry: globalRegistry,
|
||||
theme: 'default'
|
||||
};
|
||||
static events = Emitter.events;
|
||||
static sources = Emitter.sources;
|
||||
static version = typeof "2.0.3" === 'undefined' ? 'dev' : "2.0.3";
|
||||
static imports = {
|
||||
delta: Delta,
|
||||
parchment: Parchment,
|
||||
'core/module': Module,
|
||||
'core/theme': Theme
|
||||
};
|
||||
static debug(limit) {
|
||||
if (limit === true) {
|
||||
limit = 'log';
|
||||
}
|
||||
logger.level(limit);
|
||||
}
|
||||
static find(node) {
|
||||
let bubble = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
return instances.get(node) || globalRegistry.find(node, bubble);
|
||||
}
|
||||
static import(name) {
|
||||
if (this.imports[name] == null) {
|
||||
debug.error(`Cannot import ${name}. Are you sure it was registered?`);
|
||||
}
|
||||
return this.imports[name];
|
||||
}
|
||||
static register() {
|
||||
if (typeof (arguments.length <= 0 ? undefined : arguments[0]) !== 'string') {
|
||||
const target = arguments.length <= 0 ? undefined : arguments[0];
|
||||
const overwrite = !!(arguments.length <= 1 ? undefined : arguments[1]);
|
||||
const name = 'attrName' in target ? target.attrName : target.blotName;
|
||||
if (typeof name === 'string') {
|
||||
// Shortcut for formats:
|
||||
// register(Blot | Attributor, overwrite)
|
||||
this.register(`formats/${name}`, target, overwrite);
|
||||
} else {
|
||||
Object.keys(target).forEach(key => {
|
||||
this.register(key, target[key], overwrite);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const path = arguments.length <= 0 ? undefined : arguments[0];
|
||||
const target = arguments.length <= 1 ? undefined : arguments[1];
|
||||
const overwrite = !!(arguments.length <= 2 ? undefined : arguments[2]);
|
||||
if (this.imports[path] != null && !overwrite) {
|
||||
debug.warn(`Overwriting ${path} with`, target);
|
||||
}
|
||||
this.imports[path] = target;
|
||||
if ((path.startsWith('blots/') || path.startsWith('formats/')) && target && typeof target !== 'boolean' && target.blotName !== 'abstract') {
|
||||
globalRegistry.register(target);
|
||||
}
|
||||
if (typeof target.register === 'function') {
|
||||
target.register(globalRegistry);
|
||||
}
|
||||
}
|
||||
}
|
||||
constructor(container) {
|
||||
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
this.options = expandConfig(container, options);
|
||||
this.container = this.options.container;
|
||||
if (this.container == null) {
|
||||
debug.error('Invalid Quill container', container);
|
||||
return;
|
||||
}
|
||||
if (this.options.debug) {
|
||||
Quill.debug(this.options.debug);
|
||||
}
|
||||
const html = this.container.innerHTML.trim();
|
||||
this.container.classList.add('ql-container');
|
||||
this.container.innerHTML = '';
|
||||
instances.set(this.container, this);
|
||||
this.root = this.addContainer('ql-editor');
|
||||
this.root.classList.add('ql-blank');
|
||||
this.emitter = new Emitter();
|
||||
const scrollBlotName = Parchment.ScrollBlot.blotName;
|
||||
const ScrollBlot = this.options.registry.query(scrollBlotName);
|
||||
if (!ScrollBlot || !('blotName' in ScrollBlot)) {
|
||||
throw new Error(`Cannot initialize Quill without "${scrollBlotName}" blot`);
|
||||
}
|
||||
this.scroll = new ScrollBlot(this.options.registry, this.root, {
|
||||
emitter: this.emitter
|
||||
});
|
||||
this.editor = new Editor(this.scroll);
|
||||
this.selection = new Selection(this.scroll, this.emitter);
|
||||
this.composition = new Composition(this.scroll, this.emitter);
|
||||
this.theme = new this.options.theme(this, this.options); // eslint-disable-line new-cap
|
||||
this.keyboard = this.theme.addModule('keyboard');
|
||||
this.clipboard = this.theme.addModule('clipboard');
|
||||
this.history = this.theme.addModule('history');
|
||||
this.uploader = this.theme.addModule('uploader');
|
||||
this.theme.addModule('input');
|
||||
this.theme.addModule('uiNode');
|
||||
this.theme.init();
|
||||
this.emitter.on(Emitter.events.EDITOR_CHANGE, type => {
|
||||
if (type === Emitter.events.TEXT_CHANGE) {
|
||||
this.root.classList.toggle('ql-blank', this.editor.isBlank());
|
||||
}
|
||||
});
|
||||
this.emitter.on(Emitter.events.SCROLL_UPDATE, (source, mutations) => {
|
||||
const oldRange = this.selection.lastRange;
|
||||
const [newRange] = this.selection.getRange();
|
||||
const selectionInfo = oldRange && newRange ? {
|
||||
oldRange,
|
||||
newRange
|
||||
} : undefined;
|
||||
modify.call(this, () => this.editor.update(null, mutations, selectionInfo), source);
|
||||
});
|
||||
this.emitter.on(Emitter.events.SCROLL_EMBED_UPDATE, (blot, delta) => {
|
||||
const oldRange = this.selection.lastRange;
|
||||
const [newRange] = this.selection.getRange();
|
||||
const selectionInfo = oldRange && newRange ? {
|
||||
oldRange,
|
||||
newRange
|
||||
} : undefined;
|
||||
modify.call(this, () => {
|
||||
const change = new Delta().retain(blot.offset(this)).retain({
|
||||
[blot.statics.blotName]: delta
|
||||
});
|
||||
return this.editor.update(change, [], selectionInfo);
|
||||
}, Quill.sources.USER);
|
||||
});
|
||||
if (html) {
|
||||
const contents = this.clipboard.convert({
|
||||
html: `${html}<p><br></p>`,
|
||||
text: '\n'
|
||||
});
|
||||
this.setContents(contents);
|
||||
}
|
||||
this.history.clear();
|
||||
if (this.options.placeholder) {
|
||||
this.root.setAttribute('data-placeholder', this.options.placeholder);
|
||||
}
|
||||
if (this.options.readOnly) {
|
||||
this.disable();
|
||||
}
|
||||
this.allowReadOnlyEdits = false;
|
||||
}
|
||||
addContainer(container) {
|
||||
let refNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
||||
if (typeof container === 'string') {
|
||||
const className = container;
|
||||
container = document.createElement('div');
|
||||
container.classList.add(className);
|
||||
}
|
||||
this.container.insertBefore(container, refNode);
|
||||
return container;
|
||||
}
|
||||
blur() {
|
||||
this.selection.setRange(null);
|
||||
}
|
||||
deleteText(index, length, source) {
|
||||
// @ts-expect-error
|
||||
[index, length,, source] = overload(index, length, source);
|
||||
return modify.call(this, () => {
|
||||
return this.editor.deleteText(index, length);
|
||||
}, source, index, -1 * length);
|
||||
}
|
||||
disable() {
|
||||
this.enable(false);
|
||||
}
|
||||
editReadOnly(modifier) {
|
||||
this.allowReadOnlyEdits = true;
|
||||
const value = modifier();
|
||||
this.allowReadOnlyEdits = false;
|
||||
return value;
|
||||
}
|
||||
enable() {
|
||||
let enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
||||
this.scroll.enable(enabled);
|
||||
this.container.classList.toggle('ql-disabled', !enabled);
|
||||
}
|
||||
focus() {
|
||||
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||||
this.selection.focus();
|
||||
if (!options.preventScroll) {
|
||||
this.scrollSelectionIntoView();
|
||||
}
|
||||
}
|
||||
format(name, value) {
|
||||
let source = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Emitter.sources.API;
|
||||
return modify.call(this, () => {
|
||||
const range = this.getSelection(true);
|
||||
let change = new Delta();
|
||||
if (range == null) return change;
|
||||
if (this.scroll.query(name, Parchment.Scope.BLOCK)) {
|
||||
change = this.editor.formatLine(range.index, range.length, {
|
||||
[name]: value
|
||||
});
|
||||
} else if (range.length === 0) {
|
||||
this.selection.format(name, value);
|
||||
return change;
|
||||
} else {
|
||||
change = this.editor.formatText(range.index, range.length, {
|
||||
[name]: value
|
||||
});
|
||||
}
|
||||
this.setSelection(range, Emitter.sources.SILENT);
|
||||
return change;
|
||||
}, source);
|
||||
}
|
||||
formatLine(index, length, name, value, source) {
|
||||
let formats;
|
||||
// eslint-disable-next-line prefer-const
|
||||
[index, length, formats, source] = overload(index, length,
|
||||
// @ts-expect-error
|
||||
name, value, source);
|
||||
return modify.call(this, () => {
|
||||
return this.editor.formatLine(index, length, formats);
|
||||
}, source, index, 0);
|
||||
}
|
||||
formatText(index, length, name, value, source) {
|
||||
let formats;
|
||||
// eslint-disable-next-line prefer-const
|
||||
[index, length, formats, source] = overload(
|
||||
// @ts-expect-error
|
||||
index, length, name, value, source);
|
||||
return modify.call(this, () => {
|
||||
return this.editor.formatText(index, length, formats);
|
||||
}, source, index, 0);
|
||||
}
|
||||
getBounds(index) {
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
let bounds = null;
|
||||
if (typeof index === 'number') {
|
||||
bounds = this.selection.getBounds(index, length);
|
||||
} else {
|
||||
bounds = this.selection.getBounds(index.index, index.length);
|
||||
}
|
||||
if (!bounds) return null;
|
||||
const containerBounds = this.container.getBoundingClientRect();
|
||||
return {
|
||||
bottom: bounds.bottom - containerBounds.top,
|
||||
height: bounds.height,
|
||||
left: bounds.left - containerBounds.left,
|
||||
right: bounds.right - containerBounds.left,
|
||||
top: bounds.top - containerBounds.top,
|
||||
width: bounds.width
|
||||
};
|
||||
}
|
||||
getContents() {
|
||||
let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.getLength() - index;
|
||||
[index, length] = overload(index, length);
|
||||
return this.editor.getContents(index, length);
|
||||
}
|
||||
getFormat() {
|
||||
let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.getSelection(true);
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
if (typeof index === 'number') {
|
||||
return this.editor.getFormat(index, length);
|
||||
}
|
||||
return this.editor.getFormat(index.index, index.length);
|
||||
}
|
||||
getIndex(blot) {
|
||||
return blot.offset(this.scroll);
|
||||
}
|
||||
getLength() {
|
||||
return this.scroll.length();
|
||||
}
|
||||
getLeaf(index) {
|
||||
return this.scroll.leaf(index);
|
||||
}
|
||||
getLine(index) {
|
||||
return this.scroll.line(index);
|
||||
}
|
||||
getLines() {
|
||||
let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Number.MAX_VALUE;
|
||||
if (typeof index !== 'number') {
|
||||
return this.scroll.lines(index.index, index.length);
|
||||
}
|
||||
return this.scroll.lines(index, length);
|
||||
}
|
||||
getModule(name) {
|
||||
return this.theme.modules[name];
|
||||
}
|
||||
getSelection() {
|
||||
let focus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
||||
if (focus) this.focus();
|
||||
this.update(); // Make sure we access getRange with editor in consistent state
|
||||
return this.selection.getRange()[0];
|
||||
}
|
||||
getSemanticHTML() {
|
||||
let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
||||
let length = arguments.length > 1 ? arguments[1] : undefined;
|
||||
if (typeof index === 'number') {
|
||||
length = length ?? this.getLength() - index;
|
||||
}
|
||||
// @ts-expect-error
|
||||
[index, length] = overload(index, length);
|
||||
return this.editor.getHTML(index, length);
|
||||
}
|
||||
getText() {
|
||||
let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
||||
let length = arguments.length > 1 ? arguments[1] : undefined;
|
||||
if (typeof index === 'number') {
|
||||
length = length ?? this.getLength() - index;
|
||||
}
|
||||
// @ts-expect-error
|
||||
[index, length] = overload(index, length);
|
||||
return this.editor.getText(index, length);
|
||||
}
|
||||
hasFocus() {
|
||||
return this.selection.hasFocus();
|
||||
}
|
||||
insertEmbed(index, embed, value) {
|
||||
let source = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Quill.sources.API;
|
||||
return modify.call(this, () => {
|
||||
return this.editor.insertEmbed(index, embed, value);
|
||||
}, source, index);
|
||||
}
|
||||
insertText(index, text, name, value, source) {
|
||||
let formats;
|
||||
// eslint-disable-next-line prefer-const
|
||||
// @ts-expect-error
|
||||
[index,, formats, source] = overload(index, 0, name, value, source);
|
||||
return modify.call(this, () => {
|
||||
return this.editor.insertText(index, text, formats);
|
||||
}, source, index, text.length);
|
||||
}
|
||||
isEnabled() {
|
||||
return this.scroll.isEnabled();
|
||||
}
|
||||
off() {
|
||||
return this.emitter.off(...arguments);
|
||||
}
|
||||
on() {
|
||||
return this.emitter.on(...arguments);
|
||||
}
|
||||
once() {
|
||||
return this.emitter.once(...arguments);
|
||||
}
|
||||
removeFormat(index, length, source) {
|
||||
[index, length,, source] = overload(index, length, source);
|
||||
return modify.call(this, () => {
|
||||
return this.editor.removeFormat(index, length);
|
||||
}, source, index);
|
||||
}
|
||||
scrollRectIntoView(rect) {
|
||||
scrollRectIntoView(this.root, rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Quill#scrollSelectionIntoView() instead.
|
||||
*/
|
||||
scrollIntoView() {
|
||||
console.warn('Quill#scrollIntoView() has been deprecated and will be removed in the near future. Please use Quill#scrollSelectionIntoView() instead.');
|
||||
this.scrollSelectionIntoView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll the current selection into the visible area.
|
||||
* If the selection is already visible, no scrolling will occur.
|
||||
*/
|
||||
scrollSelectionIntoView() {
|
||||
const range = this.selection.lastRange;
|
||||
const bounds = range && this.selection.getBounds(range.index, range.length);
|
||||
if (bounds) {
|
||||
this.scrollRectIntoView(bounds);
|
||||
}
|
||||
}
|
||||
setContents(delta) {
|
||||
let source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Emitter.sources.API;
|
||||
return modify.call(this, () => {
|
||||
delta = new Delta(delta);
|
||||
const length = this.getLength();
|
||||
// Quill will set empty editor to \n
|
||||
const delete1 = this.editor.deleteText(0, length);
|
||||
const applied = this.editor.insertContents(0, delta);
|
||||
// Remove extra \n from empty editor initialization
|
||||
const delete2 = this.editor.deleteText(this.getLength() - 1, 1);
|
||||
return delete1.compose(applied).compose(delete2);
|
||||
}, source);
|
||||
}
|
||||
setSelection(index, length, source) {
|
||||
if (index == null) {
|
||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/22609
|
||||
this.selection.setRange(null, length || Quill.sources.API);
|
||||
} else {
|
||||
// @ts-expect-error
|
||||
[index, length,, source] = overload(index, length, source);
|
||||
this.selection.setRange(new Range(Math.max(0, index), length), source);
|
||||
if (source !== Emitter.sources.SILENT) {
|
||||
this.scrollSelectionIntoView();
|
||||
}
|
||||
}
|
||||
}
|
||||
setText(text) {
|
||||
let source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Emitter.sources.API;
|
||||
const delta = new Delta().insert(text);
|
||||
return this.setContents(delta, source);
|
||||
}
|
||||
update() {
|
||||
let source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Emitter.sources.USER;
|
||||
const change = this.scroll.update(source); // Will update selection before selection.update() does if text changes
|
||||
this.selection.update(source);
|
||||
// TODO this is usually undefined
|
||||
return change;
|
||||
}
|
||||
updateContents(delta) {
|
||||
let source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Emitter.sources.API;
|
||||
return modify.call(this, () => {
|
||||
delta = new Delta(delta);
|
||||
return this.editor.applyDelta(delta);
|
||||
}, source, true);
|
||||
}
|
||||
}
|
||||
function resolveSelector(selector) {
|
||||
return typeof selector === 'string' ? document.querySelector(selector) : selector;
|
||||
}
|
||||
function expandModuleConfig(config) {
|
||||
return Object.entries(config ?? {}).reduce((expanded, _ref) => {
|
||||
let [key, value] = _ref;
|
||||
return {
|
||||
...expanded,
|
||||
[key]: value === true ? {} : value
|
||||
};
|
||||
}, {});
|
||||
}
|
||||
function omitUndefinedValuesFromOptions(obj) {
|
||||
return Object.fromEntries(Object.entries(obj).filter(entry => entry[1] !== undefined));
|
||||
}
|
||||
function expandConfig(containerOrSelector, options) {
|
||||
const container = resolveSelector(containerOrSelector);
|
||||
if (!container) {
|
||||
throw new Error('Invalid Quill container');
|
||||
}
|
||||
const shouldUseDefaultTheme = !options.theme || options.theme === Quill.DEFAULTS.theme;
|
||||
const theme = shouldUseDefaultTheme ? Theme : Quill.import(`themes/${options.theme}`);
|
||||
if (!theme) {
|
||||
throw new Error(`Invalid theme ${options.theme}. Did you register it?`);
|
||||
}
|
||||
const {
|
||||
modules: quillModuleDefaults,
|
||||
...quillDefaults
|
||||
} = Quill.DEFAULTS;
|
||||
const {
|
||||
modules: themeModuleDefaults,
|
||||
...themeDefaults
|
||||
} = theme.DEFAULTS;
|
||||
let userModuleOptions = expandModuleConfig(options.modules);
|
||||
// Special case toolbar shorthand
|
||||
if (userModuleOptions != null && userModuleOptions.toolbar && userModuleOptions.toolbar.constructor !== Object) {
|
||||
userModuleOptions = {
|
||||
...userModuleOptions,
|
||||
toolbar: {
|
||||
container: userModuleOptions.toolbar
|
||||
}
|
||||
};
|
||||
}
|
||||
const modules = merge({}, expandModuleConfig(quillModuleDefaults), expandModuleConfig(themeModuleDefaults), userModuleOptions);
|
||||
const config = {
|
||||
...quillDefaults,
|
||||
...omitUndefinedValuesFromOptions(themeDefaults),
|
||||
...omitUndefinedValuesFromOptions(options)
|
||||
};
|
||||
let registry = options.registry;
|
||||
if (registry) {
|
||||
if (options.formats) {
|
||||
debug.warn('Ignoring "formats" option because "registry" is specified');
|
||||
}
|
||||
} else {
|
||||
registry = options.formats ? createRegistryWithFormats(options.formats, config.registry, debug) : config.registry;
|
||||
}
|
||||
return {
|
||||
...config,
|
||||
registry,
|
||||
container,
|
||||
theme,
|
||||
modules: Object.entries(modules).reduce((modulesWithDefaults, _ref2) => {
|
||||
let [name, value] = _ref2;
|
||||
if (!value) return modulesWithDefaults;
|
||||
const moduleClass = Quill.import(`modules/${name}`);
|
||||
if (moduleClass == null) {
|
||||
debug.error(`Cannot load ${name} module. Are you sure you registered it?`);
|
||||
return modulesWithDefaults;
|
||||
}
|
||||
return {
|
||||
...modulesWithDefaults,
|
||||
// @ts-expect-error
|
||||
[name]: merge({}, moduleClass.DEFAULTS || {}, value)
|
||||
};
|
||||
}, {}),
|
||||
bounds: resolveSelector(config.bounds)
|
||||
};
|
||||
}
|
||||
|
||||
// Handle selection preservation and TEXT_CHANGE emission
|
||||
// common to modification APIs
|
||||
function modify(modifier, source, index, shift) {
|
||||
if (!this.isEnabled() && source === Emitter.sources.USER && !this.allowReadOnlyEdits) {
|
||||
return new Delta();
|
||||
}
|
||||
let range = index == null ? null : this.getSelection();
|
||||
const oldDelta = this.editor.delta;
|
||||
const change = modifier();
|
||||
if (range != null) {
|
||||
if (index === true) {
|
||||
index = range.index; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
if (shift == null) {
|
||||
range = shiftRange(range, change, source);
|
||||
} else if (shift !== 0) {
|
||||
// @ts-expect-error index should always be number
|
||||
range = shiftRange(range, index, shift, source);
|
||||
}
|
||||
this.setSelection(range, Emitter.sources.SILENT);
|
||||
}
|
||||
if (change.length() > 0) {
|
||||
const args = [Emitter.events.TEXT_CHANGE, change, oldDelta, source];
|
||||
this.emitter.emit(Emitter.events.EDITOR_CHANGE, ...args);
|
||||
if (source !== Emitter.sources.SILENT) {
|
||||
this.emitter.emit(...args);
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
function overload(index, length, name, value, source) {
|
||||
let formats = {};
|
||||
// @ts-expect-error
|
||||
if (typeof index.index === 'number' && typeof index.length === 'number') {
|
||||
// Allow for throwaway end (used by insertText/insertEmbed)
|
||||
if (typeof length !== 'number') {
|
||||
// @ts-expect-error
|
||||
source = value;
|
||||
value = name;
|
||||
name = length;
|
||||
// @ts-expect-error
|
||||
length = index.length; // eslint-disable-line prefer-destructuring
|
||||
// @ts-expect-error
|
||||
index = index.index; // eslint-disable-line prefer-destructuring
|
||||
} else {
|
||||
// @ts-expect-error
|
||||
length = index.length; // eslint-disable-line prefer-destructuring
|
||||
// @ts-expect-error
|
||||
index = index.index; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
} else if (typeof length !== 'number') {
|
||||
// @ts-expect-error
|
||||
source = value;
|
||||
value = name;
|
||||
name = length;
|
||||
length = 0;
|
||||
}
|
||||
// Handle format being object, two format name/value strings or excluded
|
||||
if (typeof name === 'object') {
|
||||
// @ts-expect-error Fix me later
|
||||
formats = name;
|
||||
// @ts-expect-error
|
||||
source = value;
|
||||
} else if (typeof name === 'string') {
|
||||
if (value != null) {
|
||||
formats[name] = value;
|
||||
} else {
|
||||
// @ts-expect-error
|
||||
source = name;
|
||||
}
|
||||
}
|
||||
// Handle optional source
|
||||
source = source || Emitter.sources.API;
|
||||
// @ts-expect-error
|
||||
return [index, length, formats, source];
|
||||
}
|
||||
function shiftRange(range, index, lengthOrSource, source) {
|
||||
const length = typeof lengthOrSource === 'number' ? lengthOrSource : 0;
|
||||
if (range == null) return null;
|
||||
let start;
|
||||
let end;
|
||||
// @ts-expect-error -- TODO: add a better type guard around `index`
|
||||
if (index && typeof index.transformPosition === 'function') {
|
||||
[start, end] = [range.index, range.index + range.length].map(pos =>
|
||||
// @ts-expect-error -- TODO: add a better type guard around `index`
|
||||
index.transformPosition(pos, source !== Emitter.sources.USER));
|
||||
} else {
|
||||
[start, end] = [range.index, range.index + range.length].map(pos => {
|
||||
// @ts-expect-error -- TODO: add a better type guard around `index`
|
||||
if (pos < index || pos === index && source === Emitter.sources.USER) return pos;
|
||||
if (length >= 0) {
|
||||
return pos + length;
|
||||
}
|
||||
// @ts-expect-error -- TODO: add a better type guard around `index`
|
||||
return Math.max(index, pos + length);
|
||||
});
|
||||
}
|
||||
return new Range(start, end - start);
|
||||
}
|
||||
export { Parchment, Range };
|
||||
export { globalRegistry, expandConfig, overload, Quill as default };
|
||||
//# sourceMappingURL=quill.js.map
|
||||
1
public/assets/quill/core/quill.js.map
Normal file
1
public/assets/quill/core/quill.js.map
Normal file
File diff suppressed because one or more lines are too long
74
public/assets/quill/core/selection.d.ts
vendored
Normal file
74
public/assets/quill/core/selection.d.ts
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
import Emitter from './emitter.js';
|
||||
import type { EmitterSource } from './emitter.js';
|
||||
import type Cursor from '../blots/cursor.js';
|
||||
import type Scroll from '../blots/scroll.js';
|
||||
type NativeRange = AbstractRange;
|
||||
interface NormalizedRange {
|
||||
start: {
|
||||
node: NativeRange['startContainer'];
|
||||
offset: NativeRange['startOffset'];
|
||||
};
|
||||
end: {
|
||||
node: NativeRange['endContainer'];
|
||||
offset: NativeRange['endOffset'];
|
||||
};
|
||||
native: NativeRange;
|
||||
}
|
||||
export interface Bounds {
|
||||
bottom: number;
|
||||
height: number;
|
||||
left: number;
|
||||
right: number;
|
||||
top: number;
|
||||
width: number;
|
||||
}
|
||||
export declare class Range {
|
||||
index: number;
|
||||
length: number;
|
||||
constructor(index: number, length?: number);
|
||||
}
|
||||
declare class Selection {
|
||||
scroll: Scroll;
|
||||
emitter: Emitter;
|
||||
composing: boolean;
|
||||
mouseDown: boolean;
|
||||
root: HTMLElement;
|
||||
cursor: Cursor;
|
||||
savedRange: Range;
|
||||
lastRange: Range | null;
|
||||
lastNative: NormalizedRange | null;
|
||||
constructor(scroll: Scroll, emitter: Emitter);
|
||||
handleComposition(): void;
|
||||
handleDragging(): void;
|
||||
focus(): void;
|
||||
format(format: string, value: unknown): void;
|
||||
getBounds(index: number, length?: number): DOMRect | {
|
||||
bottom: number;
|
||||
height: number;
|
||||
left: number;
|
||||
right: number;
|
||||
top: number;
|
||||
width: number;
|
||||
} | null;
|
||||
getNativeRange(): NormalizedRange | null;
|
||||
getRange(): [Range, NormalizedRange] | [null, null];
|
||||
hasFocus(): boolean;
|
||||
normalizedToRange(range: NormalizedRange): Range;
|
||||
normalizeNative(nativeRange: NativeRange): {
|
||||
start: {
|
||||
node: Node;
|
||||
offset: number;
|
||||
};
|
||||
end: {
|
||||
node: Node;
|
||||
offset: number;
|
||||
};
|
||||
native: AbstractRange;
|
||||
} | null;
|
||||
rangeToNative(range: Range): [Node | null, number, Node | null, number];
|
||||
setNativeRange(startNode: Node | null, startOffset?: number, endNode?: Node | null, endOffset?: number | undefined, force?: boolean): void;
|
||||
setRange(range: Range | null, force: boolean, source?: EmitterSource): void;
|
||||
setRange(range: Range | null, source?: EmitterSource): void;
|
||||
update(source?: EmitterSource): void;
|
||||
}
|
||||
export default Selection;
|
||||
374
public/assets/quill/core/selection.js
Normal file
374
public/assets/quill/core/selection.js
Normal file
@@ -0,0 +1,374 @@
|
||||
import { LeafBlot, Scope } from 'parchment';
|
||||
import { cloneDeep, isEqual } from 'lodash-es';
|
||||
import Emitter from './emitter.js';
|
||||
import logger from './logger.js';
|
||||
const debug = logger('quill:selection');
|
||||
export class Range {
|
||||
constructor(index) {
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
this.index = index;
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
class Selection {
|
||||
constructor(scroll, emitter) {
|
||||
this.emitter = emitter;
|
||||
this.scroll = scroll;
|
||||
this.composing = false;
|
||||
this.mouseDown = false;
|
||||
this.root = this.scroll.domNode;
|
||||
// @ts-expect-error
|
||||
this.cursor = this.scroll.create('cursor', this);
|
||||
// savedRange is last non-null range
|
||||
this.savedRange = new Range(0, 0);
|
||||
this.lastRange = this.savedRange;
|
||||
this.lastNative = null;
|
||||
this.handleComposition();
|
||||
this.handleDragging();
|
||||
this.emitter.listenDOM('selectionchange', document, () => {
|
||||
if (!this.mouseDown && !this.composing) {
|
||||
setTimeout(this.update.bind(this, Emitter.sources.USER), 1);
|
||||
}
|
||||
});
|
||||
this.emitter.on(Emitter.events.SCROLL_BEFORE_UPDATE, () => {
|
||||
if (!this.hasFocus()) return;
|
||||
const native = this.getNativeRange();
|
||||
if (native == null) return;
|
||||
if (native.start.node === this.cursor.textNode) return; // cursor.restore() will handle
|
||||
this.emitter.once(Emitter.events.SCROLL_UPDATE, (source, mutations) => {
|
||||
try {
|
||||
if (this.root.contains(native.start.node) && this.root.contains(native.end.node)) {
|
||||
this.setNativeRange(native.start.node, native.start.offset, native.end.node, native.end.offset);
|
||||
}
|
||||
const triggeredByTyping = mutations.some(mutation => mutation.type === 'characterData' || mutation.type === 'childList' || mutation.type === 'attributes' && mutation.target === this.root);
|
||||
this.update(triggeredByTyping ? Emitter.sources.SILENT : source);
|
||||
} catch (ignored) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
});
|
||||
this.emitter.on(Emitter.events.SCROLL_OPTIMIZE, (mutations, context) => {
|
||||
if (context.range) {
|
||||
const {
|
||||
startNode,
|
||||
startOffset,
|
||||
endNode,
|
||||
endOffset
|
||||
} = context.range;
|
||||
this.setNativeRange(startNode, startOffset, endNode, endOffset);
|
||||
this.update(Emitter.sources.SILENT);
|
||||
}
|
||||
});
|
||||
this.update(Emitter.sources.SILENT);
|
||||
}
|
||||
handleComposition() {
|
||||
this.emitter.on(Emitter.events.COMPOSITION_BEFORE_START, () => {
|
||||
this.composing = true;
|
||||
});
|
||||
this.emitter.on(Emitter.events.COMPOSITION_END, () => {
|
||||
this.composing = false;
|
||||
if (this.cursor.parent) {
|
||||
const range = this.cursor.restore();
|
||||
if (!range) return;
|
||||
setTimeout(() => {
|
||||
this.setNativeRange(range.startNode, range.startOffset, range.endNode, range.endOffset);
|
||||
}, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
handleDragging() {
|
||||
this.emitter.listenDOM('mousedown', document.body, () => {
|
||||
this.mouseDown = true;
|
||||
});
|
||||
this.emitter.listenDOM('mouseup', document.body, () => {
|
||||
this.mouseDown = false;
|
||||
this.update(Emitter.sources.USER);
|
||||
});
|
||||
}
|
||||
focus() {
|
||||
if (this.hasFocus()) return;
|
||||
this.root.focus({
|
||||
preventScroll: true
|
||||
});
|
||||
this.setRange(this.savedRange);
|
||||
}
|
||||
format(format, value) {
|
||||
this.scroll.update();
|
||||
const nativeRange = this.getNativeRange();
|
||||
if (nativeRange == null || !nativeRange.native.collapsed || this.scroll.query(format, Scope.BLOCK)) return;
|
||||
if (nativeRange.start.node !== this.cursor.textNode) {
|
||||
const blot = this.scroll.find(nativeRange.start.node, false);
|
||||
if (blot == null) return;
|
||||
// TODO Give blot ability to not split
|
||||
if (blot instanceof LeafBlot) {
|
||||
const after = blot.split(nativeRange.start.offset);
|
||||
blot.parent.insertBefore(this.cursor, after);
|
||||
} else {
|
||||
// @ts-expect-error TODO: nativeRange.start.node doesn't seem to match function signature
|
||||
blot.insertBefore(this.cursor, nativeRange.start.node); // Should never happen
|
||||
}
|
||||
this.cursor.attach();
|
||||
}
|
||||
this.cursor.format(format, value);
|
||||
this.scroll.optimize();
|
||||
this.setNativeRange(this.cursor.textNode, this.cursor.textNode.data.length);
|
||||
this.update();
|
||||
}
|
||||
getBounds(index) {
|
||||
let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
const scrollLength = this.scroll.length();
|
||||
index = Math.min(index, scrollLength - 1);
|
||||
length = Math.min(index + length, scrollLength - 1) - index;
|
||||
let node;
|
||||
let [leaf, offset] = this.scroll.leaf(index);
|
||||
if (leaf == null) return null;
|
||||
if (length > 0 && offset === leaf.length()) {
|
||||
const [next] = this.scroll.leaf(index + 1);
|
||||
if (next) {
|
||||
const [line] = this.scroll.line(index);
|
||||
const [nextLine] = this.scroll.line(index + 1);
|
||||
if (line === nextLine) {
|
||||
leaf = next;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
[node, offset] = leaf.position(offset, true);
|
||||
const range = document.createRange();
|
||||
if (length > 0) {
|
||||
range.setStart(node, offset);
|
||||
[leaf, offset] = this.scroll.leaf(index + length);
|
||||
if (leaf == null) return null;
|
||||
[node, offset] = leaf.position(offset, true);
|
||||
range.setEnd(node, offset);
|
||||
return range.getBoundingClientRect();
|
||||
}
|
||||
let side = 'left';
|
||||
let rect;
|
||||
if (node instanceof Text) {
|
||||
// Return null if the text node is empty because it is
|
||||
// not able to get a useful client rect:
|
||||
// https://github.com/w3c/csswg-drafts/issues/2514.
|
||||
// Empty text nodes are most likely caused by TextBlot#optimize()
|
||||
// not getting called when editor content changes.
|
||||
if (!node.data.length) {
|
||||
return null;
|
||||
}
|
||||
if (offset < node.data.length) {
|
||||
range.setStart(node, offset);
|
||||
range.setEnd(node, offset + 1);
|
||||
} else {
|
||||
range.setStart(node, offset - 1);
|
||||
range.setEnd(node, offset);
|
||||
side = 'right';
|
||||
}
|
||||
rect = range.getBoundingClientRect();
|
||||
} else {
|
||||
if (!(leaf.domNode instanceof Element)) return null;
|
||||
rect = leaf.domNode.getBoundingClientRect();
|
||||
if (offset > 0) side = 'right';
|
||||
}
|
||||
return {
|
||||
bottom: rect.top + rect.height,
|
||||
height: rect.height,
|
||||
left: rect[side],
|
||||
right: rect[side],
|
||||
top: rect.top,
|
||||
width: 0
|
||||
};
|
||||
}
|
||||
getNativeRange() {
|
||||
const selection = document.getSelection();
|
||||
if (selection == null || selection.rangeCount <= 0) return null;
|
||||
const nativeRange = selection.getRangeAt(0);
|
||||
if (nativeRange == null) return null;
|
||||
const range = this.normalizeNative(nativeRange);
|
||||
debug.info('getNativeRange', range);
|
||||
return range;
|
||||
}
|
||||
getRange() {
|
||||
const root = this.scroll.domNode;
|
||||
if ('isConnected' in root && !root.isConnected) {
|
||||
// document.getSelection() forces layout on Blink, so we trend to
|
||||
// not calling it.
|
||||
return [null, null];
|
||||
}
|
||||
const normalized = this.getNativeRange();
|
||||
if (normalized == null) return [null, null];
|
||||
const range = this.normalizedToRange(normalized);
|
||||
return [range, normalized];
|
||||
}
|
||||
hasFocus() {
|
||||
return document.activeElement === this.root || document.activeElement != null && contains(this.root, document.activeElement);
|
||||
}
|
||||
normalizedToRange(range) {
|
||||
const positions = [[range.start.node, range.start.offset]];
|
||||
if (!range.native.collapsed) {
|
||||
positions.push([range.end.node, range.end.offset]);
|
||||
}
|
||||
const indexes = positions.map(position => {
|
||||
const [node, offset] = position;
|
||||
const blot = this.scroll.find(node, true);
|
||||
// @ts-expect-error Fix me later
|
||||
const index = blot.offset(this.scroll);
|
||||
if (offset === 0) {
|
||||
return index;
|
||||
}
|
||||
if (blot instanceof LeafBlot) {
|
||||
return index + blot.index(node, offset);
|
||||
}
|
||||
// @ts-expect-error Fix me later
|
||||
return index + blot.length();
|
||||
});
|
||||
const end = Math.min(Math.max(...indexes), this.scroll.length() - 1);
|
||||
const start = Math.min(end, ...indexes);
|
||||
return new Range(start, end - start);
|
||||
}
|
||||
normalizeNative(nativeRange) {
|
||||
if (!contains(this.root, nativeRange.startContainer) || !nativeRange.collapsed && !contains(this.root, nativeRange.endContainer)) {
|
||||
return null;
|
||||
}
|
||||
const range = {
|
||||
start: {
|
||||
node: nativeRange.startContainer,
|
||||
offset: nativeRange.startOffset
|
||||
},
|
||||
end: {
|
||||
node: nativeRange.endContainer,
|
||||
offset: nativeRange.endOffset
|
||||
},
|
||||
native: nativeRange
|
||||
};
|
||||
[range.start, range.end].forEach(position => {
|
||||
let {
|
||||
node,
|
||||
offset
|
||||
} = position;
|
||||
while (!(node instanceof Text) && node.childNodes.length > 0) {
|
||||
if (node.childNodes.length > offset) {
|
||||
node = node.childNodes[offset];
|
||||
offset = 0;
|
||||
} else if (node.childNodes.length === offset) {
|
||||
// @ts-expect-error Fix me later
|
||||
node = node.lastChild;
|
||||
if (node instanceof Text) {
|
||||
offset = node.data.length;
|
||||
} else if (node.childNodes.length > 0) {
|
||||
// Container case
|
||||
offset = node.childNodes.length;
|
||||
} else {
|
||||
// Embed case
|
||||
offset = node.childNodes.length + 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
position.node = node;
|
||||
position.offset = offset;
|
||||
});
|
||||
return range;
|
||||
}
|
||||
rangeToNative(range) {
|
||||
const scrollLength = this.scroll.length();
|
||||
const getPosition = (index, inclusive) => {
|
||||
index = Math.min(scrollLength - 1, index);
|
||||
const [leaf, leafOffset] = this.scroll.leaf(index);
|
||||
return leaf ? leaf.position(leafOffset, inclusive) : [null, -1];
|
||||
};
|
||||
return [...getPosition(range.index, false), ...getPosition(range.index + range.length, true)];
|
||||
}
|
||||
setNativeRange(startNode, startOffset) {
|
||||
let endNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : startNode;
|
||||
let endOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : startOffset;
|
||||
let force = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
||||
debug.info('setNativeRange', startNode, startOffset, endNode, endOffset);
|
||||
if (startNode != null && (this.root.parentNode == null || startNode.parentNode == null ||
|
||||
// @ts-expect-error Fix me later
|
||||
endNode.parentNode == null)) {
|
||||
return;
|
||||
}
|
||||
const selection = document.getSelection();
|
||||
if (selection == null) return;
|
||||
if (startNode != null) {
|
||||
if (!this.hasFocus()) this.root.focus({
|
||||
preventScroll: true
|
||||
});
|
||||
const {
|
||||
native
|
||||
} = this.getNativeRange() || {};
|
||||
if (native == null || force || startNode !== native.startContainer || startOffset !== native.startOffset || endNode !== native.endContainer || endOffset !== native.endOffset) {
|
||||
if (startNode instanceof Element && startNode.tagName === 'BR') {
|
||||
// @ts-expect-error Fix me later
|
||||
startOffset = Array.from(startNode.parentNode.childNodes).indexOf(startNode);
|
||||
startNode = startNode.parentNode;
|
||||
}
|
||||
if (endNode instanceof Element && endNode.tagName === 'BR') {
|
||||
// @ts-expect-error Fix me later
|
||||
endOffset = Array.from(endNode.parentNode.childNodes).indexOf(endNode);
|
||||
endNode = endNode.parentNode;
|
||||
}
|
||||
const range = document.createRange();
|
||||
// @ts-expect-error Fix me later
|
||||
range.setStart(startNode, startOffset);
|
||||
// @ts-expect-error Fix me later
|
||||
range.setEnd(endNode, endOffset);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
} else {
|
||||
selection.removeAllRanges();
|
||||
this.root.blur();
|
||||
}
|
||||
}
|
||||
setRange(range) {
|
||||
let force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
let source = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Emitter.sources.API;
|
||||
if (typeof force === 'string') {
|
||||
source = force;
|
||||
force = false;
|
||||
}
|
||||
debug.info('setRange', range);
|
||||
if (range != null) {
|
||||
const args = this.rangeToNative(range);
|
||||
this.setNativeRange(...args, force);
|
||||
} else {
|
||||
this.setNativeRange(null);
|
||||
}
|
||||
this.update(source);
|
||||
}
|
||||
update() {
|
||||
let source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Emitter.sources.USER;
|
||||
const oldRange = this.lastRange;
|
||||
const [lastRange, nativeRange] = this.getRange();
|
||||
this.lastRange = lastRange;
|
||||
this.lastNative = nativeRange;
|
||||
if (this.lastRange != null) {
|
||||
this.savedRange = this.lastRange;
|
||||
}
|
||||
if (!isEqual(oldRange, this.lastRange)) {
|
||||
if (!this.composing && nativeRange != null && nativeRange.native.collapsed && nativeRange.start.node !== this.cursor.textNode) {
|
||||
const range = this.cursor.restore();
|
||||
if (range) {
|
||||
this.setNativeRange(range.startNode, range.startOffset, range.endNode, range.endOffset);
|
||||
}
|
||||
}
|
||||
const args = [Emitter.events.SELECTION_CHANGE, cloneDeep(this.lastRange), cloneDeep(oldRange), source];
|
||||
this.emitter.emit(Emitter.events.EDITOR_CHANGE, ...args);
|
||||
if (source !== Emitter.sources.SILENT) {
|
||||
this.emitter.emit(...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function contains(parent, descendant) {
|
||||
try {
|
||||
// Firefox inserts inaccessible nodes around video elements
|
||||
descendant.parentNode; // eslint-disable-line @typescript-eslint/no-unused-expressions
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return parent.contains(descendant);
|
||||
}
|
||||
export default Selection;
|
||||
//# sourceMappingURL=selection.js.map
|
||||
1
public/assets/quill/core/selection.js.map
Normal file
1
public/assets/quill/core/selection.js.map
Normal file
File diff suppressed because one or more lines are too long
32
public/assets/quill/core/theme.d.ts
vendored
Normal file
32
public/assets/quill/core/theme.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import type Quill from '../core.js';
|
||||
import type Clipboard from '../modules/clipboard.js';
|
||||
import type History from '../modules/history.js';
|
||||
import type Keyboard from '../modules/keyboard.js';
|
||||
import type { ToolbarProps } from '../modules/toolbar.js';
|
||||
import type Uploader from '../modules/uploader.js';
|
||||
export interface ThemeOptions {
|
||||
modules: Record<string, unknown> & {
|
||||
toolbar?: null | ToolbarProps;
|
||||
};
|
||||
}
|
||||
declare class Theme {
|
||||
protected quill: Quill;
|
||||
protected options: ThemeOptions;
|
||||
static DEFAULTS: ThemeOptions;
|
||||
static themes: {
|
||||
default: typeof Theme;
|
||||
};
|
||||
modules: ThemeOptions['modules'];
|
||||
constructor(quill: Quill, options: ThemeOptions);
|
||||
init(): void;
|
||||
addModule(name: 'clipboard'): Clipboard;
|
||||
addModule(name: 'keyboard'): Keyboard;
|
||||
addModule(name: 'uploader'): Uploader;
|
||||
addModule(name: 'history'): History;
|
||||
addModule(name: string): unknown;
|
||||
}
|
||||
export interface ThemeConstructor {
|
||||
new (quill: Quill, options: unknown): Theme;
|
||||
DEFAULTS: ThemeOptions;
|
||||
}
|
||||
export default Theme;
|
||||
28
public/assets/quill/core/theme.js
Normal file
28
public/assets/quill/core/theme.js
Normal file
@@ -0,0 +1,28 @@
|
||||
class Theme {
|
||||
static DEFAULTS = {
|
||||
modules: {}
|
||||
};
|
||||
static themes = {
|
||||
default: Theme
|
||||
};
|
||||
modules = {};
|
||||
constructor(quill, options) {
|
||||
this.quill = quill;
|
||||
this.options = options;
|
||||
}
|
||||
init() {
|
||||
Object.keys(this.options.modules).forEach(name => {
|
||||
if (this.modules[name] == null) {
|
||||
this.addModule(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
addModule(name) {
|
||||
// @ts-expect-error
|
||||
const ModuleClass = this.quill.constructor.import(`modules/${name}`);
|
||||
this.modules[name] = new ModuleClass(this.quill, this.options.modules[name] || {});
|
||||
return this.modules[name];
|
||||
}
|
||||
}
|
||||
export default Theme;
|
||||
//# sourceMappingURL=theme.js.map
|
||||
1
public/assets/quill/core/theme.js.map
Normal file
1
public/assets/quill/core/theme.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"theme.js","names":["Theme","DEFAULTS","modules","themes","default","constructor","quill","options","init","Object","keys","forEach","name","addModule","ModuleClass","import"],"sources":["../../src/core/theme.ts"],"sourcesContent":["import type Quill from '../core.js';\nimport type Clipboard from '../modules/clipboard.js';\nimport type History from '../modules/history.js';\nimport type Keyboard from '../modules/keyboard.js';\nimport type { ToolbarProps } from '../modules/toolbar.js';\nimport type Uploader from '../modules/uploader.js';\n\nexport interface ThemeOptions {\n modules: Record<string, unknown> & {\n toolbar?: null | ToolbarProps;\n };\n}\n\nclass Theme {\n static DEFAULTS: ThemeOptions = {\n modules: {},\n };\n\n static themes = {\n default: Theme,\n };\n\n modules: ThemeOptions['modules'] = {};\n\n constructor(\n protected quill: Quill,\n protected options: ThemeOptions,\n ) {}\n\n init() {\n Object.keys(this.options.modules).forEach((name) => {\n if (this.modules[name] == null) {\n this.addModule(name);\n }\n });\n }\n\n addModule(name: 'clipboard'): Clipboard;\n addModule(name: 'keyboard'): Keyboard;\n addModule(name: 'uploader'): Uploader;\n addModule(name: 'history'): History;\n addModule(name: string): unknown;\n addModule(name: string) {\n // @ts-expect-error\n const ModuleClass = this.quill.constructor.import(`modules/${name}`);\n this.modules[name] = new ModuleClass(\n this.quill,\n this.options.modules[name] || {},\n );\n return this.modules[name];\n }\n}\n\nexport interface ThemeConstructor {\n new (quill: Quill, options: unknown): Theme;\n DEFAULTS: ThemeOptions;\n}\n\nexport default Theme;\n"],"mappings":"AAaA,MAAMA,KAAK,CAAC;EACV,OAAOC,QAAQ,GAAiB;IAC9BC,OAAO,EAAE,CAAC;EACZ,CAAC;EAED,OAAOC,MAAM,GAAG;IACdC,OAAO,EAAEJ;EACX,CAAC;EAEDE,OAAO,GAA4B,CAAC,CAAC;EAErCG,WAAWA,CACCC,KAAY,EACZC,OAAqB,EAC/B;IAAA,KAFUD,KAAY,GAAZA,KAAY;IAAA,KACZC,OAAqB,GAArBA,OAAqB;EAC9B;EAEHC,IAAIA,CAAA,EAAG;IACLC,MAAM,CAACC,IAAI,CAAC,IAAI,CAACH,OAAO,CAACL,OAAO,CAAC,CAACS,OAAO,CAAEC,IAAI,IAAK;MAClD,IAAI,IAAI,CAACV,OAAO,CAACU,IAAI,CAAC,IAAI,IAAI,EAAE;QAC9B,IAAI,CAACC,SAAS,CAACD,IAAI,CAAC;MACtB;IACF,CAAC,CAAC;EACJ;EAOAC,SAASA,CAACD,IAAY,EAAE;IACtB;IACA,MAAME,WAAW,GAAG,IAAI,CAACR,KAAK,CAACD,WAAW,CAACU,MAAM,CAAE,WAAUH,IAAK,EAAC,CAAC;IACpE,IAAI,CAACV,OAAO,CAACU,IAAI,CAAC,GAAG,IAAIE,WAAW,CAClC,IAAI,CAACR,KAAK,EACV,IAAI,CAACC,OAAO,CAACL,OAAO,CAACU,IAAI,CAAC,IAAI,CAAC,CACjC,CAAC;IACD,OAAO,IAAI,CAACV,OAAO,CAACU,IAAI,CAAC;EAC3B;AACF;AAOA,eAAeZ,KAAK","ignoreList":[]}
|
||||
5
public/assets/quill/core/utils/createRegistryWithFormats.d.ts
vendored
Normal file
5
public/assets/quill/core/utils/createRegistryWithFormats.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Registry } from 'parchment';
|
||||
declare const createRegistryWithFormats: (formats: string[], sourceRegistry: Registry, debug: {
|
||||
error: (errorMessage: string) => void;
|
||||
}) => Registry;
|
||||
export default createRegistryWithFormats;
|
||||
29
public/assets/quill/core/utils/createRegistryWithFormats.js
Normal file
29
public/assets/quill/core/utils/createRegistryWithFormats.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Registry } from 'parchment';
|
||||
const MAX_REGISTER_ITERATIONS = 100;
|
||||
const CORE_FORMATS = ['block', 'break', 'cursor', 'inline', 'scroll', 'text'];
|
||||
const createRegistryWithFormats = (formats, sourceRegistry, debug) => {
|
||||
const registry = new Registry();
|
||||
CORE_FORMATS.forEach(name => {
|
||||
const coreBlot = sourceRegistry.query(name);
|
||||
if (coreBlot) registry.register(coreBlot);
|
||||
});
|
||||
formats.forEach(name => {
|
||||
let format = sourceRegistry.query(name);
|
||||
if (!format) {
|
||||
debug.error(`Cannot register "${name}" specified in "formats" config. Are you sure it was registered?`);
|
||||
}
|
||||
let iterations = 0;
|
||||
while (format) {
|
||||
registry.register(format);
|
||||
format = 'blotName' in format ? format.requiredContainer ?? null : null;
|
||||
iterations += 1;
|
||||
if (iterations > MAX_REGISTER_ITERATIONS) {
|
||||
debug.error(`Cycle detected in registering blot requiredContainer: "${name}"`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
return registry;
|
||||
};
|
||||
export default createRegistryWithFormats;
|
||||
//# sourceMappingURL=createRegistryWithFormats.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"createRegistryWithFormats.js","names":["Registry","MAX_REGISTER_ITERATIONS","CORE_FORMATS","createRegistryWithFormats","formats","sourceRegistry","debug","registry","forEach","name","coreBlot","query","register","format","error","iterations","requiredContainer"],"sources":["../../../src/core/utils/createRegistryWithFormats.ts"],"sourcesContent":["import { Registry } from 'parchment';\n\nconst MAX_REGISTER_ITERATIONS = 100;\nconst CORE_FORMATS = ['block', 'break', 'cursor', 'inline', 'scroll', 'text'];\n\nconst createRegistryWithFormats = (\n formats: string[],\n sourceRegistry: Registry,\n debug: { error: (errorMessage: string) => void },\n) => {\n const registry = new Registry();\n CORE_FORMATS.forEach((name) => {\n const coreBlot = sourceRegistry.query(name);\n if (coreBlot) registry.register(coreBlot);\n });\n\n formats.forEach((name) => {\n let format = sourceRegistry.query(name);\n if (!format) {\n debug.error(\n `Cannot register \"${name}\" specified in \"formats\" config. Are you sure it was registered?`,\n );\n }\n let iterations = 0;\n while (format) {\n registry.register(format);\n format = 'blotName' in format ? format.requiredContainer ?? null : null;\n\n iterations += 1;\n if (iterations > MAX_REGISTER_ITERATIONS) {\n debug.error(\n `Cycle detected in registering blot requiredContainer: \"${name}\"`,\n );\n break;\n }\n }\n });\n\n return registry;\n};\n\nexport default createRegistryWithFormats;\n"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,WAAW;AAEpC,MAAMC,uBAAuB,GAAG,GAAG;AACnC,MAAMC,YAAY,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;AAE7E,MAAMC,yBAAyB,GAAGA,CAChCC,OAAiB,EACjBC,cAAwB,EACxBC,KAAgD,KAC7C;EACH,MAAMC,QAAQ,GAAG,IAAIP,QAAQ,CAAC,CAAC;EAC/BE,YAAY,CAACM,OAAO,CAAEC,IAAI,IAAK;IAC7B,MAAMC,QAAQ,GAAGL,cAAc,CAACM,KAAK,CAACF,IAAI,CAAC;IAC3C,IAAIC,QAAQ,EAAEH,QAAQ,CAACK,QAAQ,CAACF,QAAQ,CAAC;EAC3C,CAAC,CAAC;EAEFN,OAAO,CAACI,OAAO,CAAEC,IAAI,IAAK;IACxB,IAAII,MAAM,GAAGR,cAAc,CAACM,KAAK,CAACF,IAAI,CAAC;IACvC,IAAI,CAACI,MAAM,EAAE;MACXP,KAAK,CAACQ,KAAK,CACR,oBAAmBL,IAAK,kEAC3B,CAAC;IACH;IACA,IAAIM,UAAU,GAAG,CAAC;IAClB,OAAOF,MAAM,EAAE;MACbN,QAAQ,CAACK,QAAQ,CAACC,MAAM,CAAC;MACzBA,MAAM,GAAG,UAAU,IAAIA,MAAM,GAAGA,MAAM,CAACG,iBAAiB,IAAI,IAAI,GAAG,IAAI;MAEvED,UAAU,IAAI,CAAC;MACf,IAAIA,UAAU,GAAGd,uBAAuB,EAAE;QACxCK,KAAK,CAACQ,KAAK,CACR,0DAAyDL,IAAK,GACjE,CAAC;QACD;MACF;IACF;EACF,CAAC,CAAC;EAEF,OAAOF,QAAQ;AACjB,CAAC;AAED,eAAeJ,yBAAyB","ignoreList":[]}
|
||||
8
public/assets/quill/core/utils/scrollRectIntoView.d.ts
vendored
Normal file
8
public/assets/quill/core/utils/scrollRectIntoView.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export type Rect = {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
};
|
||||
declare const scrollRectIntoView: (root: HTMLElement, targetRect: Rect) => void;
|
||||
export default scrollRectIntoView;
|
||||
75
public/assets/quill/core/utils/scrollRectIntoView.js
Normal file
75
public/assets/quill/core/utils/scrollRectIntoView.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const getParentElement = element => element.parentElement || element.getRootNode().host || null;
|
||||
const getElementRect = element => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const scaleX = 'offsetWidth' in element && Math.abs(rect.width) / element.offsetWidth || 1;
|
||||
const scaleY = 'offsetHeight' in element && Math.abs(rect.height) / element.offsetHeight || 1;
|
||||
return {
|
||||
top: rect.top,
|
||||
right: rect.left + element.clientWidth * scaleX,
|
||||
bottom: rect.top + element.clientHeight * scaleY,
|
||||
left: rect.left
|
||||
};
|
||||
};
|
||||
const paddingValueToInt = value => {
|
||||
const number = parseInt(value, 10);
|
||||
return Number.isNaN(number) ? 0 : number;
|
||||
};
|
||||
|
||||
// Follow the steps described in https://www.w3.org/TR/cssom-view-1/#element-scrolling-members,
|
||||
// assuming that the scroll option is set to 'nearest'.
|
||||
const getScrollDistance = (targetStart, targetEnd, scrollStart, scrollEnd, scrollPaddingStart, scrollPaddingEnd) => {
|
||||
if (targetStart < scrollStart && targetEnd > scrollEnd) {
|
||||
return 0;
|
||||
}
|
||||
if (targetStart < scrollStart) {
|
||||
return -(scrollStart - targetStart + scrollPaddingStart);
|
||||
}
|
||||
if (targetEnd > scrollEnd) {
|
||||
return targetEnd - targetStart > scrollEnd - scrollStart ? targetStart + scrollPaddingStart - scrollStart : targetEnd - scrollEnd + scrollPaddingEnd;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
const scrollRectIntoView = (root, targetRect) => {
|
||||
const document = root.ownerDocument;
|
||||
let rect = targetRect;
|
||||
let current = root;
|
||||
while (current) {
|
||||
const isDocumentBody = current === document.body;
|
||||
const bounding = isDocumentBody ? {
|
||||
top: 0,
|
||||
right: window.visualViewport?.width ?? document.documentElement.clientWidth,
|
||||
bottom: window.visualViewport?.height ?? document.documentElement.clientHeight,
|
||||
left: 0
|
||||
} : getElementRect(current);
|
||||
const style = getComputedStyle(current);
|
||||
const scrollDistanceX = getScrollDistance(rect.left, rect.right, bounding.left, bounding.right, paddingValueToInt(style.scrollPaddingLeft), paddingValueToInt(style.scrollPaddingRight));
|
||||
const scrollDistanceY = getScrollDistance(rect.top, rect.bottom, bounding.top, bounding.bottom, paddingValueToInt(style.scrollPaddingTop), paddingValueToInt(style.scrollPaddingBottom));
|
||||
if (scrollDistanceX || scrollDistanceY) {
|
||||
if (isDocumentBody) {
|
||||
document.defaultView?.scrollBy(scrollDistanceX, scrollDistanceY);
|
||||
} else {
|
||||
const {
|
||||
scrollLeft,
|
||||
scrollTop
|
||||
} = current;
|
||||
if (scrollDistanceY) {
|
||||
current.scrollTop += scrollDistanceY;
|
||||
}
|
||||
if (scrollDistanceX) {
|
||||
current.scrollLeft += scrollDistanceX;
|
||||
}
|
||||
const scrolledLeft = current.scrollLeft - scrollLeft;
|
||||
const scrolledTop = current.scrollTop - scrollTop;
|
||||
rect = {
|
||||
left: rect.left - scrolledLeft,
|
||||
top: rect.top - scrolledTop,
|
||||
right: rect.right - scrolledLeft,
|
||||
bottom: rect.bottom - scrolledTop
|
||||
};
|
||||
}
|
||||
}
|
||||
current = isDocumentBody || style.position === 'fixed' ? null : getParentElement(current);
|
||||
}
|
||||
};
|
||||
export default scrollRectIntoView;
|
||||
//# sourceMappingURL=scrollRectIntoView.js.map
|
||||
1
public/assets/quill/core/utils/scrollRectIntoView.js.map
Normal file
1
public/assets/quill/core/utils/scrollRectIntoView.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user