Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40d5781c6b | ||
|
|
2a0bd6dda2 | ||
|
|
f6eeddde2d | ||
|
|
9394a4592d | ||
|
|
ff34142824 | ||
|
|
b12bacbc12 | ||
|
|
2e6261c62a | ||
|
|
42100f814c | ||
|
|
b030001387 | ||
|
|
a5abc5db27 | ||
|
|
c52143fdfc | ||
|
|
194335b4d3 | ||
|
|
a826b90428 | ||
|
|
723daabb7d |
16
README.md
16
README.md
@ -1,3 +1,19 @@
|
|||||||
|
## Note: This fork is for use in Signal Desktop
|
||||||
|
|
||||||
|
The biggest change is moving from ESM to CJS.
|
||||||
|
|
||||||
|
Beyond that, there are a few other changes:
|
||||||
|
- keyboard: fix a crash in keydown handler when line is missing
|
||||||
|
- clipboard: add `time` element to list of elements in `isLine`
|
||||||
|
- clipboard: update `matchNewline` to prevent too many newlines in a row
|
||||||
|
- clipboard: update `convert` to apply provided formats to both text and html inputs
|
||||||
|
- scroll: use `contenteditable="plaintext-only"` to fully prevent image paste
|
||||||
|
- clipboard: introduce two new options:
|
||||||
|
- `disableDefaultListeners` - if set to something truthy, disables the clipboard module's `cut`/`copy`/`paste` handlers
|
||||||
|
- `defaultMatchersOverride` - if set, overrides all the default clipboard matchers, giving full control of the list of installed matchers
|
||||||
|
|
||||||
|
It's published as `@signalapp/quill-cjs`.
|
||||||
|
|
||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<a href="https://quilljs.com/" title="Quill">Quill Rich Text Editor</a>
|
<a href="https://quilljs.com/" title="Quill">Quill Rich Text Editor</a>
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
52
package-lock.json
generated
52
package-lock.json
generated
@ -5709,6 +5709,16 @@
|
|||||||
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
|
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@signalapp/parchment-cjs": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@signalapp/parchment-cjs/-/parchment-cjs-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-hSBMQ1M7wE4GcC8ZeNtvpJF+DAJg3eIRRf1SiHS3I3Algav/sgJJNm6HIYm6muHuK7IJmuEjkL3ILSXgmu0RfQ==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@signalapp/quill-cjs": {
|
||||||
|
"resolved": "packages/quill",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@sinclair/typebox": {
|
"node_modules/@sinclair/typebox": {
|
||||||
"version": "0.27.8",
|
"version": "0.27.8",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||||
@ -6184,19 +6194,11 @@
|
|||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
"version": "4.17.0",
|
"version": "4.17.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz",
|
||||||
"integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==",
|
"integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==",
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/lodash-es": {
|
|
||||||
"version": "4.17.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
|
||||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"license": "MIT"
|
||||||
"@types/lodash": "*"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/mdast": {
|
"node_modules/@types/mdast": {
|
||||||
"version": "3.0.15",
|
"version": "3.0.15",
|
||||||
@ -13233,13 +13235,7 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/lodash-es": {
|
|
||||||
"version": "4.17.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
|
||||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.clonedeep": {
|
"node_modules/lodash.clonedeep": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
@ -14840,11 +14836,6 @@
|
|||||||
"tslib": "^2.0.3"
|
"tslib": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/parchment": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A=="
|
|
||||||
},
|
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@ -15550,10 +15541,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/quill": {
|
|
||||||
"resolved": "packages/quill",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/quill-delta": {
|
"node_modules/quill-delta": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
|
||||||
@ -19236,12 +19223,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/quill": {
|
"packages/quill": {
|
||||||
"version": "2.0.3",
|
"name": "@signalapp/quill-cjs",
|
||||||
|
"version": "2.1.0",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@signalapp/parchment-cjs": "3.0.1",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"parchment": "^3.0.0",
|
|
||||||
"quill-delta": "^5.1.0"
|
"quill-delta": "^5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -19251,7 +19239,7 @@
|
|||||||
"@babel/preset-typescript": "^7.23.3",
|
"@babel/preset-typescript": "^7.23.3",
|
||||||
"@playwright/test": "1.44.1",
|
"@playwright/test": "1.44.1",
|
||||||
"@types/highlight.js": "^9.12.4",
|
"@types/highlight.js": "^9.12.4",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash": "^4.17.14",
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
"@types/webpack": "^5.28.5",
|
"@types/webpack": "^5.28.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
## Note: This fork is for use in Signal Desktop
|
||||||
|
|
||||||
# Quill
|
# Quill
|
||||||
|
|
||||||
This is the main package of Quill.
|
This is the main package of Quill.
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const pkg = require('./package.json');
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
['@babel/preset-env', { modules: false }],
|
['@babel/preset-env', { modules: 'cjs' }],
|
||||||
'@babel/preset-typescript',
|
'@babel/preset-typescript',
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "quill",
|
"name": "@signalapp/quill-cjs",
|
||||||
"version": "2.0.3",
|
"version": "2.1.2",
|
||||||
"description": "Your powerful, rich text editor",
|
"description": "Your powerful, rich text editor",
|
||||||
"author": "Jason Chen <jhchen7@gmail.com>",
|
"author": "Jason Chen <jhchen7@gmail.com>",
|
||||||
"homepage": "https://quilljs.com",
|
"homepage": "https://quilljs.com",
|
||||||
"main": "quill.js",
|
"main": "quill.js",
|
||||||
"type": "module",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"parchment": "^3.0.0",
|
"@signalapp/parchment-cjs": "3.0.1",
|
||||||
"quill-delta": "^5.1.0"
|
"quill-delta": "^5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -19,7 +18,7 @@
|
|||||||
"@babel/preset-typescript": "^7.23.3",
|
"@babel/preset-typescript": "^7.23.3",
|
||||||
"@playwright/test": "1.44.1",
|
"@playwright/test": "1.44.1",
|
||||||
"@types/highlight.js": "^9.12.4",
|
"@types/highlight.js": "^9.12.4",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash": "^4.17.14",
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
"@types/webpack": "^5.28.5",
|
"@types/webpack": "^5.28.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
|
|||||||
@ -11,7 +11,7 @@ rm -rf $DIST
|
|||||||
mkdir $DIST
|
mkdir $DIST
|
||||||
mv $TMPDIR/src/* $DIST
|
mv $TMPDIR/src/* $DIST
|
||||||
rm -rf $TMPDIR
|
rm -rf $TMPDIR
|
||||||
npx babel src --out-dir $DIST --copy-files --no-copy-ignored --extensions .ts --source-maps
|
npx babel src --out-dir $DIST --copy-files --no-copy-ignored --extensions .ts
|
||||||
npx webpack -- --mode $1
|
npx webpack -- --mode $1
|
||||||
# https://github.com/webpack-contrib/mini-css-extract-plugin/issues/151
|
# https://github.com/webpack-contrib/mini-css-extract-plugin/issues/151
|
||||||
rm -rf $DIST/dist/*.css.js $DIST/dist/*.css.js.*
|
rm -rf $DIST/dist/*.css.js $DIST/dist/*.css.js.*
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import {
|
|||||||
EmbedBlot,
|
EmbedBlot,
|
||||||
LeafBlot,
|
LeafBlot,
|
||||||
Scope,
|
Scope,
|
||||||
} from 'parchment';
|
} from '@signalapp/parchment-cjs';
|
||||||
import type { Blot, Parent } from 'parchment';
|
import type { Blot, Parent } from '@signalapp/parchment-cjs';
|
||||||
import Delta from 'quill-delta';
|
import Delta from 'quill-delta';
|
||||||
import Break from './break.js';
|
import Break from './break.js';
|
||||||
import Inline from './inline.js';
|
import Inline from './inline.js';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { EmbedBlot } from 'parchment';
|
import { EmbedBlot } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
class Break extends EmbedBlot {
|
class Break extends EmbedBlot {
|
||||||
static value() {
|
static value() {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ContainerBlot } from 'parchment';
|
import { ContainerBlot } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
class Container extends ContainerBlot {}
|
class Container extends ContainerBlot {}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { EmbedBlot, Scope } from 'parchment';
|
import { EmbedBlot, Scope } from '@signalapp/parchment-cjs';
|
||||||
import type { Parent, ScrollBlot } from 'parchment';
|
import type { Parent, ScrollBlot } from '@signalapp/parchment-cjs';
|
||||||
import type Selection from '../core/selection.js';
|
import type Selection from '../core/selection.js';
|
||||||
import TextBlot from './text.js';
|
import TextBlot from './text.js';
|
||||||
import type { EmbedContextRange } from './embed.js';
|
import type { EmbedContextRange } from './embed.js';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { ScrollBlot } from 'parchment';
|
import type { ScrollBlot } from '@signalapp/parchment-cjs';
|
||||||
import { EmbedBlot } from 'parchment';
|
import { EmbedBlot } from '@signalapp/parchment-cjs';
|
||||||
import TextBlot from './text.js';
|
import TextBlot from './text.js';
|
||||||
|
|
||||||
const GUARD_TEXT = '\uFEFF';
|
const GUARD_TEXT = '\uFEFF';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { EmbedBlot, InlineBlot, Scope } from 'parchment';
|
import { EmbedBlot, InlineBlot, Scope } from '@signalapp/parchment-cjs';
|
||||||
import type { BlotConstructor } from 'parchment';
|
import type { BlotConstructor } from '@signalapp/parchment-cjs';
|
||||||
import Break from './break.js';
|
import Break from './break.js';
|
||||||
import Text from './text.js';
|
import Text from './text.js';
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,16 @@
|
|||||||
import { ContainerBlot, LeafBlot, Scope, ScrollBlot } from 'parchment';
|
import {
|
||||||
import type { Blot, Parent, EmbedBlot, ParentBlot, Registry } from 'parchment';
|
ContainerBlot,
|
||||||
|
LeafBlot,
|
||||||
|
Scope,
|
||||||
|
ScrollBlot,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
import type {
|
||||||
|
Blot,
|
||||||
|
Parent,
|
||||||
|
EmbedBlot,
|
||||||
|
ParentBlot,
|
||||||
|
Registry,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
import Delta, { AttributeMap, Op } from 'quill-delta';
|
import Delta, { AttributeMap, Op } from 'quill-delta';
|
||||||
import Emitter from '../core/emitter.js';
|
import Emitter from '../core/emitter.js';
|
||||||
import type { EmitterSource } from '../core/emitter.js';
|
import type { EmitterSource } from '../core/emitter.js';
|
||||||
@ -96,7 +107,10 @@ class Scroll extends ScrollBlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enable(enabled = true) {
|
enable(enabled = true) {
|
||||||
this.domNode.setAttribute('contenteditable', enabled ? 'true' : 'false');
|
this.domNode.setAttribute(
|
||||||
|
'contenteditable',
|
||||||
|
enabled ? 'plaintext-only' : 'false',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatAt(index: number, length: number, format: string, value: unknown) {
|
formatAt(index: number, length: number, format: string, value: unknown) {
|
||||||
@ -210,7 +224,8 @@ class Scroll extends ScrollBlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
return this.domNode.getAttribute('contenteditable') === 'true';
|
const value = this.domNode.getAttribute('contenteditable');
|
||||||
|
return value === 'true' || value === 'plaintext-only';
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf(index: number): [LeafBlot | null, number] {
|
leaf(index: number): [LeafBlot | null, number] {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { TextBlot } from 'parchment';
|
import { TextBlot } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
class Text extends TextBlot {}
|
class Text extends TextBlot {}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import { cloneDeep, isEqual, merge } from 'lodash-es';
|
import { cloneDeep, isEqual, merge } from 'lodash';
|
||||||
import { LeafBlot, EmbedBlot, Scope, ParentBlot } from 'parchment';
|
import {
|
||||||
import type { Blot } from 'parchment';
|
LeafBlot,
|
||||||
|
EmbedBlot,
|
||||||
|
Scope,
|
||||||
|
ParentBlot,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
import type { Blot } from '@signalapp/parchment-cjs';
|
||||||
import Delta, { AttributeMap, Op } from 'quill-delta';
|
import Delta, { AttributeMap, Op } from 'quill-delta';
|
||||||
import Block, { BlockEmbed, bubbleFormats } from '../blots/block.js';
|
import Block, { BlockEmbed, bubbleFormats } from '../blots/block.js';
|
||||||
import Break from '../blots/break.js';
|
import Break from '../blots/break.js';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash';
|
||||||
import * as Parchment from 'parchment';
|
import * as Parchment from '@signalapp/parchment-cjs';
|
||||||
import type { Op } from 'quill-delta';
|
import type { Op } from 'quill-delta';
|
||||||
import Delta from 'quill-delta';
|
import Delta from 'quill-delta';
|
||||||
import type { BlockEmbed } from '../blots/block.js';
|
import type { BlockEmbed } from '../blots/block.js';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { LeafBlot, Scope } from 'parchment';
|
import { LeafBlot, Scope } from '@signalapp/parchment-cjs';
|
||||||
import { cloneDeep, isEqual } from 'lodash-es';
|
import { cloneDeep, isEqual } from 'lodash';
|
||||||
import Emitter from './emitter.js';
|
import Emitter from './emitter.js';
|
||||||
import type { EmitterSource } from './emitter.js';
|
import type { EmitterSource } from './emitter.js';
|
||||||
import logger from './logger.js';
|
import logger from './logger.js';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Registry } from 'parchment';
|
import { Registry } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
const MAX_REGISTER_ITERATIONS = 100;
|
const MAX_REGISTER_ITERATIONS = 100;
|
||||||
const CORE_FORMATS = ['block', 'break', 'cursor', 'inline', 'scroll', 'text'];
|
const CORE_FORMATS = ['block', 'break', 'cursor', 'inline', 'scroll', 'text'];
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
import { Attributor, ClassAttributor, Scope, StyleAttributor } from 'parchment';
|
import {
|
||||||
|
Attributor,
|
||||||
|
ClassAttributor,
|
||||||
|
Scope,
|
||||||
|
StyleAttributor,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
scope: Scope.BLOCK,
|
scope: Scope.BLOCK,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ClassAttributor, Scope } from 'parchment';
|
import { ClassAttributor, Scope } from '@signalapp/parchment-cjs';
|
||||||
import { ColorAttributor } from './color.js';
|
import { ColorAttributor } from './color.js';
|
||||||
|
|
||||||
const BackgroundClass = new ClassAttributor('background', 'ql-bg', {
|
const BackgroundClass = new ClassAttributor('background', 'ql-bg', {
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import { ClassAttributor, Scope, StyleAttributor } from 'parchment';
|
import {
|
||||||
|
ClassAttributor,
|
||||||
|
Scope,
|
||||||
|
StyleAttributor,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
class ColorAttributor extends StyleAttributor {
|
class ColorAttributor extends StyleAttributor {
|
||||||
value(domNode: HTMLElement) {
|
value(domNode: HTMLElement) {
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
import { Attributor, ClassAttributor, Scope, StyleAttributor } from 'parchment';
|
import {
|
||||||
|
Attributor,
|
||||||
|
ClassAttributor,
|
||||||
|
Scope,
|
||||||
|
StyleAttributor,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
scope: Scope.BLOCK,
|
scope: Scope.BLOCK,
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import { ClassAttributor, Scope, StyleAttributor } from 'parchment';
|
import {
|
||||||
|
ClassAttributor,
|
||||||
|
Scope,
|
||||||
|
StyleAttributor,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
scope: Scope.INLINE,
|
scope: Scope.INLINE,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { EmbedBlot } from 'parchment';
|
import { EmbedBlot } from '@signalapp/parchment-cjs';
|
||||||
import { sanitize } from './link.js';
|
import { sanitize } from './link.js';
|
||||||
|
|
||||||
const ATTRIBUTES = ['alt', 'height', 'width'];
|
const ATTRIBUTES = ['alt', 'height', 'width'];
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ClassAttributor, Scope } from 'parchment';
|
import { ClassAttributor, Scope } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
class IndentAttributor extends ClassAttributor {
|
class IndentAttributor extends ClassAttributor {
|
||||||
add(node: HTMLElement, value: string | number) {
|
add(node: HTMLElement, value: string | number) {
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import { ClassAttributor, Scope, StyleAttributor } from 'parchment';
|
import {
|
||||||
|
ClassAttributor,
|
||||||
|
Scope,
|
||||||
|
StyleAttributor,
|
||||||
|
} from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
const SizeClass = new ClassAttributor('size', 'ql-size', {
|
const SizeClass = new ClassAttributor('size', 'ql-size', {
|
||||||
scope: Scope.INLINE,
|
scope: Scope.INLINE,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { LinkedList } from 'parchment';
|
import type { LinkedList } from '@signalapp/parchment-cjs';
|
||||||
import Block from '../blots/block.js';
|
import Block from '../blots/block.js';
|
||||||
import Container from '../blots/container.js';
|
import Container from '../blots/container.js';
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { ScrollBlot } from 'parchment';
|
import type { ScrollBlot } from '@signalapp/parchment-cjs';
|
||||||
import {
|
import {
|
||||||
Attributor,
|
Attributor,
|
||||||
BlockBlot,
|
BlockBlot,
|
||||||
@ -6,8 +6,9 @@ import {
|
|||||||
EmbedBlot,
|
EmbedBlot,
|
||||||
Scope,
|
Scope,
|
||||||
StyleAttributor,
|
StyleAttributor,
|
||||||
} from 'parchment';
|
} from '@signalapp/parchment-cjs';
|
||||||
import Delta from 'quill-delta';
|
import Delta from 'quill-delta';
|
||||||
|
import type { AttributeMap } from 'quill-delta';
|
||||||
import { BlockEmbed } from '../blots/block.js';
|
import { BlockEmbed } from '../blots/block.js';
|
||||||
import type { EmitterSource } from '../core/emitter.js';
|
import type { EmitterSource } from '../core/emitter.js';
|
||||||
import logger from '../core/logger.js';
|
import logger from '../core/logger.js';
|
||||||
@ -27,7 +28,12 @@ import normalizeExternalHTML from './normalizeExternalHTML/index.js';
|
|||||||
const debug = logger('quill:clipboard');
|
const debug = logger('quill:clipboard');
|
||||||
|
|
||||||
type Selector = string | Node['TEXT_NODE'] | Node['ELEMENT_NODE'];
|
type Selector = string | Node['TEXT_NODE'] | Node['ELEMENT_NODE'];
|
||||||
type Matcher = (node: Node, delta: Delta, scroll: ScrollBlot) => Delta;
|
type Matcher = (
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) => Delta;
|
||||||
|
|
||||||
const CLIPBOARD_CONFIG: [Selector, Matcher][] = [
|
const CLIPBOARD_CONFIG: [Selector, Matcher][] = [
|
||||||
[Node.TEXT_NODE, matchText],
|
[Node.TEXT_NODE, matchText],
|
||||||
@ -69,6 +75,8 @@ const STYLE_ATTRIBUTORS = [
|
|||||||
|
|
||||||
interface ClipboardOptions {
|
interface ClipboardOptions {
|
||||||
matchers: [Selector, Matcher][];
|
matchers: [Selector, Matcher][];
|
||||||
|
defaultMatchersOverride?: [Selector, Matcher][];
|
||||||
|
disableDefaultListeners?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Clipboard extends Module<ClipboardOptions> {
|
class Clipboard extends Module<ClipboardOptions> {
|
||||||
@ -80,17 +88,24 @@ class Clipboard extends Module<ClipboardOptions> {
|
|||||||
|
|
||||||
constructor(quill: Quill, options: Partial<ClipboardOptions>) {
|
constructor(quill: Quill, options: Partial<ClipboardOptions>) {
|
||||||
super(quill, options);
|
super(quill, options);
|
||||||
this.quill.root.addEventListener('copy', (e) =>
|
|
||||||
this.onCaptureCopy(e, false),
|
if (!options.disableDefaultListeners) {
|
||||||
);
|
this.quill.root.addEventListener('copy', (e) =>
|
||||||
this.quill.root.addEventListener('cut', (e) => this.onCaptureCopy(e, true));
|
this.onCaptureCopy(e, false),
|
||||||
this.quill.root.addEventListener('paste', this.onCapturePaste.bind(this));
|
);
|
||||||
|
this.quill.root.addEventListener('cut', (e) =>
|
||||||
|
this.onCaptureCopy(e, true),
|
||||||
|
);
|
||||||
|
this.quill.root.addEventListener('paste', this.onCapturePaste.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
this.matchers = [];
|
this.matchers = [];
|
||||||
CLIPBOARD_CONFIG.concat(this.options.matchers ?? []).forEach(
|
const baseMatchers = options.defaultMatchersOverride ?? CLIPBOARD_CONFIG;
|
||||||
([selector, matcher]) => {
|
baseMatchers
|
||||||
|
.concat(this.options.matchers ?? [])
|
||||||
|
.forEach(([selector, matcher]) => {
|
||||||
this.addMatcher(selector, matcher);
|
this.addMatcher(selector, matcher);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addMatcher(selector: Selector, matcher: Matcher) {
|
addMatcher(selector: Selector, matcher: Matcher) {
|
||||||
@ -109,7 +124,7 @@ class Clipboard extends Module<ClipboardOptions> {
|
|||||||
if (!html) {
|
if (!html) {
|
||||||
return new Delta().insert(text || '', formats);
|
return new Delta().insert(text || '', formats);
|
||||||
}
|
}
|
||||||
const delta = this.convertHTML(html);
|
const delta = this.convertHTML(html, formats);
|
||||||
// Remove trailing newline
|
// Remove trailing newline
|
||||||
if (
|
if (
|
||||||
deltaEndsWith(delta, '\n') &&
|
deltaEndsWith(delta, '\n') &&
|
||||||
@ -124,7 +139,7 @@ class Clipboard extends Module<ClipboardOptions> {
|
|||||||
normalizeExternalHTML(doc);
|
normalizeExternalHTML(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected convertHTML(html: string) {
|
protected convertHTML(html: string, formats: Record<string, unknown> = {}) {
|
||||||
const doc = new DOMParser().parseFromString(html, 'text/html');
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
||||||
this.normalizeHTML(doc);
|
this.normalizeHTML(doc);
|
||||||
const container = doc.body;
|
const container = doc.body;
|
||||||
@ -139,6 +154,7 @@ class Clipboard extends Module<ClipboardOptions> {
|
|||||||
elementMatchers,
|
elementMatchers,
|
||||||
textMatchers,
|
textMatchers,
|
||||||
nodeMatches,
|
nodeMatches,
|
||||||
|
formats,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +298,7 @@ function applyFormat(
|
|||||||
format: string,
|
format: string,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
scroll: ScrollBlot,
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
): Delta {
|
): Delta {
|
||||||
if (!scroll.query(format)) {
|
if (!scroll.query(format)) {
|
||||||
return delta;
|
return delta;
|
||||||
@ -290,10 +307,14 @@ function applyFormat(
|
|||||||
return delta.reduce((newDelta, op) => {
|
return delta.reduce((newDelta, op) => {
|
||||||
if (!op.insert) return newDelta;
|
if (!op.insert) return newDelta;
|
||||||
if (op.attributes && op.attributes[format]) {
|
if (op.attributes && op.attributes[format]) {
|
||||||
return newDelta.push(op);
|
return newDelta.insert(op.insert, { ...op.attributes, ...attributes });
|
||||||
}
|
}
|
||||||
const formats = value ? { [format]: value } : {};
|
const formats = value ? { [format]: value } : {};
|
||||||
return newDelta.insert(op.insert, { ...formats, ...op.attributes });
|
return newDelta.insert(op.insert, {
|
||||||
|
...formats,
|
||||||
|
...op.attributes,
|
||||||
|
...attributes,
|
||||||
|
});
|
||||||
}, new Delta());
|
}, new Delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,6 +370,7 @@ function isLine(node: Node, scroll: ScrollBlot) {
|
|||||||
'section',
|
'section',
|
||||||
'table',
|
'table',
|
||||||
'td',
|
'td',
|
||||||
|
'time',
|
||||||
'tr',
|
'tr',
|
||||||
'ul',
|
'ul',
|
||||||
'video',
|
'video',
|
||||||
@ -384,11 +406,12 @@ function traverse(
|
|||||||
elementMatchers: Matcher[],
|
elementMatchers: Matcher[],
|
||||||
textMatchers: Matcher[],
|
textMatchers: Matcher[],
|
||||||
nodeMatches: WeakMap<Node, Matcher[]>,
|
nodeMatches: WeakMap<Node, Matcher[]>,
|
||||||
|
attributes: AttributeMap,
|
||||||
): Delta {
|
): Delta {
|
||||||
// Post-order
|
// Post-order
|
||||||
if (node.nodeType === node.TEXT_NODE) {
|
if (node.nodeType === node.TEXT_NODE) {
|
||||||
return textMatchers.reduce((delta: Delta, matcher) => {
|
return textMatchers.reduce((delta: Delta, matcher) => {
|
||||||
return matcher(node, delta, scroll);
|
return matcher(node, delta, scroll, attributes);
|
||||||
}, new Delta());
|
}, new Delta());
|
||||||
}
|
}
|
||||||
if (node.nodeType === node.ELEMENT_NODE) {
|
if (node.nodeType === node.ELEMENT_NODE) {
|
||||||
@ -399,14 +422,20 @@ function traverse(
|
|||||||
elementMatchers,
|
elementMatchers,
|
||||||
textMatchers,
|
textMatchers,
|
||||||
nodeMatches,
|
nodeMatches,
|
||||||
|
attributes,
|
||||||
);
|
);
|
||||||
if (childNode.nodeType === node.ELEMENT_NODE) {
|
if (childNode.nodeType === node.ELEMENT_NODE) {
|
||||||
childrenDelta = elementMatchers.reduce((reducedDelta, matcher) => {
|
childrenDelta = elementMatchers.reduce((reducedDelta, matcher) => {
|
||||||
return matcher(childNode as HTMLElement, reducedDelta, scroll);
|
return matcher(
|
||||||
|
childNode as HTMLElement,
|
||||||
|
reducedDelta,
|
||||||
|
scroll,
|
||||||
|
attributes,
|
||||||
|
);
|
||||||
}, childrenDelta);
|
}, childrenDelta);
|
||||||
childrenDelta = (nodeMatches.get(childNode) || []).reduce(
|
childrenDelta = (nodeMatches.get(childNode) || []).reduce(
|
||||||
(reducedDelta, matcher) => {
|
(reducedDelta, matcher) => {
|
||||||
return matcher(childNode, reducedDelta, scroll);
|
return matcher(childNode, reducedDelta, scroll, attributes);
|
||||||
},
|
},
|
||||||
childrenDelta,
|
childrenDelta,
|
||||||
);
|
);
|
||||||
@ -417,13 +446,23 @@ function traverse(
|
|||||||
return new Delta();
|
return new Delta();
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMatchAlias(format: string) {
|
function createMatchAlias(format: string): Matcher {
|
||||||
return (_node: Element, delta: Delta, scroll: ScrollBlot) => {
|
return (
|
||||||
return applyFormat(delta, format, true, scroll);
|
_node: Element,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) => {
|
||||||
|
return applyFormat(delta, format, true, scroll, attributes);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchAttributor(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
|
function matchAttributor(
|
||||||
|
node: HTMLElement,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
targetAttributes: AttributeMap,
|
||||||
|
) {
|
||||||
const attributes = Attributor.keys(node);
|
const attributes = Attributor.keys(node);
|
||||||
const classes = ClassAttributor.keys(node);
|
const classes = ClassAttributor.keys(node);
|
||||||
const styles = StyleAttributor.keys(node);
|
const styles = StyleAttributor.keys(node);
|
||||||
@ -449,12 +488,18 @@ function matchAttributor(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return Object.entries(formats).reduce(
|
return Object.entries(formats).reduce(
|
||||||
(newDelta, [name, value]) => applyFormat(newDelta, name, value, scroll),
|
(newDelta, [name, value]) =>
|
||||||
|
applyFormat(newDelta, name, value, scroll, targetAttributes),
|
||||||
delta,
|
delta,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchBlot(node: Node, delta: Delta, scroll: ScrollBlot) {
|
function matchBlot(
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
const match = scroll.query(node);
|
const match = scroll.query(node);
|
||||||
if (match == null) return delta;
|
if (match == null) return delta;
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
@ -483,33 +528,49 @@ function matchBlot(node: Node, delta: Delta, scroll: ScrollBlot) {
|
|||||||
match.blotName,
|
match.blotName,
|
||||||
match.formats(node, scroll),
|
match.formats(node, scroll),
|
||||||
scroll,
|
scroll,
|
||||||
|
attributes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchBreak(node: Node, delta: Delta) {
|
function matchBreak(
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
_scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
if (!deltaEndsWith(delta, '\n')) {
|
if (!deltaEndsWith(delta, '\n')) {
|
||||||
delta.insert('\n');
|
delta.insert('\n', attributes);
|
||||||
}
|
}
|
||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchCodeBlock(node: Node, delta: Delta, scroll: ScrollBlot) {
|
function matchCodeBlock(
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
const match = scroll.query('code-block');
|
const match = scroll.query('code-block');
|
||||||
const language =
|
const language =
|
||||||
match && 'formats' in match && typeof match.formats === 'function'
|
match && 'formats' in match && typeof match.formats === 'function'
|
||||||
? match.formats(node, scroll)
|
? match.formats(node, scroll)
|
||||||
: true;
|
: true;
|
||||||
return applyFormat(delta, 'code-block', language, scroll);
|
return applyFormat(delta, 'code-block', language, scroll, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchIgnore() {
|
function matchIgnore() {
|
||||||
return new Delta();
|
return new Delta();
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchIndent(node: Node, delta: Delta, scroll: ScrollBlot) {
|
function matchIndent(
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
const match = scroll.query(node);
|
const match = scroll.query(node);
|
||||||
if (
|
if (
|
||||||
match == null ||
|
match == null ||
|
||||||
@ -534,11 +595,20 @@ function matchIndent(node: Node, delta: Delta, scroll: ScrollBlot) {
|
|||||||
if (op.attributes && typeof op.attributes.indent === 'number') {
|
if (op.attributes && typeof op.attributes.indent === 'number') {
|
||||||
return composed.push(op);
|
return composed.push(op);
|
||||||
}
|
}
|
||||||
return composed.insert(op.insert, { indent, ...(op.attributes || {}) });
|
return composed.insert(op.insert, {
|
||||||
|
indent,
|
||||||
|
...(op.attributes || {}),
|
||||||
|
attributes,
|
||||||
|
});
|
||||||
}, new Delta());
|
}, new Delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchList(node: Node, delta: Delta, scroll: ScrollBlot) {
|
function matchList(
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
const element = node as Element;
|
const element = node as Element;
|
||||||
let list = element.tagName === 'OL' ? 'ordered' : 'bullet';
|
let list = element.tagName === 'OL' ? 'ordered' : 'bullet';
|
||||||
|
|
||||||
@ -547,27 +617,48 @@ function matchList(node: Node, delta: Delta, scroll: ScrollBlot) {
|
|||||||
list = checkedAttr === 'true' ? 'checked' : 'unchecked';
|
list = checkedAttr === 'true' ? 'checked' : 'unchecked';
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyFormat(delta, 'list', list, scroll);
|
return applyFormat(delta, 'list', list, scroll, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchNewline(node: Node, delta: Delta, scroll: ScrollBlot) {
|
function deltaIs(delta: Delta, text: string): boolean {
|
||||||
if (!deltaEndsWith(delta, '\n')) {
|
let allText = '';
|
||||||
|
for (
|
||||||
|
let i = delta.ops.length - 1;
|
||||||
|
i >= 0 && allText.length <= text.length;
|
||||||
|
i -= 1
|
||||||
|
) {
|
||||||
|
const op = delta.ops[i];
|
||||||
|
if (typeof op.insert !== 'string') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
allText = op.insert + allText;
|
||||||
|
}
|
||||||
|
return allText === text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchNewline(
|
||||||
|
node: Node,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
|
if (!deltaIs(delta, '\n') && !deltaEndsWith(delta, '\n\n')) {
|
||||||
if (
|
if (
|
||||||
isLine(node, scroll) &&
|
isLine(node, scroll) &&
|
||||||
(node.childNodes.length > 0 || node instanceof HTMLParagraphElement)
|
(node.childNodes.length > 0 || node instanceof HTMLParagraphElement)
|
||||||
) {
|
) {
|
||||||
return delta.insert('\n');
|
return delta.insert('\n', attributes);
|
||||||
}
|
}
|
||||||
if (delta.length() > 0 && node.nextSibling) {
|
if (delta.length() > 0 && node.nextSibling) {
|
||||||
let nextSibling: Node | null = node.nextSibling;
|
let nextSibling: Node | null = node.nextSibling;
|
||||||
while (nextSibling != null) {
|
while (nextSibling != null) {
|
||||||
if (isLine(nextSibling, scroll)) {
|
if (isLine(nextSibling, scroll)) {
|
||||||
return delta.insert('\n');
|
return delta.insert('\n', attributes);
|
||||||
}
|
}
|
||||||
const match = scroll.query(nextSibling);
|
const match = scroll.query(nextSibling);
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
if (match && match.prototype instanceof BlockEmbed) {
|
if (match && match.prototype instanceof BlockEmbed) {
|
||||||
return delta.insert('\n');
|
return delta.insert('\n', attributes);
|
||||||
}
|
}
|
||||||
nextSibling = nextSibling.firstChild;
|
nextSibling = nextSibling.firstChild;
|
||||||
}
|
}
|
||||||
@ -576,7 +667,12 @@ function matchNewline(node: Node, delta: Delta, scroll: ScrollBlot) {
|
|||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchStyles(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
|
function matchStyles(
|
||||||
|
node: HTMLElement,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
const formats: Record<string, unknown> = {};
|
const formats: Record<string, unknown> = {};
|
||||||
const style: Partial<CSSStyleDeclaration> = node.style || {};
|
const style: Partial<CSSStyleDeclaration> = node.style || {};
|
||||||
if (style.fontStyle === 'italic') {
|
if (style.fontStyle === 'italic') {
|
||||||
@ -596,13 +692,14 @@ function matchStyles(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
|
|||||||
formats.bold = true;
|
formats.bold = true;
|
||||||
}
|
}
|
||||||
delta = Object.entries(formats).reduce(
|
delta = Object.entries(formats).reduce(
|
||||||
(newDelta, [name, value]) => applyFormat(newDelta, name, value, scroll),
|
(newDelta, [name, value]) =>
|
||||||
|
applyFormat(newDelta, name, value, scroll, attributes),
|
||||||
delta,
|
delta,
|
||||||
);
|
);
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
if (parseFloat(style.textIndent || 0) > 0) {
|
if (parseFloat(style.textIndent || 0) > 0) {
|
||||||
// Could be 0.5in
|
// Could be 0.5in
|
||||||
return new Delta().insert('\t').concat(delta);
|
return new Delta().insert('\t', attributes).concat(delta);
|
||||||
}
|
}
|
||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
@ -611,6 +708,7 @@ function matchTable(
|
|||||||
node: HTMLTableRowElement,
|
node: HTMLTableRowElement,
|
||||||
delta: Delta,
|
delta: Delta,
|
||||||
scroll: ScrollBlot,
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
) {
|
) {
|
||||||
const table =
|
const table =
|
||||||
node.parentElement?.tagName === 'TABLE'
|
node.parentElement?.tagName === 'TABLE'
|
||||||
@ -619,17 +717,22 @@ function matchTable(
|
|||||||
if (table != null) {
|
if (table != null) {
|
||||||
const rows = Array.from(table.querySelectorAll('tr'));
|
const rows = Array.from(table.querySelectorAll('tr'));
|
||||||
const row = rows.indexOf(node) + 1;
|
const row = rows.indexOf(node) + 1;
|
||||||
return applyFormat(delta, 'table', row, scroll);
|
return applyFormat(delta, 'table', row, scroll, attributes);
|
||||||
}
|
}
|
||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchText(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
|
function matchText(
|
||||||
|
node: HTMLElement,
|
||||||
|
delta: Delta,
|
||||||
|
scroll: ScrollBlot,
|
||||||
|
attributes: AttributeMap,
|
||||||
|
) {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
let text = node.data as string;
|
let text = node.data as string;
|
||||||
// Word represents empty line with <o:p> </o:p>
|
// Word represents empty line with <o:p> </o:p>
|
||||||
if (node.parentElement?.tagName === 'O:P') {
|
if (node.parentElement?.tagName === 'O:P') {
|
||||||
return delta.insert(text.trim());
|
return delta.insert(text.trim(), attributes);
|
||||||
}
|
}
|
||||||
if (!isPre(node)) {
|
if (!isPre(node)) {
|
||||||
if (
|
if (
|
||||||
@ -665,13 +768,14 @@ function matchText(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
|
|||||||
// done removing whitespace and can normalize all to regular space
|
// done removing whitespace and can normalize all to regular space
|
||||||
text = text.replaceAll('\u00a0', ' ');
|
text = text.replaceAll('\u00a0', ' ');
|
||||||
}
|
}
|
||||||
return delta.insert(text);
|
return delta.insert(text, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Clipboard as default,
|
Clipboard as default,
|
||||||
matchAttributor,
|
matchAttributor,
|
||||||
matchBlot,
|
matchBlot,
|
||||||
|
matchBreak,
|
||||||
matchNewline,
|
matchNewline,
|
||||||
matchText,
|
matchText,
|
||||||
traverse,
|
traverse,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Scope } from 'parchment';
|
import { Scope } from '@signalapp/parchment-cjs';
|
||||||
import type Delta from 'quill-delta';
|
import type Delta from 'quill-delta';
|
||||||
import Module from '../core/module.js';
|
import Module from '../core/module.js';
|
||||||
import Quill from '../core/quill.js';
|
import Quill from '../core/quill.js';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { cloneDeep, isEqual } from 'lodash-es';
|
import { cloneDeep, isEqual } from 'lodash';
|
||||||
import Delta, { AttributeMap } from 'quill-delta';
|
import Delta, { AttributeMap } from 'quill-delta';
|
||||||
import { EmbedBlot, Scope, TextBlot } from 'parchment';
|
import { EmbedBlot, Scope, TextBlot } from '@signalapp/parchment-cjs';
|
||||||
import type { Blot, BlockBlot } from 'parchment';
|
import type { Blot, BlockBlot } from '@signalapp/parchment-cjs';
|
||||||
import Quill from '../core/quill.js';
|
import Quill from '../core/quill.js';
|
||||||
import logger from '../core/logger.js';
|
import logger from '../core/logger.js';
|
||||||
import Module from '../core/module.js';
|
import Module from '../core/module.js';
|
||||||
@ -206,8 +206,7 @@ class Keyboard extends Module<KeyboardOptions> {
|
|||||||
leafEnd instanceof TextBlot ? leafEnd.value().slice(offsetEnd) : '';
|
leafEnd instanceof TextBlot ? leafEnd.value().slice(offsetEnd) : '';
|
||||||
const curContext = {
|
const curContext = {
|
||||||
collapsed: range.length === 0,
|
collapsed: range.length === 0,
|
||||||
// @ts-expect-error Fix me later
|
empty: range.length === 0 && (line?.length() ?? 0) <= 1,
|
||||||
empty: range.length === 0 && line.length() <= 1,
|
|
||||||
format: this.quill.getFormat(range),
|
format: this.quill.getFormat(range),
|
||||||
line,
|
line,
|
||||||
offset,
|
offset,
|
||||||
@ -351,6 +350,13 @@ class Keyboard extends Module<KeyboardOptions> {
|
|||||||
this.quill.updateContents(delta, Quill.sources.USER);
|
this.quill.updateContents(delta, Quill.sources.USER);
|
||||||
this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
|
this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
|
||||||
this.quill.focus();
|
this.quill.focus();
|
||||||
|
|
||||||
|
Object.keys(context.format).forEach((name) => {
|
||||||
|
if (lineFormats[name] != null) return;
|
||||||
|
if (Array.isArray(context.format[name])) return;
|
||||||
|
if (name === 'code' || name === 'link') return;
|
||||||
|
this.quill.format(name, context.format[name], Quill.sources.USER);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Delta from 'quill-delta';
|
import Delta from 'quill-delta';
|
||||||
import { ClassAttributor, Scope } from 'parchment';
|
import { ClassAttributor, Scope } from '@signalapp/parchment-cjs';
|
||||||
import type { Blot, ScrollBlot } from 'parchment';
|
import type { Blot, ScrollBlot } from '@signalapp/parchment-cjs';
|
||||||
import Inline from '../blots/inline.js';
|
import Inline from '../blots/inline.js';
|
||||||
import Quill from '../core/quill.js';
|
import Quill from '../core/quill.js';
|
||||||
import Module from '../core/module.js';
|
import Module from '../core/module.js';
|
||||||
@ -302,6 +302,10 @@ class Syntax extends Module<SyntaxOptions> {
|
|||||||
const container = this.quill.root.ownerDocument.createElement('div');
|
const container = this.quill.root.ownerDocument.createElement('div');
|
||||||
container.classList.add(CodeBlock.className);
|
container.classList.add(CodeBlock.className);
|
||||||
container.innerHTML = highlight(this.options.hljs, language, text);
|
container.innerHTML = highlight(this.options.hljs, language, text);
|
||||||
|
const attributes = this.quill.getFormat(
|
||||||
|
this.quill.selection.savedRange.index,
|
||||||
|
);
|
||||||
|
|
||||||
return traverse(
|
return traverse(
|
||||||
this.quill.scroll,
|
this.quill.scroll,
|
||||||
container,
|
container,
|
||||||
@ -329,6 +333,7 @@ class Syntax extends Module<SyntaxOptions> {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
new WeakMap(),
|
new WeakMap(),
|
||||||
|
attributes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import Delta from 'quill-delta';
|
import Delta from 'quill-delta';
|
||||||
import { EmbedBlot, Scope } from 'parchment';
|
import { EmbedBlot, Scope } from '@signalapp/parchment-cjs';
|
||||||
import Quill from '../core/quill.js';
|
import Quill from '../core/quill.js';
|
||||||
import logger from '../core/logger.js';
|
import logger from '../core/logger.js';
|
||||||
import Module from '../core/module.js';
|
import Module from '../core/module.js';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ParentBlot } from 'parchment';
|
import { ParentBlot } from '@signalapp/parchment-cjs';
|
||||||
import Module from '../core/module.js';
|
import Module from '../core/module.js';
|
||||||
import Quill from '../core/quill.js';
|
import Quill from '../core/quill.js';
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash';
|
||||||
import type Quill from '../core/quill.js';
|
import type Quill from '../core/quill.js';
|
||||||
import Emitter from '../core/emitter.js';
|
import Emitter from '../core/emitter.js';
|
||||||
import Theme from '../core/theme.js';
|
import Theme from '../core/theme.js';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash';
|
||||||
import Emitter from '../core/emitter.js';
|
import Emitter from '../core/emitter.js';
|
||||||
import BaseTheme, { BaseTooltip } from './base.js';
|
import BaseTheme, { BaseTooltip } from './base.js';
|
||||||
import { Range } from '../core/selection.js';
|
import { Range } from '../core/selection.js';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash';
|
||||||
import Emitter from '../core/emitter.js';
|
import Emitter from '../core/emitter.js';
|
||||||
import BaseTheme, { BaseTooltip } from './base.js';
|
import BaseTheme, { BaseTooltip } from './base.js';
|
||||||
import LinkBlot from '../formats/link.js';
|
import LinkBlot from '../formats/link.js';
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import Quill, { Delta } from '../../src/quill.js';
|
|||||||
import type { EmitterSource, Parchment, Range } from '../../src/quill.js';
|
import type { EmitterSource, Parchment, Range } from '../../src/quill.js';
|
||||||
import type { default as Block, BlockEmbed } from '../../src/blots/block.js';
|
import type { default as Block, BlockEmbed } from '../../src/blots/block.js';
|
||||||
import SnowTheme from '../../src/themes/snow.js';
|
import SnowTheme from '../../src/themes/snow.js';
|
||||||
import { LeafBlot } from 'parchment';
|
import { LeafBlot } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
{
|
{
|
||||||
const Counter = (quill: Quill, options: { unit: string }) => {
|
const Counter = (quill: Quill, options: { unit: string }) => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Registry } from 'parchment';
|
import { Registry } from '@signalapp/parchment-cjs';
|
||||||
import type { Attributor } from 'parchment';
|
import type { Attributor } from '@signalapp/parchment-cjs';
|
||||||
|
|
||||||
import Block from '../../../src/blots/block.js';
|
import Block from '../../../src/blots/block.js';
|
||||||
import Break from '../../../src/blots/break.js';
|
import Break from '../../../src/blots/break.js';
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import Editor from '../../../src/core/editor.js';
|
|||||||
import Block from '../../../src/blots/block.js';
|
import Block from '../../../src/blots/block.js';
|
||||||
import { Range } from '../../../src/core/selection.js';
|
import { Range } from '../../../src/core/selection.js';
|
||||||
import Scroll from '../../../src/blots/scroll.js';
|
import Scroll from '../../../src/blots/scroll.js';
|
||||||
import { Registry } from 'parchment';
|
import { Registry } from '@signalapp/parchment-cjs';
|
||||||
import Text from '../../../src/blots/text.js';
|
import Text from '../../../src/blots/text.js';
|
||||||
import Emitter from '../../../src/core/emitter.js';
|
import Emitter from '../../../src/core/emitter.js';
|
||||||
import Break from '../../../src/blots/break.js';
|
import Break from '../../../src/blots/break.js';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import '../../../src/quill.js';
|
import '../../../src/quill.js';
|
||||||
import Delta from 'quill-delta';
|
import Delta from 'quill-delta';
|
||||||
import { LeafBlot, Registry } from 'parchment';
|
import { LeafBlot, Registry } from '@signalapp/parchment-cjs';
|
||||||
import { afterEach, beforeEach, describe, expect, test, vitest } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, test, vitest } from 'vitest';
|
||||||
import type { MockedFunction } from 'vitest';
|
import type { MockedFunction } from 'vitest';
|
||||||
import Emitter from '../../../src/core/emitter.js';
|
import Emitter from '../../../src/core/emitter.js';
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { describe, expect, test, vitest } from 'vitest';
|
|||||||
import createRegistryWithFormats from '../../../../src/core/utils/createRegistryWithFormats.js';
|
import createRegistryWithFormats from '../../../../src/core/utils/createRegistryWithFormats.js';
|
||||||
import { globalRegistry } from '../../../../src/core/quill.js';
|
import { globalRegistry } from '../../../../src/core/quill.js';
|
||||||
import logger from '../../../../src/core/logger.js';
|
import logger from '../../../../src/core/logger.js';
|
||||||
import { Registry } from 'parchment';
|
import { Registry } from '@signalapp/parchment-cjs';
|
||||||
import Inline from '../../../../src/blots/inline.js';
|
import Inline from '../../../../src/blots/inline.js';
|
||||||
import Container from '../../../../src/blots/container.js';
|
import Container from '../../../../src/blots/container.js';
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
} from '../../../src/formats/table.js';
|
} from '../../../src/formats/table.js';
|
||||||
import Video from '../../../src/formats/video.js';
|
import Video from '../../../src/formats/video.js';
|
||||||
import { createRegistry } from '../__helpers__/factory.js';
|
import { createRegistry } from '../__helpers__/factory.js';
|
||||||
import type { RegistryDefinition } from 'parchment';
|
import type { RegistryDefinition } from '@signalapp/parchment-cjs';
|
||||||
import {
|
import {
|
||||||
DirectionAttribute,
|
DirectionAttribute,
|
||||||
DirectionClass,
|
DirectionClass,
|
||||||
|
|||||||
@ -11,11 +11,12 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"declaration": false,
|
"declaration": false,
|
||||||
"module": "ES2020",
|
"module": "CommonJS",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "node",
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"noUnusedLocals": true
|
"noUnusedLocals": true,
|
||||||
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "test/**/*"]
|
"include": ["src/**/*", "test/**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user