prosemirror-view 1.23.13 → 1.24.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +5733 -0
- package/dist/index.d.ts +799 -0
- package/dist/index.es.js +41 -41
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4823 -5139
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
- package/src/README.md +2 -0
- package/src/browser.ts +23 -0
- package/src/{capturekeys.js → capturekeys.ts} +38 -37
- package/src/{clipboard.js → clipboard.ts} +44 -41
- package/src/{decoration.js → decoration.ts} +313 -268
- package/src/{dom.js → dom.ts} +27 -24
- package/src/{domchange.js → domchange.ts} +38 -36
- package/src/{domcoords.js → domcoords.ts} +120 -99
- package/src/{domobserver.js → domobserver.ts} +41 -28
- package/src/index.ts +705 -0
- package/src/{input.js → input.ts} +203 -183
- package/src/{selection.js → selection.ts} +54 -48
- package/src/{viewdesc.js → viewdesc.ts} +342 -336
- package/rollup.config.js +0 -14
- package/src/browser.js +0 -23
- package/src/index.js +0 -668
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prosemirror-view",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0-beta.3",
|
|
4
4
|
"description": "ProseMirror's view component",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
},
|
|
13
|
+
"sideEffects": false,
|
|
7
14
|
"style": "style/prosemirror.css",
|
|
8
15
|
"license": "MIT",
|
|
9
16
|
"maintainers": [
|
|
@@ -23,18 +30,11 @@
|
|
|
23
30
|
"prosemirror-transform": "^1.1.0"
|
|
24
31
|
},
|
|
25
32
|
"devDependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"moduleserve": "^0.7.0",
|
|
29
|
-
"prosemirror-test-builder": "^1.0.0",
|
|
30
|
-
"rollup": "^2.26.3",
|
|
31
|
-
"@rollup/plugin-buble": "^0.21.3"
|
|
33
|
+
"@prosemirror/buildhelper": "^0.1.5",
|
|
34
|
+
"prosemirror-test-builder": "^1.0.0"
|
|
32
35
|
},
|
|
33
36
|
"scripts": {
|
|
34
|
-
"test": "
|
|
35
|
-
"
|
|
36
|
-
"build": "rollup -c",
|
|
37
|
-
"watch": "rollup -c -w",
|
|
38
|
-
"prepare": "npm run build"
|
|
37
|
+
"test": "pm-runtests",
|
|
38
|
+
"prepare": "pm-buildhelper src/index.ts"
|
|
39
39
|
}
|
|
40
40
|
}
|
package/src/README.md
CHANGED
package/src/browser.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const nav = typeof navigator != "undefined" ? navigator : null
|
|
2
|
+
const doc = typeof document != "undefined" ? document : null
|
|
3
|
+
const agent = (nav && nav.userAgent) || ""
|
|
4
|
+
|
|
5
|
+
const ie_edge = /Edge\/(\d+)/.exec(agent)
|
|
6
|
+
const ie_upto10 = /MSIE \d/.exec(agent)
|
|
7
|
+
const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent)
|
|
8
|
+
|
|
9
|
+
export const ie = !!(ie_upto10 || ie_11up || ie_edge)
|
|
10
|
+
export const ie_version = ie_upto10 ? (document as any).documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0
|
|
11
|
+
export const gecko = !ie && /gecko\/(\d+)/i.test(agent)
|
|
12
|
+
export const gecko_version = gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1]
|
|
13
|
+
|
|
14
|
+
const _chrome = !ie && /Chrome\/(\d+)/.exec(agent)
|
|
15
|
+
export const chrome = !!_chrome
|
|
16
|
+
export const chrome_version = _chrome ? +_chrome[1] : 0
|
|
17
|
+
export const safari = !ie && !!nav && /Apple Computer/.test(nav.vendor)
|
|
18
|
+
// Is true for both iOS and iPadOS for convenience
|
|
19
|
+
export const ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2)
|
|
20
|
+
export const mac = ios || (nav ? /Mac/.test(nav.platform) : false)
|
|
21
|
+
export const android = /Android \d/.test(agent)
|
|
22
|
+
export const webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style
|
|
23
|
+
export const webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import {Selection, NodeSelection, TextSelection, AllSelection} from "prosemirror-state"
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import {Selection, NodeSelection, TextSelection, AllSelection, EditorState} from "prosemirror-state"
|
|
2
|
+
import {EditorView} from "./index"
|
|
3
|
+
import * as browser from "./browser"
|
|
4
|
+
import {domIndex, selectionCollapsed, DOMSelection} from "./dom"
|
|
4
5
|
import {selectionToDOM} from "./selection"
|
|
5
6
|
|
|
6
|
-
function moveSelectionBlock(state, dir) {
|
|
7
|
+
function moveSelectionBlock(state: EditorState, dir: number) {
|
|
7
8
|
let {$anchor, $head} = state.selection
|
|
8
9
|
let $side = dir > 0 ? $anchor.max($head) : $anchor.min($head)
|
|
9
10
|
let $start = !$side.parent.inlineContent ? $side : $side.depth ? state.doc.resolve(dir > 0 ? $side.after() : $side.before()) : null
|
|
10
11
|
return $start && Selection.findFrom($start, dir)
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
function apply(view, sel) {
|
|
14
|
+
function apply(view: EditorView, sel: Selection) {
|
|
14
15
|
view.dispatch(view.state.tr.setSelection(sel).scrollIntoView())
|
|
15
16
|
return true
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
function selectHorizontally(view, dir, mods) {
|
|
19
|
+
function selectHorizontally(view: EditorView, dir: number, mods: string) {
|
|
19
20
|
let sel = view.state.selection
|
|
20
21
|
if (sel instanceof TextSelection) {
|
|
21
22
|
if (!sel.empty || mods.indexOf("s") > -1) {
|
|
@@ -49,22 +50,22 @@ function selectHorizontally(view, dir, mods) {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
function nodeLen(node) {
|
|
53
|
-
return node.nodeType == 3 ? node.nodeValue
|
|
53
|
+
function nodeLen(node: Node) {
|
|
54
|
+
return node.nodeType == 3 ? node.nodeValue!.length : node.childNodes.length
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
function isIgnorable(dom) {
|
|
57
|
+
function isIgnorable(dom: Node) {
|
|
57
58
|
let desc = dom.pmViewDesc
|
|
58
59
|
return desc && desc.size == 0 && (dom.nextSibling || dom.nodeName != "BR")
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
// Make sure the cursor isn't directly after one or more ignored
|
|
62
63
|
// nodes, which will confuse the browser's cursor motion logic.
|
|
63
|
-
function skipIgnoredNodesLeft(view) {
|
|
64
|
-
let sel = view.
|
|
65
|
-
let node = sel.focusNode
|
|
64
|
+
function skipIgnoredNodesLeft(view: EditorView) {
|
|
65
|
+
let sel = view.domSelection()
|
|
66
|
+
let node = sel.focusNode!, offset = sel.focusOffset
|
|
66
67
|
if (!node) return
|
|
67
|
-
let moveNode, moveOffset, force = false
|
|
68
|
+
let moveNode, moveOffset: number | undefined, force = false
|
|
68
69
|
// Gecko will do odd things when the selection is directly in front
|
|
69
70
|
// of a non-editable node, so in that case, move it into the next
|
|
70
71
|
// node if possible. Issue prosemirror/prosemirror#832.
|
|
@@ -80,7 +81,7 @@ function skipIgnoredNodesLeft(view) {
|
|
|
80
81
|
moveOffset = --offset
|
|
81
82
|
} else if (before.nodeType == 3) {
|
|
82
83
|
node = before
|
|
83
|
-
offset = node.nodeValue
|
|
84
|
+
offset = node.nodeValue!.length
|
|
84
85
|
} else break
|
|
85
86
|
}
|
|
86
87
|
} else if (isBlockNode(node)) {
|
|
@@ -93,7 +94,7 @@ function skipIgnoredNodesLeft(view) {
|
|
|
93
94
|
prev = prev.previousSibling
|
|
94
95
|
}
|
|
95
96
|
if (!prev) {
|
|
96
|
-
node = node.parentNode
|
|
97
|
+
node = node.parentNode!
|
|
97
98
|
if (node == view.dom) break
|
|
98
99
|
offset = 0
|
|
99
100
|
} else {
|
|
@@ -103,17 +104,17 @@ function skipIgnoredNodesLeft(view) {
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
if (force) setSelFocus(view, sel, node, offset)
|
|
106
|
-
else if (moveNode) setSelFocus(view, sel, moveNode, moveOffset)
|
|
107
|
+
else if (moveNode) setSelFocus(view, sel, moveNode, moveOffset!)
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
// Make sure the cursor isn't directly before one or more ignored
|
|
110
111
|
// nodes.
|
|
111
|
-
function skipIgnoredNodesRight(view) {
|
|
112
|
-
let sel = view.
|
|
113
|
-
let node = sel.focusNode
|
|
112
|
+
function skipIgnoredNodesRight(view: EditorView) {
|
|
113
|
+
let sel = view.domSelection()
|
|
114
|
+
let node = sel.focusNode!, offset = sel.focusOffset
|
|
114
115
|
if (!node) return
|
|
115
116
|
let len = nodeLen(node)
|
|
116
|
-
let moveNode, moveOffset
|
|
117
|
+
let moveNode, moveOffset: number | undefined
|
|
117
118
|
for (;;) {
|
|
118
119
|
if (offset < len) {
|
|
119
120
|
if (node.nodeType != 1) break
|
|
@@ -133,7 +134,7 @@ function skipIgnoredNodesRight(view) {
|
|
|
133
134
|
next = next.nextSibling
|
|
134
135
|
}
|
|
135
136
|
if (!next) {
|
|
136
|
-
node = node.parentNode
|
|
137
|
+
node = node.parentNode!
|
|
137
138
|
if (node == view.dom) break
|
|
138
139
|
offset = len = 0
|
|
139
140
|
} else {
|
|
@@ -143,15 +144,15 @@ function skipIgnoredNodesRight(view) {
|
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
|
-
if (moveNode) setSelFocus(view, sel, moveNode, moveOffset)
|
|
147
|
+
if (moveNode) setSelFocus(view, sel, moveNode, moveOffset!)
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
function isBlockNode(dom) {
|
|
150
|
+
function isBlockNode(dom: Node) {
|
|
150
151
|
let desc = dom.pmViewDesc
|
|
151
152
|
return desc && desc.node && desc.node.isBlock
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
function setSelFocus(view, sel, node, offset) {
|
|
155
|
+
function setSelFocus(view: EditorView, sel: DOMSelection, node: Node, offset: number) {
|
|
155
156
|
if (selectionCollapsed(sel)) {
|
|
156
157
|
let range = document.createRange()
|
|
157
158
|
range.setEnd(node, offset)
|
|
@@ -169,11 +170,10 @@ function setSelFocus(view, sel, node, offset) {
|
|
|
169
170
|
}, 50)
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
// : (EditorState, number)
|
|
173
173
|
// Check whether vertical selection motion would involve node
|
|
174
174
|
// selections. If so, apply it (if not, the result is left to the
|
|
175
175
|
// browser)
|
|
176
|
-
function selectVertically(view, dir, mods) {
|
|
176
|
+
function selectVertically(view: EditorView, dir: number, mods: string) {
|
|
177
177
|
let sel = view.state.selection
|
|
178
178
|
if (sel instanceof TextSelection && !sel.empty || mods.indexOf("s") > -1) return false
|
|
179
179
|
if (browser.mac && mods.indexOf("m") > -1) return false
|
|
@@ -192,7 +192,7 @@ function selectVertically(view, dir, mods) {
|
|
|
192
192
|
return false
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
function stopNativeHorizontalDelete(view, dir) {
|
|
195
|
+
function stopNativeHorizontalDelete(view: EditorView, dir: number) {
|
|
196
196
|
if (!(view.state.selection instanceof TextSelection)) return true
|
|
197
197
|
let {$head, $anchor, empty} = view.state.selection
|
|
198
198
|
if (!$head.sameParent($anchor)) return true
|
|
@@ -209,7 +209,7 @@ function stopNativeHorizontalDelete(view, dir) {
|
|
|
209
209
|
return false
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
function switchEditable(view, node, state) {
|
|
212
|
+
function switchEditable(view: EditorView, node: HTMLElement, state: string) {
|
|
213
213
|
view.domObserver.stop()
|
|
214
214
|
node.contentEditable = state
|
|
215
215
|
view.domObserver.start()
|
|
@@ -220,15 +220,16 @@ function switchEditable(view, node, state) {
|
|
|
220
220
|
// wrong things when the down arrow is pressed when the cursor is
|
|
221
221
|
// directly at the start of a textblock and has an uneditable node
|
|
222
222
|
// after it
|
|
223
|
-
function safariDownArrowBug(view) {
|
|
224
|
-
if (!browser.safari || view.state.selection.$head.parentOffset > 0) return
|
|
225
|
-
let {focusNode, focusOffset} = view.
|
|
223
|
+
function safariDownArrowBug(view: EditorView) {
|
|
224
|
+
if (!browser.safari || view.state.selection.$head.parentOffset > 0) return false
|
|
225
|
+
let {focusNode, focusOffset} = view.domSelection()
|
|
226
226
|
if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
|
|
227
|
-
focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
|
|
228
|
-
let child = focusNode.firstChild
|
|
229
|
-
switchEditable(view, child, true)
|
|
230
|
-
setTimeout(() => switchEditable(view, child, false), 20)
|
|
227
|
+
focusNode.firstChild && (focusNode.firstChild as HTMLElement).contentEditable == "false") {
|
|
228
|
+
let child = focusNode.firstChild as HTMLElement
|
|
229
|
+
switchEditable(view, child, "true")
|
|
230
|
+
setTimeout(() => switchEditable(view, child, "false"), 20)
|
|
231
231
|
}
|
|
232
|
+
return false
|
|
232
233
|
}
|
|
233
234
|
|
|
234
235
|
// A backdrop key mapping used to make sure we always suppress keys
|
|
@@ -238,7 +239,7 @@ function safariDownArrowBug(view) {
|
|
|
238
239
|
// cursor-motion keys, the code in the handlers also takes care of
|
|
239
240
|
// block selections.
|
|
240
241
|
|
|
241
|
-
function getMods(event) {
|
|
242
|
+
function getMods(event: KeyboardEvent) {
|
|
242
243
|
let result = ""
|
|
243
244
|
if (event.ctrlKey) result += "c"
|
|
244
245
|
if (event.metaKey) result += "m"
|
|
@@ -247,7 +248,7 @@ function getMods(event) {
|
|
|
247
248
|
return result
|
|
248
249
|
}
|
|
249
250
|
|
|
250
|
-
export function captureKeyDown(view, event) {
|
|
251
|
+
export function captureKeyDown(view: EditorView, event: KeyboardEvent) {
|
|
251
252
|
let code = event.keyCode, mods = getMods(event)
|
|
252
253
|
if (code == 8 || (browser.mac && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac
|
|
253
254
|
return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodesLeft(view)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {Slice, Fragment, DOMParser, DOMSerializer} from "prosemirror-model"
|
|
2
|
-
import browser from "./browser"
|
|
1
|
+
import {Slice, Fragment, DOMParser, DOMSerializer, ResolvedPos, NodeType, Node} from "prosemirror-model"
|
|
2
|
+
import * as browser from "./browser"
|
|
3
|
+
import {EditorView} from "./index"
|
|
3
4
|
|
|
4
|
-
export function serializeForClipboard(view, slice) {
|
|
5
|
+
export function serializeForClipboard(view: EditorView, slice: Slice) {
|
|
5
6
|
let context = [], {content, openStart, openEnd} = slice
|
|
6
|
-
while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild
|
|
7
|
+
while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild!.childCount == 1) {
|
|
7
8
|
openStart--
|
|
8
9
|
openEnd--
|
|
9
|
-
let node = content.firstChild
|
|
10
|
+
let node = content.firstChild!
|
|
10
11
|
context.push(node.type.name, node.attrs != node.type.defaultAttrs ? node.attrs : null)
|
|
11
12
|
content = node.content
|
|
12
13
|
}
|
|
@@ -30,7 +31,7 @@ export function serializeForClipboard(view, slice) {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
if (firstChild && firstChild.nodeType == 1)
|
|
33
|
-
firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd} ${JSON.stringify(context)}`)
|
|
34
|
+
(firstChild as HTMLElement).setAttribute("data-pm-slice", `${openStart} ${openEnd} ${JSON.stringify(context)}`)
|
|
34
35
|
|
|
35
36
|
let text = view.someProp("clipboardTextSerializer", f => f(slice)) ||
|
|
36
37
|
slice.content.textBetween(0, slice.content.size, "\n\n")
|
|
@@ -38,10 +39,10 @@ export function serializeForClipboard(view, slice) {
|
|
|
38
39
|
return {dom: wrap, text}
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
// : (EditorView, string, string, ?bool, ResolvedPos) → ?Slice
|
|
42
42
|
// Read a slice of content from the clipboard (or drop data).
|
|
43
|
-
export function parseFromClipboard(view, text, html, plainText, $context) {
|
|
44
|
-
let
|
|
43
|
+
export function parseFromClipboard(view: EditorView, text: string, html: string | null, plainText: boolean, $context: ResolvedPos) {
|
|
44
|
+
let inCode = $context.parent.type.spec.code
|
|
45
|
+
let dom: HTMLElement | undefined, slice: Slice | undefined
|
|
45
46
|
if (!html && !text) return null
|
|
46
47
|
let asText = text && (plainText || inCode || !html)
|
|
47
48
|
if (asText) {
|
|
@@ -55,26 +56,27 @@ export function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
55
56
|
let {schema} = view.state, serializer = DOMSerializer.fromSchema(schema)
|
|
56
57
|
dom = document.createElement("div")
|
|
57
58
|
text.split(/(?:\r\n?|\n)+/).forEach(block => {
|
|
58
|
-
let p = dom
|
|
59
|
+
let p = dom!.appendChild(document.createElement("p"))
|
|
59
60
|
if (block) p.appendChild(serializer.serializeNode(schema.text(block, marks)))
|
|
60
61
|
})
|
|
61
62
|
}
|
|
62
63
|
} else {
|
|
63
|
-
view.someProp("transformPastedHTML", f => { html = f(html) })
|
|
64
|
-
dom = readHTML(html)
|
|
64
|
+
view.someProp("transformPastedHTML", f => { html = f(html!) })
|
|
65
|
+
dom = readHTML(html!)
|
|
65
66
|
if (browser.webkit) restoreReplacedSpaces(dom)
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
let contextNode = dom && dom.querySelector("[data-pm-slice]")
|
|
69
|
-
let sliceData = contextNode && /^(\d+) (\d+) (.*)/.exec(contextNode.getAttribute("data-pm-slice"))
|
|
70
|
+
let sliceData = contextNode && /^(\d+) (\d+) (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "")
|
|
70
71
|
if (!slice) {
|
|
71
72
|
let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema)
|
|
72
|
-
slice = parser.parseSlice(dom
|
|
73
|
+
slice = parser.parseSlice(dom!, {
|
|
73
74
|
preserveWhitespace: !!(asText || sliceData),
|
|
74
75
|
context: $context,
|
|
75
76
|
ruleFromNode(dom) {
|
|
76
77
|
if (dom.nodeName == "BR" && !dom.nextSibling &&
|
|
77
78
|
dom.parentNode && !inlineParents.test(dom.parentNode.nodeName)) return {ignore: true}
|
|
79
|
+
return null
|
|
78
80
|
}
|
|
79
81
|
})
|
|
80
82
|
}
|
|
@@ -84,15 +86,15 @@ export function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
84
86
|
slice = Slice.maxOpen(normalizeSiblings(slice.content, $context), true)
|
|
85
87
|
if (slice.openStart || slice.openEnd) {
|
|
86
88
|
let openStart = 0, openEnd = 0
|
|
87
|
-
for (let node = slice.content.firstChild; openStart < slice.openStart && !node
|
|
88
|
-
openStart++, node = node
|
|
89
|
-
for (let node = slice.content.lastChild; openEnd < slice.openEnd && !node
|
|
90
|
-
openEnd++, node = node
|
|
89
|
+
for (let node = slice.content.firstChild; openStart < slice.openStart && !node!.type.spec.isolating;
|
|
90
|
+
openStart++, node = node!.firstChild) {}
|
|
91
|
+
for (let node = slice.content.lastChild; openEnd < slice.openEnd && !node!.type.spec.isolating;
|
|
92
|
+
openEnd++, node = node!.lastChild) {}
|
|
91
93
|
slice = closeSlice(slice, openStart, openEnd)
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
view.someProp("transformPasted", f => { slice = f(slice) })
|
|
97
|
+
view.someProp("transformPasted", f => { slice = f(slice!) })
|
|
96
98
|
return slice
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -106,23 +108,23 @@ const inlineParents = /^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|outpu
|
|
|
106
108
|
// This addresses the problem that Transform.replace expects a
|
|
107
109
|
// coherent slice, and will fail to place a set of siblings that don't
|
|
108
110
|
// fit anywhere in the schema.
|
|
109
|
-
function normalizeSiblings(fragment, $context) {
|
|
111
|
+
function normalizeSiblings(fragment: Fragment, $context: ResolvedPos) {
|
|
110
112
|
if (fragment.childCount < 2) return fragment
|
|
111
113
|
for (let d = $context.depth; d >= 0; d--) {
|
|
112
114
|
let parent = $context.node(d)
|
|
113
115
|
let match = parent.contentMatchAt($context.index(d))
|
|
114
|
-
let lastWrap, result = []
|
|
116
|
+
let lastWrap: readonly NodeType[] | undefined, result: Node[] | null = []
|
|
115
117
|
fragment.forEach(node => {
|
|
116
118
|
if (!result) return
|
|
117
119
|
let wrap = match.findWrapping(node.type), inLast
|
|
118
120
|
if (!wrap) return result = null
|
|
119
|
-
if (inLast = result.length && lastWrap
|
|
121
|
+
if (inLast = result.length && lastWrap!.length && addToSibling(wrap, lastWrap!, node, result[result.length - 1], 0)) {
|
|
120
122
|
result[result.length - 1] = inLast
|
|
121
123
|
} else {
|
|
122
|
-
if (result.length) result[result.length - 1] = closeRight(result[result.length - 1], lastWrap
|
|
124
|
+
if (result.length) result[result.length - 1] = closeRight(result[result.length - 1], lastWrap!.length)
|
|
123
125
|
let wrapped = withWrappers(node, wrap)
|
|
124
126
|
result.push(wrapped)
|
|
125
|
-
match = match.matchType(wrapped.type
|
|
127
|
+
match = match.matchType(wrapped.type)!
|
|
126
128
|
lastWrap = wrap
|
|
127
129
|
}
|
|
128
130
|
})
|
|
@@ -131,7 +133,7 @@ function normalizeSiblings(fragment, $context) {
|
|
|
131
133
|
return fragment
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
function withWrappers(node, wrap, from = 0) {
|
|
136
|
+
function withWrappers(node: Node, wrap: readonly NodeType[], from = 0) {
|
|
135
137
|
for (let i = wrap.length - 1; i >= from; i--)
|
|
136
138
|
node = wrap[i].create(null, Fragment.from(node))
|
|
137
139
|
return node
|
|
@@ -139,9 +141,10 @@ function withWrappers(node, wrap, from = 0) {
|
|
|
139
141
|
|
|
140
142
|
// Used to group adjacent nodes wrapped in similar parents by
|
|
141
143
|
// normalizeSiblings into the same parent node
|
|
142
|
-
function addToSibling(wrap, lastWrap
|
|
144
|
+
function addToSibling(wrap: readonly NodeType[], lastWrap: readonly NodeType[],
|
|
145
|
+
node: Node, sibling: Node, depth: number): Node | undefined {
|
|
143
146
|
if (depth < wrap.length && depth < lastWrap.length && wrap[depth] == lastWrap[depth]) {
|
|
144
|
-
let inner = addToSibling(wrap, lastWrap, node, sibling.lastChild
|
|
147
|
+
let inner = addToSibling(wrap, lastWrap, node, sibling.lastChild!, depth + 1)
|
|
145
148
|
if (inner) return sibling.copy(sibling.content.replaceChild(sibling.childCount - 1, inner))
|
|
146
149
|
let match = sibling.contentMatchAt(sibling.childCount)
|
|
147
150
|
if (match.matchType(depth == wrap.length - 1 ? node.type : wrap[depth + 1]))
|
|
@@ -149,23 +152,23 @@ function addToSibling(wrap, lastWrap, node, sibling, depth) {
|
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
|
|
152
|
-
function closeRight(node, depth) {
|
|
155
|
+
function closeRight(node: Node, depth: number) {
|
|
153
156
|
if (depth == 0) return node
|
|
154
|
-
let fragment = node.content.replaceChild(node.childCount - 1, closeRight(node.lastChild
|
|
155
|
-
let fill = node.contentMatchAt(node.childCount).fillBefore(Fragment.empty, true)
|
|
157
|
+
let fragment = node.content.replaceChild(node.childCount - 1, closeRight(node.lastChild!, depth - 1))
|
|
158
|
+
let fill = node.contentMatchAt(node.childCount).fillBefore(Fragment.empty, true)!
|
|
156
159
|
return node.copy(fragment.append(fill))
|
|
157
160
|
}
|
|
158
161
|
|
|
159
|
-
function closeRange(fragment, side, from, to, depth, openEnd) {
|
|
160
|
-
let node = side < 0 ? fragment.firstChild : fragment.lastChild
|
|
162
|
+
function closeRange(fragment: Fragment, side: number, from: number, to: number, depth: number, openEnd: number) {
|
|
163
|
+
let node = side < 0 ? fragment.firstChild! : fragment.lastChild!, inner = node.content
|
|
161
164
|
if (depth < to - 1) inner = closeRange(inner, side, from, to, depth + 1, openEnd)
|
|
162
165
|
if (depth >= from)
|
|
163
|
-
inner = side < 0 ? node.contentMatchAt(0)
|
|
164
|
-
: inner.append(node.contentMatchAt(node.childCount)
|
|
166
|
+
inner = side < 0 ? node.contentMatchAt(0)!.fillBefore(inner, fragment.childCount > 1 || openEnd <= depth)!.append(inner)
|
|
167
|
+
: inner.append(node.contentMatchAt(node.childCount)!.fillBefore(Fragment.empty, true)!)
|
|
165
168
|
return fragment.replaceChild(side < 0 ? 0 : fragment.childCount - 1, node.copy(inner))
|
|
166
169
|
}
|
|
167
170
|
|
|
168
|
-
function closeSlice(slice, openStart, openEnd) {
|
|
171
|
+
function closeSlice(slice: Slice, openStart: number, openEnd: number) {
|
|
169
172
|
if (openStart < slice.openStart)
|
|
170
173
|
slice = new Slice(closeRange(slice.content, -1, openStart, slice.openStart, 0, slice.openEnd), openStart, slice.openEnd)
|
|
171
174
|
if (openEnd < slice.openEnd)
|
|
@@ -176,7 +179,7 @@ function closeSlice(slice, openStart, openEnd) {
|
|
|
176
179
|
// Trick from jQuery -- some elements must be wrapped in other
|
|
177
180
|
// elements for innerHTML to work. I.e. if you do `div.innerHTML =
|
|
178
181
|
// "<td>..</td>"` the table cells are ignored.
|
|
179
|
-
const wrapMap = {
|
|
182
|
+
const wrapMap: {[node: string]: string[]} = {
|
|
180
183
|
thead: ["table"],
|
|
181
184
|
tbody: ["table"],
|
|
182
185
|
tfoot: ["table"],
|
|
@@ -188,12 +191,12 @@ const wrapMap = {
|
|
|
188
191
|
th: ["table", "tbody", "tr"]
|
|
189
192
|
}
|
|
190
193
|
|
|
191
|
-
let _detachedDoc = null
|
|
194
|
+
let _detachedDoc: Document | null = null
|
|
192
195
|
function detachedDoc() {
|
|
193
196
|
return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"))
|
|
194
197
|
}
|
|
195
198
|
|
|
196
|
-
function readHTML(html) {
|
|
199
|
+
function readHTML(html: string) {
|
|
197
200
|
let metas = /^(\s*<meta [^>]*>)*/.exec(html)
|
|
198
201
|
if (metas) html = html.slice(metas[0].length)
|
|
199
202
|
let elt = detachedDoc().createElement("div")
|
|
@@ -210,7 +213,7 @@ function readHTML(html) {
|
|
|
210
213
|
// clipboard. This tries to convert such non-breaking spaces (which
|
|
211
214
|
// will be wrapped in a plain span on Chrome, a span with class
|
|
212
215
|
// Apple-converted-space on Safari) back to regular spaces.
|
|
213
|
-
function restoreReplacedSpaces(dom) {
|
|
216
|
+
function restoreReplacedSpaces(dom: HTMLElement) {
|
|
214
217
|
let nodes = dom.querySelectorAll(browser.chrome ? "span:not([class]):not([style])" : "span.Apple-converted-space")
|
|
215
218
|
for (let i = 0; i < nodes.length; i++) {
|
|
216
219
|
let node = nodes[i]
|
|
@@ -219,9 +222,9 @@ function restoreReplacedSpaces(dom) {
|
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
224
|
|
|
222
|
-
function addContext(slice, context) {
|
|
225
|
+
function addContext(slice: Slice, context: string) {
|
|
223
226
|
if (!slice.size) return slice
|
|
224
|
-
let schema = slice.content.firstChild
|
|
227
|
+
let schema = slice.content.firstChild!.type.schema, array
|
|
225
228
|
try { array = JSON.parse(context) }
|
|
226
229
|
catch(e) { return slice }
|
|
227
230
|
let {content, openStart, openEnd} = slice
|