Latest repo

This commit is contained in:
Marc
2025-06-02 16:42:16 +00:00
parent 53ddf1a329
commit cde5fae175
27907 changed files with 3875388 additions and 1 deletions

29
node_modules/parchment/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,29 @@
Copyright (c) 2015, Jason Chen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

274
node_modules/parchment/README.md generated vendored Normal file
View File

@@ -0,0 +1,274 @@
# Parchment [![Build Status](https://travis-ci.org/quilljs/parchment.svg?branch=master)](http://travis-ci.org/quilljs/parchment) [![Coverage Status](https://coveralls.io/repos/github/quilljs/parchment/badge.svg?branch=master)](https://coveralls.io/github/quilljs/parchment?branch=master)
Parchment is [Quill](https://quilljs.com)'s document model. It is a parallel tree structure to the DOM tree, and provides functionality useful for content editors, like Quill. A Parchment tree is made up of [Blots](#blots), which mirror a DOM node counterpart. Blots can provide structure, formatting, and/or content. [Attributors](#attributors) can also provide lightweight formatting information.
**Note:** You should never instantiate a Blot yourself with `new`. This may prevent necessary lifecycle functionality of a Blot. Use the [Registry](#registry)'s `create()` method instead.
`npm install --save parchment`
See [Cloning Medium with Parchment](https://quilljs.com/guides/cloning-medium-with-parchment/) for a guide on how Quill uses Parchment its document model.
## Blots
Blots are the basic building blocks of a Parchment document. Several basic implementations such as [Block](#block-blot), [Inline](#inline-blot), and [Embed](#embed-blot) are provided. In general you will want to extend one of these, instead of building from scratch. After implementation, blots need to be [registered](#registry) before usage.
At the very minimum a Blot must be named with a static `blotName` and associated with either a `tagName` or `className`. If a Blot is defined with both a tag and class, the class takes precedence, but the tag may be used as a fallback. Blots must also have a [scope](#registry), which determine if it is inline or block.
```typescript
class Blot {
static blotName: string;
static className: string;
static tagName: string;
static scope: Scope;
domNode: Node;
prev: Blot;
next: Blot;
parent: Blot;
// Creates corresponding DOM node
static create(value?: any): Node;
constructor(domNode: Node, value?: any);
// For leaves, length of blot's value()
// For parents, sum of children's values
length(): Number;
// Manipulate at given index and length, if applicable.
// Will often pass call onto appropriate child.
deleteAt(index: number, length: number);
formatAt(index: number, length: number, format: string, value: any);
insertAt(index: number, text: string);
insertAt(index: number, embed: string, value: any);
// Returns offset between this blot and an ancestor's
offset(ancestor: Blot = this.parent): number;
// Called after update cycle completes. Cannot change the value or length
// of the document, and any DOM operation must reduce complexity of the DOM
// tree. A shared context object is passed through all blots.
optimize(context: {[key: string]: any}): void;
// Called when blot changes, with the mutation records of its change.
// Internal records of the blot values can be updated, and modifcations of
// the blot itself is permitted. Can be trigger from user change or API call.
// A shared context object is passed through all blots.
update(mutations: MutationRecord[], context: {[key: string]: any});
/** Leaf Blots only **/
// Returns the value represented by domNode if it is this Blot's type
// No checking that domNode can represent this Blot type is required so
// applications needing it should check externally before calling.
static value(domNode): any;
// Given location represented by node and offset from DOM Selection Range,
// return index to that location.
index(node: Node, offset: number): number;
// Given index to location within blot, return node and offset representing
// that location, consumable by DOM Selection Range
position(index: number, inclusive: boolean): [Node, number];
// Return value represented by this blot
// Should not change without interaction from API or
// user change detectable by update()
value(): any;
/** Parent blots only **/
// Whitelist array of Blots that can be direct children.
static allowedChildren: Blot[];
// Default child blot to be inserted if this blot becomes empty.
static defaultChild: string;
children: LinkedList<Blot>;
// Called during construction, should fill its own children LinkedList.
build();
// Useful search functions for descendant(s), should not modify
descendant(type: BlotClass, index: number, inclusive): Blot
descendents(type: BlotClass, index: number, length: number): Blot[];
/** Formattable blots only **/
// Returns format values represented by domNode if it is this Blot's type
// No checking that domNode is this Blot's type is required.
static formats(domNode: Node);
// Apply format to blot. Should not pass onto child or other blot.
format(format: name, value: any);
// Return formats represented by blot, including from Attributors.
formats(): Object;
}
```
### Example
Implementation for a Blot representing a link, which is a parent, inline scoped, and formattable.
```typescript
import Parchment from 'parchment';
class LinkBlot extends Parchment.Inline {
static create(url) {
let node = super.create();
node.setAttribute('href', url);
node.setAttribute('target', '_blank');
node.setAttribute('title', node.textContent);
return node;
}
static formats(domNode) {
return domNode.getAttribute('href') || true;
}
format(name, value) {
if (name === 'link' && value) {
this.domNode.setAttribute('href', value);
} else {
super.format(name, value);
}
}
formats() {
let formats = super.formats();
formats['link'] = LinkBlot.formats(this.domNode);
return formats;
}
}
LinkBlot.blotName = 'link';
LinkBlot.tagName = 'A';
Parchment.register(LinkBlot);
```
Quill also provides many great example implementions in its [source code](https://github.com/quilljs/quill/tree/develop/formats).
### Block Blot
Basic implementation of a block scoped formattable parent Blot. Formatting a block blot by default will replace the appropriate subsection of the blot.
### Inline Blot
Basic implementation of an inline scoped formattable parent Blot. Formatting an inline blot by default either wraps itself with another blot or passes the call to the approprate child.
### Embed Blot
Basic implementation of a non-text leaf blot, that is formattable. Its corresponding DOM node will often be a [Void Element](https://www.w3.org/TR/html5/syntax.html#void-elements), but can be a [Normal Element](https://www.w3.org/TR/html5/syntax.html#normal-elements). In these cases Parchment will not manipulate or generally be aware of the element's children, and it will be important to correctly implement the blot's `index()` and `position()` functions to correctly work with cursors/selections.
### Scroll
The root parent blot of a Parchment document. It is not formattable.
## Attributors
Attributors are the alternative, more lightweight, way to represent formats. Their DOM counterpart is an [Attribute](https://www.w3.org/TR/html5/syntax.html#attributes-0). Like a DOM attribute's relationship to a node, Attributors are meant to belong to Blots. Calling `formats()` on an [Inline](#inline-blot) or [Block](#block-blot) blot will return both the format of the corresponding DOM node represents (if any) and the formats the DOM node's attributes represent (if any).
Attributors have the following interface:
```typescript
class Attributor {
attrName: string;
keyName: string;
scope: Scope;
whitelist: string[];
constructor(attrName: string, keyName: string, options: Object = {});
add(node: HTMLElement, value: string): boolean;
canAdd(node: HTMLElement, value: string): boolean;
remove(node: HTMLElement);
value(node: HTMLElement);
}
```
Note custom attributors are instances, rather than class definitions like Blots. Similar to Blots, instead of creating from scratch, you will probably want to use existing Attributor implementations, such as the base [Attributor](#attributor), [Class Attributor](#class-attributor) or [Style Attributor](#style-attributor).
The implementation for Attributors is surprisingly simple, and its [source code](https://github.com/quilljs/parchment/tree/master/src/attributor) may be another source of understanding.
### Attributor
Uses a plain attribute to represent formats.
```js
import Parchment from 'parchment';
let Width = new Parchment.Attributor.Attribute('width', 'width');
Parchment.register(Width);
let imageNode = document.createElement('img');
Width.add(imageNode, '10px');
console.log(imageNode.outerHTML); // Will print <img width="10px">
Width.value(imageNode); // Will return 10px
Width.remove(imageNode);
console.log(imageNode.outerHTML); // Will print <img>
```
### Class Attributor
Uses a classname pattern to represent formats.
```js
import Parchment from 'parchment';
let Align = new Parchment.Attributor.Class('align', 'blot-align');
Parchment.register(Align);
let node = document.createElement('div');
Align.add(node, 'right');
console.log(node.outerHTML); // Will print <div class="blot-align-right"></div>
```
### Style Attributor
Uses inline styles to represent formats.
```js
import Parchment from 'parchment';
let Align = new Parchment.Attributor.Style('align', 'text-align', {
whitelist: ['right', 'center', 'justify'] // Having no value implies left align
});
Parchment.register(Align);
let node = document.createElement('div');
Align.add(node, 'right');
console.log(node.outerHTML); // Will print <div style="text-align: right;"></div>
```
## Registry
All methods are accessible from Parchment ex. `Parchment.create('bold')`.
```typescript
// Creates a blot given a name or DOM node.
// When given just a scope, creates blot the same name as scope
create(domNode: Node, value?: any): Blot;
create(blotName: string, value?: any): Blot;
create(scope: Scope): Blot;
// Given DOM node, find corresponding Blot.
// Bubbling is useful when searching for a Embed Blot with its corresponding
// DOM node's descendant nodes.
find(domNode: Node, bubble: boolean = false): Blot;
// Search for a Blot or Attributor
// When given just a scope, finds blot with same name as scope
query(tagName: string, scope: Scope = Scope.ANY): BlotClass;
query(blotName: string, scope: Scope = Scope.ANY): BlotClass;
query(domNode: Node, scope: Scope = Scope.ANY): BlotClass;
query(scope: Scope): BlotClass;
query(attributorName: string, scope: Scope = Scope.ANY): Attributor;
// Register Blot class definition or Attributor instance
register(BlotClass | Attributor);
```

1749
node_modules/parchment/dist/parchment.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

1
node_modules/parchment/dist/parchment.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
import * as Registry from '../registry';
export interface AttributorOptions {
scope?: Registry.Scope;
whitelist?: string[];
}
export default class Attributor {
attrName: string;
keyName: string;
scope: Registry.Scope;
whitelist: string[] | undefined;
static keys(node: HTMLElement): string[];
constructor(attrName: string, keyName: string, options?: AttributorOptions);
add(node: HTMLElement, value: string): boolean;
canAdd(node: HTMLElement, value: any): boolean;
remove(node: HTMLElement): void;
value(node: HTMLElement): string;
}

View File

@@ -0,0 +1,8 @@
import Attributor from './attributor';
declare class ClassAttributor extends Attributor {
static keys(node: HTMLElement): string[];
add(node: HTMLElement, value: string): boolean;
remove(node: HTMLElement): void;
value(node: HTMLElement): string;
}
export default ClassAttributor;

15
node_modules/parchment/dist/src/attributor/store.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import Attributor from './attributor';
import { Formattable } from '../blot/abstract/blot';
declare class AttributorStore {
private attributes;
private domNode;
constructor(domNode: HTMLElement);
attribute(attribute: Attributor, value: any): void;
build(): void;
copy(target: Formattable): void;
move(target: Formattable): void;
values(): {
[key: string]: any;
};
}
export default AttributorStore;

View File

@@ -0,0 +1,8 @@
import Attributor from './attributor';
declare class StyleAttributor extends Attributor {
static keys(node: Element): string[];
add(node: HTMLElement, value: string): boolean;
remove(node: HTMLElement): void;
value(node: HTMLElement): string;
}
export default StyleAttributor;

View File

@@ -0,0 +1,63 @@
import LinkedList from '../../collection/linked-list';
import LinkedNode from '../../collection/linked-node';
export interface Blot extends LinkedNode {
scroll: Parent;
parent: Parent;
prev: Blot;
next: Blot;
domNode: Node;
attach(): void;
clone(): Blot;
detach(): void;
insertInto(parentBlot: Parent, refBlot?: Blot): void;
isolate(index: number, length: number): Blot;
offset(root?: Blot): number;
remove(): void;
replace(target: Blot): void;
replaceWith(name: string, value: any): Blot;
replaceWith(replacement: Blot): Blot;
split(index: number, force?: boolean): Blot;
wrap(name: string, value: any): Parent;
wrap(wrapper: Parent): Parent;
deleteAt(index: number, length: number): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): void;
optimize(context: {
[key: string]: any;
}): void;
optimize(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
}
export interface Parent extends Blot {
children: LinkedList<Blot>;
domNode: HTMLElement;
appendChild(child: Blot): void;
descendant<T>(type: {
new (): T;
}, index: number): [T, number];
descendant<T>(matcher: (blot: Blot) => boolean, index: number): [T, number];
descendants<T>(type: {
new (): T;
}, index: number, length: number): T[];
descendants<T>(matcher: (blot: Blot) => boolean, index: number, length: number): T[];
insertBefore(child: Blot, refNode?: Blot): void;
moveChildren(parent: Parent, refNode?: Blot): void;
path(index: number, inclusive?: boolean): [Blot, number][];
removeChild(child: Blot): void;
unwrap(): void;
}
export interface Formattable extends Blot {
format(name: string, value: any): void;
formats(): {
[index: string]: any;
};
}
export interface Leaf extends Blot {
index(node: Node, offset: number): number;
position(index: number, inclusive: boolean): [Node, number];
value(): any;
}

View File

@@ -0,0 +1,40 @@
import { Blot, Parent } from './blot';
import LinkedList from '../../collection/linked-list';
import ShadowBlot from './shadow';
declare class ContainerBlot extends ShadowBlot implements Parent {
static defaultChild: string;
static allowedChildren: any[];
children: LinkedList<Blot>;
domNode: HTMLElement;
constructor(domNode: Node);
appendChild(other: Blot): void;
attach(): void;
build(): void;
deleteAt(index: number, length: number): void;
descendant(criteria: {
new (): Blot;
}, index: number): [Blot | null, number];
descendant(criteria: (blot: Blot) => boolean, index: number): [Blot | null, number];
descendants(criteria: {
new (): Blot;
}, index: number, length: number): Blot[];
descendants(criteria: (blot: Blot) => boolean, index: number, length: number): Blot[];
detach(): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): void;
insertBefore(childBlot: Blot, refBlot?: Blot): void;
length(): number;
moveChildren(targetParent: Parent, refNode?: Blot): void;
optimize(context: {
[key: string]: any;
}): void;
path(index: number, inclusive?: boolean): [Blot, number][];
removeChild(child: Blot): void;
replace(target: Blot): void;
split(index: number, force?: boolean): Blot;
unwrap(): void;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
}
export default ContainerBlot;

View File

@@ -0,0 +1,18 @@
import AttributorStore from '../../attributor/store';
import { Blot, Parent, Formattable } from './blot';
import ContainerBlot from './container';
declare class FormatBlot extends ContainerBlot implements Formattable {
protected attributes: AttributorStore;
static formats(domNode: HTMLElement): any;
constructor(domNode: Node);
format(name: string, value: any): void;
formats(): {
[index: string]: any;
};
replaceWith(name: string | Blot, value?: any): Blot;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
wrap(name: string | Parent, value?: any): Parent;
}
export default FormatBlot;

View File

@@ -0,0 +1,11 @@
import { Leaf } from './blot';
import ShadowBlot from './shadow';
import * as Registry from '../../registry';
declare class LeafBlot extends ShadowBlot implements Leaf {
static scope: Registry.Scope;
static value(domNode: Node): any;
index(node: Node, offset: number): number;
position(index: number, inclusive?: boolean): [Node, number];
value(): any;
}
export default LeafBlot;

View File

@@ -0,0 +1,41 @@
import { Blot, Parent } from './blot';
import LinkedList from '../../collection/linked-list';
import ShadowBlot from './shadow';
import * as Registry from '../../registry';
declare class ParentBlot extends ShadowBlot implements Parent {
static defaultChild: Registry.BlotConstructor | null;
static allowedChildren: Registry.BlotConstructor[] | null;
children: LinkedList<Blot>;
domNode: HTMLElement;
constructor(domNode: Node);
appendChild(other: Blot): void;
attach(): void;
build(): void;
deleteAt(index: number, length: number): number;
descendant(criteria: {
new (): Blot;
}, index: number): [Blot | null, number];
descendant(criteria: (blot: Blot) => boolean, index: number): [Blot | null, number];
descendants(criteria: {
new (): Blot;
}, index: number, length: number): Blot[];
descendants(criteria: (blot: Blot) => boolean, index: number, length: number): Blot[];
detach(): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): number;
insertBefore(childBlot: Blot, refBlot?: Blot | null): void;
length(): number;
moveChildren(targetParent: Parent, refNode?: Blot): void;
optimize(context: {
[key: string]: any;
}): void;
path(index: number, inclusive?: boolean): [Blot, number][];
removeChild(child: Blot): void;
replaceWith(name: string | Blot, value?: any): Blot;
split(index: number, force?: boolean): Blot | null;
unwrap(): void;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
}
export default ParentBlot;

View File

@@ -0,0 +1,38 @@
import { Blot, Parent } from './blot';
import * as Registry from '../../registry';
declare class ShadowBlot implements Blot {
domNode: Node;
static blotName: string;
static className: string;
static scope: Registry.Scope;
static tagName: string;
prev: Blot;
next: Blot;
parent: Parent;
scroll: Parent;
readonly statics: any;
static create(value: any): Node;
constructor(domNode: Node);
attach(): void;
clone(): Blot;
detach(): void;
deleteAt(index: number, length: number): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): void;
insertInto(parentBlot: Parent, refBlot?: Blot | null): void;
isolate(index: number, length: number): Blot;
length(): number;
offset(root?: Blot): number;
optimize(context: {
[key: string]: any;
}): void;
remove(): void;
replace(target: Blot): void;
replaceWith(name: string | Blot, value?: any): Blot;
split(index: number, force?: boolean): Blot;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
wrap(name: string | Parent, value?: any): Parent;
}
export default ShadowBlot;

15
node_modules/parchment/dist/src/blot/block.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import FormatBlot from './abstract/format';
import * as Registry from '../registry';
declare class BlockBlot extends FormatBlot {
static blotName: string;
static scope: Registry.Scope;
static tagName: string;
static formats(domNode: HTMLElement): any;
format(name: string, value: any): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): void;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
}
export default BlockBlot;

11
node_modules/parchment/dist/src/blot/embed.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import { Formattable } from './abstract/blot';
import LeafBlot from './abstract/leaf';
declare class EmbedBlot extends LeafBlot implements Formattable {
static formats(domNode: HTMLElement): any;
format(name: string, value: any): void;
formatAt(index: number, length: number, name: string, value: any): void;
formats(): {
[index: string]: any;
};
}
export default EmbedBlot;

14
node_modules/parchment/dist/src/blot/inline.d.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import FormatBlot from './abstract/format';
import * as Registry from '../registry';
declare class InlineBlot extends FormatBlot {
static blotName: string;
static scope: Registry.Scope;
static tagName: string;
static formats(domNode: HTMLElement): any;
format(name: string, value: any): void;
formatAt(index: number, length: number, name: string, value: any): void;
optimize(context: {
[key: string]: any;
}): void;
}
export default InlineBlot;

24
node_modules/parchment/dist/src/blot/scroll.d.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import ContainerBlot from './abstract/container';
import * as Registry from '../registry';
declare class ScrollBlot extends ContainerBlot {
static blotName: string;
static defaultChild: string;
static scope: Registry.Scope;
static tagName: string;
observer: MutationObserver;
constructor(node: HTMLDivElement);
detach(): void;
deleteAt(index: number, length: number): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): void;
optimize(context: {
[key: string]: any;
}): void;
optimize(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
update(mutations?: MutationRecord[], context?: {
[key: string]: any;
}): void;
}
export default ScrollBlot;

26
node_modules/parchment/dist/src/blot/text.d.ts generated vendored Normal file
View File

@@ -0,0 +1,26 @@
import { Blot, Leaf } from './abstract/blot';
import LeafBlot from './abstract/leaf';
import * as Registry from '../registry';
declare class TextBlot extends LeafBlot implements Leaf {
static blotName: string;
static scope: Registry.Scope;
domNode: Text;
protected text: string;
static create(value: string): Text;
static value(domNode: Text): string;
constructor(node: Node);
deleteAt(index: number, length: number): void;
index(node: Node, offset: number): number;
insertAt(index: number, value: string, def?: any): void;
length(): number;
optimize(context: {
[key: string]: any;
}): void;
position(index: number, inclusive?: boolean): [Node, number];
split(index: number, force?: boolean): Blot;
update(mutations: MutationRecord[], context: {
[key: string]: any;
}): void;
value(): string;
}
export default TextBlot;

View File

@@ -0,0 +1,19 @@
import LinkedNode from './linked-node';
declare class LinkedList<T extends LinkedNode> {
head: T | null;
tail: T | null;
length: number;
constructor();
append(...nodes: T[]): void;
contains(node: T): boolean;
insertBefore(node: T | null, refNode: T | null): void;
offset(target: T): number;
remove(node: T): void;
iterator(curNode?: T | null): () => T | null;
find(index: number, inclusive?: boolean): [T | null, number];
forEach(callback: (cur: T) => void): void;
forEachAt(index: number, length: number, callback: (cur: T, offset: number, length: number) => void): void;
map(callback: (cur: T | null) => any): any[];
reduce<M>(callback: (memo: M, cur: T) => M, memo: M): M;
}
export default LinkedList;

View File

@@ -0,0 +1,6 @@
interface LinkedNode {
prev: LinkedNode | null;
next: LinkedNode | null;
length(): number;
}
export default LinkedNode;

35
node_modules/parchment/dist/src/parchment.d.ts generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import ContainerBlot from './blot/abstract/container';
import FormatBlot from './blot/abstract/format';
import LeafBlot from './blot/abstract/leaf';
import ScrollBlot from './blot/scroll';
import InlineBlot from './blot/inline';
import BlockBlot from './blot/block';
import EmbedBlot from './blot/embed';
import TextBlot from './blot/text';
import Attributor from './attributor/attributor';
import ClassAttributor from './attributor/class';
import StyleAttributor from './attributor/style';
import AttributorStore from './attributor/store';
import * as Registry from './registry';
declare let Parchment: {
Scope: typeof Registry.Scope;
create: typeof Registry.create;
find: typeof Registry.find;
query: typeof Registry.query;
register: typeof Registry.register;
Container: typeof ContainerBlot;
Format: typeof FormatBlot;
Leaf: typeof LeafBlot;
Embed: typeof EmbedBlot;
Scroll: typeof ScrollBlot;
Block: typeof BlockBlot;
Inline: typeof InlineBlot;
Text: typeof TextBlot;
Attributor: {
Attribute: typeof Attributor;
Class: typeof ClassAttributor;
Style: typeof StyleAttributor;
Store: typeof AttributorStore;
};
};
export default Parchment;

31
node_modules/parchment/dist/src/registry.d.ts generated vendored Normal file
View File

@@ -0,0 +1,31 @@
import Attributor from './attributor/attributor';
import { Blot } from './blot/abstract/blot';
export interface BlotConstructor {
blotName: string;
new (node: Node, value?: any): Blot;
create(value?: any): Node;
}
export declare class ParchmentError extends Error {
message: string;
name: string;
stack: string;
constructor(message: string);
}
export declare const DATA_KEY = "__blot";
export declare enum Scope {
TYPE = 3,
LEVEL = 12,
ATTRIBUTE = 13,
BLOT = 14,
INLINE = 7,
BLOCK = 11,
BLOCK_BLOT = 10,
INLINE_BLOT = 6,
BLOCK_ATTRIBUTE = 9,
INLINE_ATTRIBUTE = 5,
ANY = 15,
}
export declare function create(input: Node | string | Scope, value?: any): Blot;
export declare function find(node: Node | null, bubble?: boolean): Blot | null;
export declare function query(query: string | Node | Scope, scope?: Scope): Attributor | BlotConstructor | null;
export declare function register(...Definitions: any[]): any;

44
node_modules/parchment/package.json generated vendored Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "parchment",
"version": "1.1.4",
"description": "A document model for rich text editors",
"author": "Jason Chen <jhchen7@gmail.com>",
"homepage": "http://quilljs.com/docs/parchment",
"main": "dist/parchment.js",
"files": [
"tsconfig.json",
"dist",
"src"
],
"types": "dist/src/parchment.d.ts",
"devDependencies": {
"babel-core": "^6.26.0",
"istanbul": "~0.4.5",
"jasmine-core": "^2.9.1",
"karma": "^2.0.0",
"karma-babel-preprocessor": "^7.0.0",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage": "^1.1.1",
"karma-jasmine": "^1.1.1",
"karma-sauce-launcher": "^1.2.0",
"karma-webpack": "^2.0.9",
"ts-loader": "^3.4.0",
"typescript": "^2.7.1",
"webpack": "^3.10.0"
},
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "https://github.com/quilljs/parchment"
},
"scripts": {
"build": "webpack --config webpack.conf.js",
"prepublish": "npm run build",
"test": "karma start",
"test:server": "karma start --no-single-run",
"test:travis": "karma start --browsers saucelabs-chrome --reporters dots,saucelabs"
},
"bugs": {
"url": "https://github.com/quilljs/parchment/issues"
}
}

61
node_modules/parchment/src/attributor/attributor.ts generated vendored Normal file
View File

@@ -0,0 +1,61 @@
import * as Registry from '../registry';
export interface AttributorOptions {
scope?: Registry.Scope;
whitelist?: string[];
}
export default class Attributor {
attrName: string;
keyName: string;
scope: Registry.Scope;
whitelist: string[] | undefined;
static keys(node: HTMLElement): string[] {
return [].map.call(node.attributes, function(item: Attr) {
return item.name;
});
}
constructor(attrName: string, keyName: string, options: AttributorOptions = {}) {
this.attrName = attrName;
this.keyName = keyName;
let attributeBit = Registry.Scope.TYPE & Registry.Scope.ATTRIBUTE;
if (options.scope != null) {
// Ignore type bits, force attribute bit
this.scope = (options.scope & Registry.Scope.LEVEL) | attributeBit;
} else {
this.scope = Registry.Scope.ATTRIBUTE;
}
if (options.whitelist != null) this.whitelist = options.whitelist;
}
add(node: HTMLElement, value: string): boolean {
if (!this.canAdd(node, value)) return false;
node.setAttribute(this.keyName, value);
return true;
}
canAdd(node: HTMLElement, value: any): boolean {
let match = Registry.query(node, Registry.Scope.BLOT & (this.scope | Registry.Scope.TYPE));
if (match == null) return false;
if (this.whitelist == null) return true;
if (typeof value === 'string') {
return this.whitelist.indexOf(value.replace(/["']/g, '')) > -1;
} else {
return this.whitelist.indexOf(value) > -1;
}
}
remove(node: HTMLElement): void {
node.removeAttribute(this.keyName);
}
value(node: HTMLElement): string {
let value = node.getAttribute(this.keyName);
if (this.canAdd(node, value) && value) {
return value;
}
return '';
}
}

44
node_modules/parchment/src/attributor/class.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
import Attributor from './attributor';
function match(node: HTMLElement, prefix: string): string[] {
let className = node.getAttribute('class') || '';
return className.split(/\s+/).filter(function(name) {
return name.indexOf(`${prefix}-`) === 0;
});
}
class ClassAttributor extends Attributor {
static keys(node: HTMLElement): string[] {
return (node.getAttribute('class') || '').split(/\s+/).map(function(name) {
return name
.split('-')
.slice(0, -1)
.join('-');
});
}
add(node: HTMLElement, value: string): boolean {
if (!this.canAdd(node, value)) return false;
this.remove(node);
node.classList.add(`${this.keyName}-${value}`);
return true;
}
remove(node: HTMLElement): void {
let matches = match(node, this.keyName);
matches.forEach(function(name) {
node.classList.remove(name);
});
if (node.classList.length === 0) {
node.removeAttribute('class');
}
}
value(node: HTMLElement): string {
let result = match(node, this.keyName)[0] || '';
let value = result.slice(this.keyName.length + 1); // +1 for hyphen
return this.canAdd(node, value) ? value : '';
}
}
export default ClassAttributor;

73
node_modules/parchment/src/attributor/store.ts generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import Attributor from './attributor';
import ClassAttributor from './class';
import StyleAttributor from './style';
import { Formattable } from '../blot/abstract/blot';
import * as Registry from '../registry';
class AttributorStore {
private attributes: { [key: string]: Attributor } = {};
private domNode: HTMLElement;
constructor(domNode: HTMLElement) {
this.domNode = domNode;
this.build();
}
attribute(attribute: Attributor, value: any): void {
// verb
if (value) {
if (attribute.add(this.domNode, value)) {
if (attribute.value(this.domNode) != null) {
this.attributes[attribute.attrName] = attribute;
} else {
delete this.attributes[attribute.attrName];
}
}
} else {
attribute.remove(this.domNode);
delete this.attributes[attribute.attrName];
}
}
build(): void {
this.attributes = {};
let attributes = Attributor.keys(this.domNode);
let classes = ClassAttributor.keys(this.domNode);
let styles = StyleAttributor.keys(this.domNode);
attributes
.concat(classes)
.concat(styles)
.forEach(name => {
let attr = Registry.query(name, Registry.Scope.ATTRIBUTE);
if (attr instanceof Attributor) {
this.attributes[attr.attrName] = attr;
}
});
}
copy(target: Formattable): void {
Object.keys(this.attributes).forEach(key => {
let value = this.attributes[key].value(this.domNode);
target.format(key, value);
});
}
move(target: Formattable): void {
this.copy(target);
Object.keys(this.attributes).forEach(key => {
this.attributes[key].remove(this.domNode);
});
this.attributes = {};
}
values(): { [key: string]: any } {
return Object.keys(
this.attributes,
).reduce((attributes: { [key: string]: any }, name: string) => {
attributes[name] = this.attributes[name].value(this.domNode);
return attributes;
}, {});
}
}
export default AttributorStore;

44
node_modules/parchment/src/attributor/style.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
import Attributor from './attributor';
function camelize(name: string): string {
let parts = name.split('-');
let rest = parts
.slice(1)
.map(function(part: string) {
return part[0].toUpperCase() + part.slice(1);
})
.join('');
return parts[0] + rest;
}
class StyleAttributor extends Attributor {
static keys(node: Element): string[] {
return (node.getAttribute('style') || '').split(';').map(function(value) {
let arr = value.split(':');
return arr[0].trim();
});
}
add(node: HTMLElement, value: string): boolean {
if (!this.canAdd(node, value)) return false;
// @ts-ignore
node.style[camelize(this.keyName)] = value;
return true;
}
remove(node: HTMLElement): void {
// @ts-ignore
node.style[camelize(this.keyName)] = '';
if (!node.getAttribute('style')) {
node.removeAttribute('style');
}
}
value(node: HTMLElement): string {
// @ts-ignore
let value = node.style[camelize(this.keyName)];
return this.canAdd(node, value) ? value : '';
}
}
export default StyleAttributor;

58
node_modules/parchment/src/blot/abstract/blot.ts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
import LinkedList from '../../collection/linked-list';
import LinkedNode from '../../collection/linked-node';
export interface Blot extends LinkedNode {
scroll: Parent;
parent: Parent;
prev: Blot;
next: Blot;
domNode: Node;
attach(): void;
clone(): Blot;
detach(): void;
insertInto(parentBlot: Parent, refBlot?: Blot): void;
isolate(index: number, length: number): Blot;
offset(root?: Blot): number;
remove(): void;
replace(target: Blot): void;
replaceWith(name: string, value: any): Blot;
replaceWith(replacement: Blot): Blot;
split(index: number, force?: boolean): Blot;
wrap(name: string, value: any): Parent;
wrap(wrapper: Parent): Parent;
deleteAt(index: number, length: number): void;
formatAt(index: number, length: number, name: string, value: any): void;
insertAt(index: number, value: string, def?: any): void;
optimize(context: { [key: string]: any }): void;
optimize(mutations: MutationRecord[], context: { [key: string]: any }): void;
update(mutations: MutationRecord[], context: { [key: string]: any }): void;
}
export interface Parent extends Blot {
children: LinkedList<Blot>;
domNode: HTMLElement;
appendChild(child: Blot): void;
descendant<T>(type: { new (): T }, index: number): [T, number];
descendant<T>(matcher: (blot: Blot) => boolean, index: number): [T, number];
descendants<T>(type: { new (): T }, index: number, length: number): T[];
descendants<T>(matcher: (blot: Blot) => boolean, index: number, length: number): T[];
insertBefore(child: Blot, refNode?: Blot): void;
moveChildren(parent: Parent, refNode?: Blot): void;
path(index: number, inclusive?: boolean): [Blot, number][];
removeChild(child: Blot): void;
unwrap(): void;
}
export interface Formattable extends Blot {
format(name: string, value: any): void;
formats(): { [index: string]: any };
}
export interface Leaf extends Blot {
index(node: Node, offset: number): number;
position(index: number, inclusive: boolean): [Node, number];
value(): any;
}

268
node_modules/parchment/src/blot/abstract/container.ts generated vendored Normal file
View File

@@ -0,0 +1,268 @@
import { Blot, Parent, Leaf } from './blot';
import LinkedList from '../../collection/linked-list';
import ShadowBlot from './shadow';
import * as Registry from '../../registry';
class ContainerBlot extends ShadowBlot implements Parent {
static defaultChild: string;
static allowedChildren: any[];
children!: LinkedList<Blot>;
domNode!: HTMLElement;
constructor(domNode: Node) {
super(domNode);
this.build();
}
appendChild(other: Blot): void {
this.insertBefore(other);
}
attach(): void {
super.attach();
this.children.forEach(child => {
child.attach();
});
}
build(): void {
this.children = new LinkedList<Blot>();
// Need to be reversed for if DOM nodes already in order
[].slice
.call(this.domNode.childNodes)
.reverse()
.forEach((node: Node) => {
try {
let child = makeBlot(node);
this.insertBefore(child, this.children.head || undefined);
} catch (err) {
if (err instanceof Registry.ParchmentError) return;
else throw err;
}
});
}
deleteAt(index: number, length: number): void {
if (index === 0 && length === this.length()) {
return this.remove();
}
this.children.forEachAt(index, length, function(child, offset, length) {
child.deleteAt(offset, length);
});
}
descendant(criteria: { new (): Blot }, index: number): [Blot | null, number];
descendant(criteria: (blot: Blot) => boolean, index: number): [Blot | null, number];
descendant(criteria: any, index: number): [Blot | null, number] {
let [child, offset] = this.children.find(index);
if (
(criteria.blotName == null && criteria(child)) ||
(criteria.blotName != null && child instanceof criteria)
) {
return [<any>child, offset];
} else if (child instanceof ContainerBlot) {
return child.descendant(criteria, offset);
} else {
return [null, -1];
}
}
descendants(criteria: { new (): Blot }, index: number, length: number): Blot[];
descendants(criteria: (blot: Blot) => boolean, index: number, length: number): Blot[];
descendants(criteria: any, index: number = 0, length: number = Number.MAX_VALUE): Blot[] {
let descendants: Blot[] = [];
let lengthLeft = length;
this.children.forEachAt(index, length, function(child: Blot, index: number, length: number) {
if (
(criteria.blotName == null && criteria(child)) ||
(criteria.blotName != null && child instanceof criteria)
) {
descendants.push(child);
}
if (child instanceof ContainerBlot) {
descendants = descendants.concat(child.descendants(criteria, index, lengthLeft));
}
lengthLeft -= length;
});
return descendants;
}
detach(): void {
this.children.forEach(function(child) {
child.detach();
});
super.detach();
}
formatAt(index: number, length: number, name: string, value: any): void {
this.children.forEachAt(index, length, function(child, offset, length) {
child.formatAt(offset, length, name, value);
});
}
insertAt(index: number, value: string, def?: any): void {
let [child, offset] = this.children.find(index);
if (child) {
child.insertAt(offset, value, def);
} else {
let blot = def == null ? Registry.create('text', value) : Registry.create(value, def);
this.appendChild(blot);
}
}
insertBefore(childBlot: Blot, refBlot?: Blot): void {
if (
this.statics.allowedChildren != null &&
!this.statics.allowedChildren.some(function(child: Registry.BlotConstructor) {
return childBlot instanceof child;
})
) {
throw new Registry.ParchmentError(
`Cannot insert ${(<ShadowBlot>childBlot).statics.blotName} into ${this.statics.blotName}`,
);
}
childBlot.insertInto(this, refBlot);
}
length(): number {
return this.children.reduce(function(memo, child) {
return memo + child.length();
}, 0);
}
moveChildren(targetParent: Parent, refNode?: Blot): void {
this.children.forEach(function(child) {
targetParent.insertBefore(child, refNode);
});
}
optimize(context: { [key: string]: any }) {
super.optimize(context);
if (this.children.length === 0) {
if (this.statics.defaultChild != null) {
let child = Registry.create(this.statics.defaultChild);
this.appendChild(child);
child.optimize(context);
} else {
this.remove();
}
}
}
path(index: number, inclusive: boolean = false): [Blot, number][] {
let [child, offset] = this.children.find(index, inclusive);
let position: [Blot, number][] = [[this, index]];
if (child instanceof ContainerBlot) {
return position.concat(child.path(offset, inclusive));
} else if (child != null) {
position.push([child, offset]);
}
return position;
}
removeChild(child: Blot): void {
this.children.remove(child);
}
replace(target: Blot): void {
if (target instanceof ContainerBlot) {
target.moveChildren(this);
}
super.replace(target);
}
split(index: number, force: boolean = false): Blot {
if (!force) {
if (index === 0) return this;
if (index === this.length()) return this.next;
}
let after = <ContainerBlot>this.clone();
this.parent.insertBefore(after, this.next);
this.children.forEachAt(index, this.length(), function(child, offset, length) {
child = child.split(offset, force);
after.appendChild(child);
});
return after;
}
unwrap(): void {
this.moveChildren(this.parent, this.next);
this.remove();
}
update(mutations: MutationRecord[], context: { [key: string]: any }): void {
let addedNodes: Node[] = [];
let removedNodes: Node[] = [];
mutations.forEach(mutation => {
if (mutation.target === this.domNode && mutation.type === 'childList') {
addedNodes.push.apply(addedNodes, mutation.addedNodes);
removedNodes.push.apply(removedNodes, mutation.removedNodes);
}
});
removedNodes.forEach((node: Node) => {
// Check node has actually been removed
// One exception is Chrome does not immediately remove IFRAMEs
// from DOM but MutationRecord is correct in its reported removal
if (
node.parentNode != null &&
// @ts-ignore
node.tagName !== 'IFRAME' &&
document.body.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINED_BY
) {
return;
}
let blot = Registry.find(node);
if (blot == null) return;
if (blot.domNode.parentNode == null || blot.domNode.parentNode === this.domNode) {
blot.detach();
}
});
addedNodes
.filter(node => {
return node.parentNode == this.domNode;
})
.sort(function(a, b) {
if (a === b) return 0;
if (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) {
return 1;
}
return -1;
})
.forEach(node => {
let refBlot: Blot | null = null;
if (node.nextSibling != null) {
refBlot = Registry.find(node.nextSibling);
}
let blot = makeBlot(node);
if (blot.next != refBlot || blot.next == null) {
if (blot.parent != null) {
blot.parent.removeChild(this);
}
this.insertBefore(blot, refBlot || undefined);
}
});
}
}
function makeBlot(node: Node): Blot {
let blot = Registry.find(node);
if (blot == null) {
try {
blot = Registry.create(node);
} catch (e) {
blot = Registry.create(Registry.Scope.INLINE);
[].slice.call(node.childNodes).forEach(function(child: Node) {
// @ts-ignore
blot.domNode.appendChild(child);
});
if (node.parentNode) {
node.parentNode.replaceChild(blot.domNode, node);
}
blot.attach();
}
}
return blot;
}
export default ContainerBlot;

71
node_modules/parchment/src/blot/abstract/format.ts generated vendored Normal file
View File

@@ -0,0 +1,71 @@
import Attributor from '../../attributor/attributor';
import AttributorStore from '../../attributor/store';
import { Blot, Parent, Formattable } from './blot';
import ContainerBlot from './container';
import ShadowBlot from './shadow';
import * as Registry from '../../registry';
class FormatBlot extends ContainerBlot implements Formattable {
protected attributes: AttributorStore;
static formats(domNode: HTMLElement): any {
if (typeof this.tagName === 'string') {
return true;
} else if (Array.isArray(this.tagName)) {
return domNode.tagName.toLowerCase();
}
return undefined;
}
constructor(domNode: Node) {
super(domNode);
this.attributes = new AttributorStore(this.domNode);
}
format(name: string, value: any): void {
let format = Registry.query(name);
if (format instanceof Attributor) {
this.attributes.attribute(format, value);
} else if (value) {
if (format != null && (name !== this.statics.blotName || this.formats()[name] !== value)) {
this.replaceWith(name, value);
}
}
}
formats(): { [index: string]: any } {
let formats = this.attributes.values();
let format = this.statics.formats(this.domNode);
if (format != null) {
formats[this.statics.blotName] = format;
}
return formats;
}
replaceWith(name: string | Blot, value?: any): Blot {
let replacement = <FormatBlot>super.replaceWith(name, value);
this.attributes.copy(replacement);
return replacement;
}
update(mutations: MutationRecord[], context: { [key: string]: any }): void {
super.update(mutations, context);
if (
mutations.some(mutation => {
return mutation.target === this.domNode && mutation.type === 'attributes';
})
) {
this.attributes.build();
}
}
wrap(name: string | Parent, value?: any): Parent {
let wrapper = super.wrap(name, value);
if (wrapper instanceof FormatBlot && wrapper.statics.scope === this.statics.scope) {
this.attributes.move(wrapper);
}
return wrapper;
}
}
export default FormatBlot;

33
node_modules/parchment/src/blot/abstract/leaf.ts generated vendored Normal file
View File

@@ -0,0 +1,33 @@
import { Formattable, Leaf } from './blot';
import ShadowBlot from './shadow';
import * as Registry from '../../registry';
class LeafBlot extends ShadowBlot implements Leaf {
static scope = Registry.Scope.INLINE_BLOT;
static value(domNode: Node): any {
return true;
}
index(node: Node, offset: number): number {
if (
this.domNode === node ||
this.domNode.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINED_BY
) {
return Math.min(offset, 1);
}
return -1;
}
position(index: number, inclusive?: boolean): [Node, number] {
let offset = [].indexOf.call(this.parent.domNode.childNodes, this.domNode);
if (index > 0) offset += 1;
return [this.parent.domNode, offset];
}
value(): any {
return { [this.statics.blotName]: this.statics.value(this.domNode) || true };
}
}
export default LeafBlot;

174
node_modules/parchment/src/blot/abstract/shadow.ts generated vendored Normal file
View File

@@ -0,0 +1,174 @@
import { Blot, Parent, Formattable } from './blot';
import * as Registry from '../../registry';
class ShadowBlot implements Blot {
static blotName = 'abstract';
static className: string;
static scope: Registry.Scope;
static tagName: string;
// @ts-ignore
prev: Blot;
// @ts-ignore
next: Blot;
// @ts-ignore
parent: Parent;
// @ts-ignore
scroll: Parent;
// Hack for accessing inherited static methods
get statics(): any {
return this.constructor;
}
static create(value: any): Node {
if (this.tagName == null) {
throw new Registry.ParchmentError('Blot definition missing tagName');
}
let node;
if (Array.isArray(this.tagName)) {
if (typeof value === 'string') {
value = value.toUpperCase();
if (parseInt(value).toString() === value) {
value = parseInt(value);
}
}
if (typeof value === 'number') {
node = document.createElement(this.tagName[value - 1]);
} else if (this.tagName.indexOf(value) > -1) {
node = document.createElement(value);
} else {
node = document.createElement(this.tagName[0]);
}
} else {
node = document.createElement(this.tagName);
}
if (this.className) {
node.classList.add(this.className);
}
return node;
}
constructor(public domNode: Node) {
// @ts-ignore
this.domNode[Registry.DATA_KEY] = { blot: this };
}
attach(): void {
if (this.parent != null) {
this.scroll = this.parent.scroll;
}
}
clone(): Blot {
let domNode = this.domNode.cloneNode(false);
return Registry.create(domNode);
}
detach() {
if (this.parent != null) this.parent.removeChild(this);
// @ts-ignore
delete this.domNode[Registry.DATA_KEY];
}
deleteAt(index: number, length: number): void {
let blot = this.isolate(index, length);
blot.remove();
}
formatAt(index: number, length: number, name: string, value: any): void {
let blot = this.isolate(index, length);
if (Registry.query(name, Registry.Scope.BLOT) != null && value) {
blot.wrap(name, value);
} else if (Registry.query(name, Registry.Scope.ATTRIBUTE) != null) {
let parent = <Parent & Formattable>Registry.create(this.statics.scope);
blot.wrap(parent);
parent.format(name, value);
}
}
insertAt(index: number, value: string, def?: any): void {
let blot = def == null ? Registry.create('text', value) : Registry.create(value, def);
let ref = this.split(index);
this.parent.insertBefore(blot, ref);
}
insertInto(parentBlot: Parent, refBlot: Blot | null = null): void {
if (this.parent != null) {
this.parent.children.remove(this);
}
let refDomNode: Node | null = null;
parentBlot.children.insertBefore(this, refBlot);
if (refBlot != null) {
refDomNode = refBlot.domNode;
}
if (this.domNode.parentNode != parentBlot.domNode ||
this.domNode.nextSibling != refDomNode) {
parentBlot.domNode.insertBefore(this.domNode, refDomNode);
}
this.parent = parentBlot;
this.attach();
}
isolate(index: number, length: number): Blot {
let target = this.split(index);
target.split(length);
return target;
}
length(): number {
return 1;
}
offset(root: Blot = this.parent): number {
if (this.parent == null || this == root) return 0;
return this.parent.children.offset(this) + this.parent.offset(root);
}
optimize(context: { [key: string]: any }): void {
// TODO clean up once we use WeakMap
// @ts-ignore
if (this.domNode[Registry.DATA_KEY] != null) {
// @ts-ignore
delete this.domNode[Registry.DATA_KEY].mutations;
}
}
remove(): void {
if (this.domNode.parentNode != null) {
this.domNode.parentNode.removeChild(this.domNode);
}
this.detach();
}
replace(target: Blot): void {
if (target.parent == null) return;
target.parent.insertBefore(this, target.next);
target.remove();
}
replaceWith(name: string | Blot, value?: any): Blot {
let replacement = typeof name === 'string' ? Registry.create(name, value) : name;
replacement.replace(this);
return replacement;
}
split(index: number, force?: boolean): Blot {
return index === 0 ? this : this.next;
}
update(mutations: MutationRecord[], context: { [key: string]: any }): void {
// Nothing to do by default
}
wrap(name: string | Parent, value?: any): Parent {
let wrapper = typeof name === 'string' ? <Parent>Registry.create(name, value) : name;
if (this.parent != null) {
this.parent.insertBefore(wrapper, this.next);
}
wrapper.appendChild(this);
return wrapper;
}
}
export default ShadowBlot;

53
node_modules/parchment/src/blot/block.ts generated vendored Normal file
View File

@@ -0,0 +1,53 @@
import FormatBlot from './abstract/format';
import * as Registry from '../registry';
class BlockBlot extends FormatBlot {
static blotName = 'block';
static scope = Registry.Scope.BLOCK_BLOT;
static tagName = 'P';
static formats(domNode: HTMLElement): any {
let tagName = (<any>Registry.query(BlockBlot.blotName)).tagName;
if (domNode.tagName === tagName) return undefined;
return super.formats(domNode);
}
format(name: string, value: any) {
if (Registry.query(name, Registry.Scope.BLOCK) == null) {
return;
} else if (name === this.statics.blotName && !value) {
this.replaceWith(BlockBlot.blotName);
} else {
super.format(name, value);
}
}
formatAt(index: number, length: number, name: string, value: any): void {
if (Registry.query(name, Registry.Scope.BLOCK) != null) {
this.format(name, value);
} else {
super.formatAt(index, length, name, value);
}
}
insertAt(index: number, value: string, def?: any): void {
if (def == null || Registry.query(value, Registry.Scope.INLINE) != null) {
// Insert text or inline
super.insertAt(index, value, def);
} else {
let after = this.split(index);
let blot = Registry.create(value, def);
after.parent.insertBefore(blot, after);
}
}
update(mutations: MutationRecord[], context: { [key: string]: any }): void {
if (navigator.userAgent.match(/Trident/)) {
this.build();
} else {
super.update(mutations, context);
}
}
}
export default BlockBlot;

29
node_modules/parchment/src/blot/embed.ts generated vendored Normal file
View File

@@ -0,0 +1,29 @@
import { Formattable } from './abstract/blot';
import LeafBlot from './abstract/leaf';
class EmbedBlot extends LeafBlot implements Formattable {
static formats(domNode: HTMLElement): any {
return undefined;
}
format(name: string, value: any): void {
// super.formatAt wraps, which is what we want in general,
// but this allows subclasses to overwrite for formats
// that just apply to particular embeds
super.formatAt(0, this.length(), name, value);
}
formatAt(index: number, length: number, name: string, value: any): void {
if (index === 0 && length === this.length()) {
this.format(name, value);
} else {
super.formatAt(index, length, name, value);
}
}
formats(): { [index: string]: any } {
return this.statics.formats(this.domNode);
}
}
export default EmbedBlot;

64
node_modules/parchment/src/blot/inline.ts generated vendored Normal file
View File

@@ -0,0 +1,64 @@
import FormatBlot from './abstract/format';
import LeafBlot from './abstract/leaf';
import ShadowBlot from './abstract/shadow';
import * as Registry from '../registry';
// Shallow object comparison
function isEqual(obj1: Object, obj2: Object): boolean {
if (Object.keys(obj1).length !== Object.keys(obj2).length) return false;
// @ts-ignore
for (let prop in obj1) {
// @ts-ignore
if (obj1[prop] !== obj2[prop]) return false;
}
return true;
}
class InlineBlot extends FormatBlot {
static blotName = 'inline';
static scope = Registry.Scope.INLINE_BLOT;
static tagName = 'SPAN';
static formats(domNode: HTMLElement): any {
if (domNode.tagName === InlineBlot.tagName) return undefined;
return super.formats(domNode);
}
format(name: string, value: any) {
if (name === this.statics.blotName && !value) {
this.children.forEach(child => {
if (!(child instanceof FormatBlot)) {
child = child.wrap(InlineBlot.blotName, true);
}
this.attributes.copy(<FormatBlot>child);
});
this.unwrap();
} else {
super.format(name, value);
}
}
formatAt(index: number, length: number, name: string, value: any): void {
if (this.formats()[name] != null || Registry.query(name, Registry.Scope.ATTRIBUTE)) {
let blot = <InlineBlot>this.isolate(index, length);
blot.format(name, value);
} else {
super.formatAt(index, length, name, value);
}
}
optimize(context: { [key: string]: any }): void {
super.optimize(context);
let formats = this.formats();
if (Object.keys(formats).length === 0) {
return this.unwrap(); // unformatted span
}
let next = this.next;
if (next instanceof InlineBlot && next.prev === this && isEqual(formats, next.formats())) {
next.moveChildren(this);
next.remove();
}
}
}
export default InlineBlot;

166
node_modules/parchment/src/blot/scroll.ts generated vendored Normal file
View File

@@ -0,0 +1,166 @@
import { Blot } from './abstract/blot';
import ContainerBlot from './abstract/container';
import LinkedList from '../collection/linked-list';
import * as Registry from '../registry';
const OBSERVER_CONFIG = {
attributes: true,
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true,
};
const MAX_OPTIMIZE_ITERATIONS = 100;
class ScrollBlot extends ContainerBlot {
static blotName = 'scroll';
static defaultChild = 'block';
static scope = Registry.Scope.BLOCK_BLOT;
static tagName = 'DIV';
observer: MutationObserver;
constructor(node: HTMLDivElement) {
super(node);
this.scroll = this;
this.observer = new MutationObserver((mutations: MutationRecord[]) => {
this.update(mutations);
});
this.observer.observe(this.domNode, OBSERVER_CONFIG);
this.attach();
}
detach() {
super.detach();
this.observer.disconnect();
}
deleteAt(index: number, length: number): void {
this.update();
if (index === 0 && length === this.length()) {
this.children.forEach(function(child) {
child.remove();
});
} else {
super.deleteAt(index, length);
}
}
formatAt(index: number, length: number, name: string, value: any): void {
this.update();
super.formatAt(index, length, name, value);
}
insertAt(index: number, value: string, def?: any): void {
this.update();
super.insertAt(index, value, def);
}
optimize(context: { [key: string]: any }): void;
optimize(mutations: MutationRecord[], context: { [key: string]: any }): void;
optimize(mutations: any = [], context: any = {}): void {
super.optimize(context);
// We must modify mutations directly, cannot make copy and then modify
let records = [].slice.call(this.observer.takeRecords());
// Array.push currently seems to be implemented by a non-tail recursive function
// so we cannot just mutations.push.apply(mutations, this.observer.takeRecords());
while (records.length > 0) mutations.push(records.pop());
// TODO use WeakMap
let mark = (blot: Blot | null, markParent: boolean = true) => {
if (blot == null || blot === this) return;
if (blot.domNode.parentNode == null) return;
// @ts-ignore
if (blot.domNode[Registry.DATA_KEY].mutations == null) {
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations = [];
}
if (markParent) mark(blot.parent);
};
let optimize = function(blot: Blot) {
// Post-order traversal
if (
// @ts-ignore
blot.domNode[Registry.DATA_KEY] == null ||
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations == null
) {
return;
}
if (blot instanceof ContainerBlot) {
blot.children.forEach(optimize);
}
blot.optimize(context);
};
let remaining = mutations;
for (let i = 0; remaining.length > 0; i += 1) {
if (i >= MAX_OPTIMIZE_ITERATIONS) {
throw new Error('[Parchment] Maximum optimize iterations reached');
}
remaining.forEach(function(mutation: MutationRecord) {
let blot = Registry.find(mutation.target, true);
if (blot == null) return;
if (blot.domNode === mutation.target) {
if (mutation.type === 'childList') {
mark(Registry.find(mutation.previousSibling, false));
[].forEach.call(mutation.addedNodes, function(node: Node) {
let child = Registry.find(node, false);
mark(child, false);
if (child instanceof ContainerBlot) {
child.children.forEach(function(grandChild: Blot) {
mark(grandChild, false);
});
}
});
} else if (mutation.type === 'attributes') {
mark(blot.prev);
}
}
mark(blot);
});
this.children.forEach(optimize);
remaining = [].slice.call(this.observer.takeRecords());
records = remaining.slice();
while (records.length > 0) mutations.push(records.pop());
}
}
update(mutations?: MutationRecord[], context: { [key: string]: any } = {}): void {
mutations = mutations || this.observer.takeRecords();
// TODO use WeakMap
mutations
.map(function(mutation: MutationRecord) {
let blot = Registry.find(mutation.target, true);
if (blot == null) return null;
// @ts-ignore
if (blot.domNode[Registry.DATA_KEY].mutations == null) {
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations = [mutation];
return blot;
} else {
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations.push(mutation);
return null;
}
})
.forEach((blot: Blot | null) => {
if (
blot == null ||
blot === this ||
//@ts-ignore
blot.domNode[Registry.DATA_KEY] == null
)
return;
// @ts-ignore
blot.update(blot.domNode[Registry.DATA_KEY].mutations || [], context);
});
// @ts-ignore
if (this.domNode[Registry.DATA_KEY].mutations != null) {
// @ts-ignore
super.update(this.domNode[Registry.DATA_KEY].mutations, context);
}
this.optimize(mutations, context);
}
}
export default ScrollBlot;

93
node_modules/parchment/src/blot/text.ts generated vendored Normal file
View File

@@ -0,0 +1,93 @@
import { Blot, Leaf } from './abstract/blot';
import LeafBlot from './abstract/leaf';
import * as Registry from '../registry';
class TextBlot extends LeafBlot implements Leaf {
static blotName = 'text';
static scope = Registry.Scope.INLINE_BLOT;
public domNode!: Text;
protected text: string;
static create(value: string): Text {
return document.createTextNode(value);
}
static value(domNode: Text): string {
let text = domNode.data;
// @ts-ignore
if (text['normalize']) text = text['normalize']();
return text;
}
constructor(node: Node) {
super(node);
this.text = this.statics.value(this.domNode);
}
deleteAt(index: number, length: number): void {
this.domNode.data = this.text = this.text.slice(0, index) + this.text.slice(index + length);
}
index(node: Node, offset: number): number {
if (this.domNode === node) {
return offset;
}
return -1;
}
insertAt(index: number, value: string, def?: any): void {
if (def == null) {
this.text = this.text.slice(0, index) + value + this.text.slice(index);
this.domNode.data = this.text;
} else {
super.insertAt(index, value, def);
}
}
length(): number {
return this.text.length;
}
optimize(context: { [key: string]: any }): void {
super.optimize(context);
this.text = this.statics.value(this.domNode);
if (this.text.length === 0) {
this.remove();
} else if (this.next instanceof TextBlot && this.next.prev === this) {
this.insertAt(this.length(), (<TextBlot>this.next).value());
this.next.remove();
}
}
position(index: number, inclusive: boolean = false): [Node, number] {
return [this.domNode, index];
}
split(index: number, force: boolean = false): Blot {
if (!force) {
if (index === 0) return this;
if (index === this.length()) return this.next;
}
let after = Registry.create(this.domNode.splitText(index));
this.parent.insertBefore(after, this.next);
this.text = this.statics.value(this.domNode);
return after;
}
update(mutations: MutationRecord[], context: { [key: string]: any }): void {
if (
mutations.some(mutation => {
return mutation.type === 'characterData' && mutation.target === this.domNode;
})
) {
this.text = this.statics.value(this.domNode);
}
}
value(): string {
return this.text;
}
}
export default TextBlot;

143
node_modules/parchment/src/collection/linked-list.ts generated vendored Normal file
View File

@@ -0,0 +1,143 @@
import LinkedNode from './linked-node';
class LinkedList<T extends LinkedNode> {
head: T | null;
tail: T | null;
length: number;
constructor() {
this.head = this.tail = null;
this.length = 0;
}
append(...nodes: T[]): void {
this.insertBefore(nodes[0], null);
if (nodes.length > 1) {
this.append.apply(this, nodes.slice(1));
}
}
contains(node: T): boolean {
let cur,
next = this.iterator();
while ((cur = next())) {
if (cur === node) return true;
}
return false;
}
insertBefore(node: T | null, refNode: T | null): void {
if (!node) return
node.next = refNode;
if (refNode != null) {
node.prev = refNode.prev;
if (refNode.prev != null) {
refNode.prev.next = node;
}
refNode.prev = node;
if (refNode === this.head) {
this.head = node;
}
} else if (this.tail != null) {
this.tail.next = node;
node.prev = this.tail;
this.tail = node;
} else {
node.prev = null;
this.head = this.tail = node;
}
this.length += 1;
}
offset(target: T): number {
let index = 0,
cur = this.head;
while (cur != null) {
if (cur === target) return index;
index += cur.length();
cur = <T>cur.next;
}
return -1;
}
remove(node: T): void {
if (!this.contains(node)) return;
if (node.prev != null) node.prev.next = node.next;
if (node.next != null) node.next.prev = node.prev;
if (node === this.head) this.head = <T>node.next;
if (node === this.tail) this.tail = <T>node.prev;
this.length -= 1;
}
iterator(curNode: T | null = this.head): () => T | null {
// TODO use yield when we can
return function(): T | null {
let ret = curNode;
if (curNode != null) curNode = <T>curNode.next;
return ret;
};
}
find(index: number, inclusive: boolean = false): [T | null, number] {
let cur,
next = this.iterator();
while ((cur = next())) {
let length = cur.length();
if (
index < length ||
(inclusive && index === length && (cur.next == null || cur.next.length() !== 0))
) {
return [cur, index];
}
index -= length;
}
return [null, 0];
}
forEach(callback: (cur: T) => void): void {
let cur,
next = this.iterator();
while ((cur = next())) {
callback(cur);
}
}
forEachAt(
index: number,
length: number,
callback: (cur: T, offset: number, length: number) => void,
): void {
if (length <= 0) return;
let [startNode, offset] = this.find(index);
let cur,
curIndex = index - offset,
next = this.iterator(startNode);
while ((cur = next()) && curIndex < index + length) {
let curLength = cur.length();
if (index > curIndex) {
callback(cur, index - curIndex, Math.min(length, curIndex + curLength - index));
} else {
callback(cur, 0, Math.min(curLength, index + length - curIndex));
}
curIndex += curLength;
}
}
map(callback: (cur: T | null) => any): any[] {
return this.reduce(function(memo: (T | null)[], cur: T | null) {
memo.push(callback(cur));
return memo;
}, []);
}
reduce<M>(callback: (memo: M, cur: T) => M, memo: M): M {
let cur,
next = this.iterator();
while ((cur = next())) {
memo = callback(memo, cur);
}
return memo;
}
}
export default LinkedList;

8
node_modules/parchment/src/collection/linked-node.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
interface LinkedNode {
prev: LinkedNode | null;
next: LinkedNode | null;
length(): number;
}
export default LinkedNode;

46
node_modules/parchment/src/parchment.ts generated vendored Normal file
View File

@@ -0,0 +1,46 @@
import { Blot } from './blot/abstract/blot';
import ContainerBlot from './blot/abstract/container';
import FormatBlot from './blot/abstract/format';
import LeafBlot from './blot/abstract/leaf';
import ScrollBlot from './blot/scroll';
import InlineBlot from './blot/inline';
import BlockBlot from './blot/block';
import EmbedBlot from './blot/embed';
import TextBlot from './blot/text';
import Attributor from './attributor/attributor';
import ClassAttributor from './attributor/class';
import StyleAttributor from './attributor/style';
import AttributorStore from './attributor/store';
import * as Registry from './registry';
let Parchment = {
Scope: Registry.Scope,
create: Registry.create,
find: Registry.find,
query: Registry.query,
register: Registry.register,
Container: ContainerBlot,
Format: FormatBlot,
Leaf: LeafBlot,
Embed: EmbedBlot,
Scroll: ScrollBlot,
Block: BlockBlot,
Inline: InlineBlot,
Text: TextBlot,
Attributor: {
Attribute: Attributor,
Class: ClassAttributor,
Style: StyleAttributor,
Store: AttributorStore,
},
};
export default Parchment;

133
node_modules/parchment/src/registry.ts generated vendored Normal file
View File

@@ -0,0 +1,133 @@
import Attributor from './attributor/attributor';
import { Blot, Formattable } from './blot/abstract/blot';
export interface BlotConstructor {
blotName: string;
new (node: Node, value?: any): Blot;
create(value?: any): Node;
}
export class ParchmentError extends Error {
message: string;
name: string;
stack!: string;
constructor(message: string) {
message = '[Parchment] ' + message;
super(message);
this.message = message;
this.name = (<any>this.constructor).name;
}
}
let attributes: { [key: string]: Attributor } = {};
let classes: { [key: string]: BlotConstructor } = {};
let tags: { [key: string]: BlotConstructor } = {};
let types: { [key: string]: Attributor | BlotConstructor } = {};
export const DATA_KEY = '__blot';
export enum Scope {
TYPE = (1 << 2) - 1, // 0011 Lower two bits
LEVEL = ((1 << 2) - 1) << 2, // 1100 Higher two bits
ATTRIBUTE = (1 << 0) | LEVEL, // 1101
BLOT = (1 << 1) | LEVEL, // 1110
INLINE = (1 << 2) | TYPE, // 0111
BLOCK = (1 << 3) | TYPE, // 1011
BLOCK_BLOT = BLOCK & BLOT, // 1010
INLINE_BLOT = INLINE & BLOT, // 0110
BLOCK_ATTRIBUTE = BLOCK & ATTRIBUTE, // 1001
INLINE_ATTRIBUTE = INLINE & ATTRIBUTE, // 0101
ANY = TYPE | LEVEL,
}
export function create(input: Node | string | Scope, value?: any): Blot {
let match = query(input);
if (match == null) {
throw new ParchmentError(`Unable to create ${input} blot`);
}
let BlotClass = <BlotConstructor>match;
let node =
// @ts-ignore
input instanceof Node || input['nodeType'] === Node.TEXT_NODE ? input : BlotClass.create(value);
return new BlotClass(<Node>node, value);
}
export function find(node: Node | null, bubble: boolean = false): Blot | null {
if (node == null) return null;
// @ts-ignore
if (node[DATA_KEY] != null) return node[DATA_KEY].blot;
if (bubble) return find(node.parentNode, bubble);
return null;
}
export function query(
query: string | Node | Scope,
scope: Scope = Scope.ANY,
): Attributor | BlotConstructor | null {
let match;
if (typeof query === 'string') {
match = types[query] || attributes[query];
// @ts-ignore
} else if (query instanceof Text || query['nodeType'] === Node.TEXT_NODE) {
match = types['text'];
} else if (typeof query === 'number') {
if (query & Scope.LEVEL & Scope.BLOCK) {
match = types['block'];
} else if (query & Scope.LEVEL & Scope.INLINE) {
match = types['inline'];
}
} else if (query instanceof HTMLElement) {
let names = (query.getAttribute('class') || '').split(/\s+/);
for (let i in names) {
match = classes[names[i]];
if (match) break;
}
match = match || tags[query.tagName];
}
if (match == null) return null;
// @ts-ignore
if (scope & Scope.LEVEL & match.scope && scope & Scope.TYPE & match.scope) return match;
return null;
}
export function register(...Definitions: any[]): any {
if (Definitions.length > 1) {
return Definitions.map(function(d) {
return register(d);
});
}
let Definition = Definitions[0];
if (typeof Definition.blotName !== 'string' && typeof Definition.attrName !== 'string') {
throw new ParchmentError('Invalid definition');
} else if (Definition.blotName === 'abstract') {
throw new ParchmentError('Cannot register abstract class');
}
types[Definition.blotName || Definition.attrName] = Definition;
if (typeof Definition.keyName === 'string') {
attributes[Definition.keyName] = Definition;
} else {
if (Definition.className != null) {
classes[Definition.className] = Definition;
}
if (Definition.tagName != null) {
if (Array.isArray(Definition.tagName)) {
Definition.tagName = Definition.tagName.map(function(tagName: string) {
return tagName.toUpperCase();
});
} else {
Definition.tagName = Definition.tagName.toUpperCase();
}
let tagNames = Array.isArray(Definition.tagName) ? Definition.tagName : [Definition.tagName];
tagNames.forEach(function(tag: string) {
if (tags[tag] == null || Definition.className == null) {
tags[tag] = Definition;
}
});
}
}
return Definition;
}

9
node_modules/parchment/tsconfig.json generated vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"declaration": true,
"strict": true
},
"exclude": ["node_modules", "test"]
}