first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:30:42 +03:00
commit 4d92991817
1982 changed files with 284835 additions and 0 deletions

View 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;

View 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

View 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
View 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;

View 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(' ', '&nbsp;');
}
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

File diff suppressed because one or more lines are too long

33
public/assets/quill/core/emitter.d.ts vendored Normal file
View 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;

View 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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
import type Quill from '../core.js';
declare const _default: WeakMap<Node, Quill>;
export default _default;

View File

@@ -0,0 +1,2 @@
export default new WeakMap();
//# sourceMappingURL=instances.js.map

View 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
View 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;

View 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

View 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
View 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;

View 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

View 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
View 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 };

View 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

File diff suppressed because one or more lines are too long

74
public/assets/quill/core/selection.d.ts vendored Normal file
View 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;

View 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

File diff suppressed because one or more lines are too long

32
public/assets/quill/core/theme.d.ts vendored Normal file
View 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;

View 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

View 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":[]}

View 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;

View 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

View File

@@ -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":[]}

View 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;

View 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

File diff suppressed because one or more lines are too long