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/package.json CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.23.13",
3
+ "version": "1.24.0-beta.3",
4
4
  "description": "ProseMirror's view component",
5
- "main": "dist/index.js",
6
- "module": "dist/index.es.js",
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
- "ist": "^1.0.0",
27
- "mocha": "^9.1.2",
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": "FIXME autorun browser tests",
35
- "test-server": "node test/link-mocha-css.js && moduleserve test --port 8090",
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
@@ -14,6 +14,8 @@ this module.
14
14
 
15
15
  @NodeView
16
16
 
17
+ @DOMEventMap
18
+
17
19
  ### Decorations
18
20
 
19
21
  Decorations make it possible to influence the way the document is
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 browser from "./browser"
3
- import {domIndex, selectionCollapsed} from "./dom"
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.length : node.childNodes.length
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.root.getSelection()
65
- let node = sel.focusNode, offset = sel.focusOffset
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.length
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.root.getSelection()
113
- let node = sel.focusNode, offset = sel.focusOffset
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.root.getSelection()
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.childCount == 1) {
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 dom, inCode = $context.parent.type.spec.code, slice
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.appendChild(document.createElement("p"))
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.type.spec.isolating;
88
- openStart++, node = node.firstChild) {}
89
- for (let node = slice.content.lastChild; openEnd < slice.openEnd && !node.type.spec.isolating;
90
- openEnd++, node = node.lastChild) {}
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.length && addToSibling(wrap, lastWrap, node, result[result.length - 1], 0)) {
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.length)
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, wrapped.attrs)
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, node, sibling, depth) {
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, depth + 1)
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, depth - 1))
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, inner = node.content
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).fillBefore(inner, fragment.childCount > 1 || openEnd <= depth).append(inner)
164
- : inner.append(node.contentMatchAt(node.childCount).fillBefore(Fragment.empty, true))
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.type.schema, array
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