prosemirror-view
Advanced tools
Comparing version 1.27.0 to 1.27.1
@@ -699,4 +699,4 @@ import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state'; | ||
/** | ||
Can be used to transform pasted content before it is applied to | ||
the document. | ||
Can be used to transform pasted or dragged-and-dropped content | ||
before it is applied to the document. | ||
*/ | ||
@@ -703,0 +703,0 @@ transformPasted?: (this: P, slice: Slice) => Slice; |
{ | ||
"name": "prosemirror-view", | ||
"version": "1.27.0", | ||
"version": "1.27.1", | ||
"description": "ProseMirror's view component", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -553,16 +553,20 @@ import {Node, Mark} from "prosemirror-model" | ||
// move those that are after the changes. | ||
let shift = (oldStart: number, oldEnd: number, newStart: number, newEnd: number) => { | ||
for (let i = 0; i < children.length; i += 3) { | ||
let end = children[i + 1] as number, dSize | ||
if (end < 0 || oldStart > end + oldOffset) continue | ||
let start = (children[i] as number) + oldOffset | ||
if (oldEnd >= start) { | ||
children[i + 1] = oldStart <= start ? -2 : -1 | ||
} else if (newStart >= offset && (dSize = (newEnd - newStart) - (oldEnd - oldStart))) { | ||
;(children[i] as number) += dSize | ||
;(children[i + 1] as number) += dSize | ||
for (let i = 0; i < mapping.maps.length; i++) { | ||
let moved = 0 | ||
mapping.maps[i].forEach((oldStart: number, oldEnd: number, newStart: number, newEnd: number) => { | ||
let dSize = (newEnd - newStart) - (oldEnd - oldStart) | ||
for (let i = 0; i < children.length; i += 3) { | ||
let end = children[i + 1] as number | ||
if (end < 0 || oldStart > end + oldOffset - moved) continue | ||
let start = (children[i] as number) + oldOffset - moved | ||
if (oldEnd >= start) { | ||
children[i + 1] = oldStart <= start ? -2 : -1 | ||
} else if (newStart >= offset && dSize) { | ||
;(children[i] as number) += dSize | ||
;(children[i + 1] as number) += dSize | ||
} | ||
} | ||
} | ||
moved += dSize | ||
}) | ||
} | ||
for (let i = 0; i < mapping.maps.length; i++) mapping.maps[i].forEach(shift) | ||
@@ -569,0 +573,0 @@ // Find the child nodes that still correspond to a single node, |
@@ -344,3 +344,3 @@ import {EditorState} from "prosemirror-state" | ||
else { to ++ } | ||
return flattenV(singleRect(textRange(node as Text, from, to), takeSide), takeSide < 0) | ||
return flattenV(singleRect(textRange(node as Text, from, to), 1), takeSide < 0) | ||
} | ||
@@ -347,0 +347,0 @@ } |
@@ -0,4 +1,5 @@ | ||
import {Selection} from "prosemirror-state" | ||
import * as browser from "./browser" | ||
import {domIndex, isEquivalentPosition} from "./dom" | ||
import {hasFocusAndSelection, selectionToDOM} from "./selection" | ||
import {domIndex, isEquivalentPosition, selectionCollapsed, DOMSelection} from "./dom" | ||
import {hasFocusAndSelection, selectionToDOM, selectionFromDOM} from "./selection" | ||
import {EditorView} from "./index" | ||
@@ -23,3 +24,3 @@ | ||
set(sel: Selection) { | ||
set(sel: DOMSelection) { | ||
this.anchorNode = sel.anchorNode; this.anchorOffset = sel.anchorOffset | ||
@@ -33,3 +34,3 @@ this.focusNode = sel.focusNode; this.focusOffset = sel.focusOffset | ||
eq(sel: Selection) { | ||
eq(sel: DOMSelection) { | ||
return sel.anchorNode == this.anchorNode && sel.anchorOffset == this.anchorOffset && | ||
@@ -143,3 +144,3 @@ sel.focusNode == this.focusNode && sel.focusOffset == this.focusOffset | ||
ignoreSelectionChange(sel: Selection) { | ||
ignoreSelectionChange(sel: DOMSelection) { | ||
if (sel.rangeCount == 0) return true | ||
@@ -158,3 +159,4 @@ let container = sel.getRangeAt(0).commonAncestorContainer | ||
flush() { | ||
if (!this.view.docView || this.flushingSoon > -1) return | ||
let {view} = this | ||
if (!view.docView || this.flushingSoon > -1) return | ||
let mutations = this.observer ? this.observer.takeRecords() : [] | ||
@@ -166,7 +168,7 @@ if (this.queue.length) { | ||
let sel = this.view.domSelection() | ||
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel) | ||
let sel = view.domSelection() | ||
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel) | ||
let from = -1, to = -1, typeOver = false, added: Node[] = [] | ||
if (this.view.editable) { | ||
if (view.editable) { | ||
for (let i = 0; i < mutations.length; i++) { | ||
@@ -191,10 +193,22 @@ let result = this.registerMutation(mutations[i], added) | ||
if (from > -1 || newSel) { | ||
let readSel: Selection | null = null | ||
// If it looks like the browser has reset the selection to the | ||
// start of the document after focus, restore the selection from | ||
// the state | ||
if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 && | ||
view.input.lastTouch < Date.now() - 300 && | ||
selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) && | ||
readSel.eq(Selection.near(view.state.doc.resolve(0), 1))) { | ||
view.input.lastFocus = 0 | ||
selectionToDOM(view) | ||
this.currentSelection.set(sel) | ||
view.scrollToSelection() | ||
} else if (from > -1 || newSel) { | ||
if (from > -1) { | ||
this.view.docView.markDirty(from, to) | ||
checkCSS(this.view) | ||
view.docView.markDirty(from, to) | ||
checkCSS(view) | ||
} | ||
this.handleDOMChange(from, to, typeOver, added) | ||
if (this.view.docView && this.view.docView.dirty) this.view.updateState(this.view.state) | ||
else if (!this.currentSelection.eq(sel)) selectionToDOM(this.view) | ||
if (view.docView && view.docView.dirty) view.updateState(view.state) | ||
else if (!this.currentSelection.eq(sel)) selectionToDOM(view) | ||
this.currentSelection.set(sel) | ||
@@ -252,9 +266,14 @@ } | ||
let cssChecked = false | ||
let cssChecked: WeakMap<EditorView, null> = new WeakMap() | ||
let cssCheckWarned: boolean = false | ||
function checkCSS(view: EditorView) { | ||
if (cssChecked) return | ||
cssChecked = true | ||
if (getComputedStyle(view.dom).whiteSpace == "normal") | ||
if (cssChecked.has(view)) return | ||
cssChecked.set(view, null) | ||
if (['normal', 'nowrap', 'pre-line'].indexOf(getComputedStyle(view.dom).whiteSpace) !== -1) { | ||
view.requiresGeckoHackNode = browser.gecko | ||
if (cssCheckWarned) return | ||
console["warn"]("ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package.") | ||
cssCheckWarned = true | ||
} | ||
} |
@@ -56,2 +56,6 @@ import {NodeSelection, EditorState, Plugin, PluginView, Transaction, Selection} from "prosemirror-state" | ||
domObserver!: DOMObserver | ||
/// Holds `true` when a hack node is needed in Firefox to prevent the | ||
/// [space is eaten issue](https://github.com/ProseMirror/prosemirror/issues/651) | ||
/// @internal | ||
requiresGeckoHackNode: boolean = false | ||
@@ -218,11 +222,3 @@ /// The view's current [state](#state.EditorState). | ||
} else if (scroll == "to selection") { | ||
let startDOM = this.domSelection().focusNode! | ||
if (this.someProp("handleScrollToSelection", f => f(this))) { | ||
// Handled | ||
} else if (state.selection instanceof NodeSelection) { | ||
let target = this.docView.domAfterPos(state.selection.from) | ||
if (target.nodeType == 1) scrollRectIntoView(this, (target as HTMLElement).getBoundingClientRect(), startDOM) | ||
} else { | ||
scrollRectIntoView(this, this.coordsAtPos(state.selection.head, 1), startDOM) | ||
} | ||
this.scrollToSelection() | ||
} else if (oldScrollPos) { | ||
@@ -233,2 +229,15 @@ resetScrollPos(oldScrollPos) | ||
/// @internal | ||
scrollToSelection() { | ||
let startDOM = this.domSelection().focusNode! | ||
if (this.someProp("handleScrollToSelection", f => f(this))) { | ||
// Handled | ||
} else if (this.state.selection instanceof NodeSelection) { | ||
let target = this.docView.domAfterPos(this.state.selection.from) | ||
if (target.nodeType == 1) scrollRectIntoView(this, (target as HTMLElement).getBoundingClientRect(), startDOM) | ||
} else { | ||
scrollRectIntoView(this, this.coordsAtPos(this.state.selection.head, 1), startDOM) | ||
} | ||
} | ||
private destroyPluginViews() { | ||
@@ -629,4 +638,4 @@ let view | ||
/// Can be used to transform pasted content before it is applied to | ||
/// the document. | ||
/// Can be used to transform pasted or dragged-and-dropped content | ||
/// before it is applied to the document. | ||
transformPasted?: (this: P, slice: Slice) => Slice | ||
@@ -633,0 +642,0 @@ |
@@ -16,3 +16,4 @@ import {Selection, NodeSelection, TextSelection} from "prosemirror-state" | ||
const handlers: {[event: string]: (view: EditorView, event: Event) => void} = {} | ||
let editHandlers: {[event: string]: (view: EditorView, event: Event) => void} = {} | ||
const editHandlers: {[event: string]: (view: EditorView, event: Event) => void} = {} | ||
const passiveHandlers: Record<string, boolean> = {touchstart: true, touchmove: true} | ||
@@ -29,2 +30,4 @@ export class InputState { | ||
lastIOSEnterFallbackTimeout = -1 | ||
lastFocus = 0 | ||
lastTouch = 0 | ||
lastAndroidDelete = 0 | ||
@@ -47,3 +50,3 @@ composing = false | ||
handler(view, event) | ||
}) | ||
}, passiveHandlers[event] ? {passive: true} : undefined) | ||
} | ||
@@ -409,3 +412,4 @@ // On Safari, for reasons beyond my understanding, adding an input | ||
handlers.touchdown = view => { | ||
handlers.touchstart = view => { | ||
view.input.lastTouch = Date.now() | ||
forceDOMFlush(view) | ||
@@ -415,2 +419,7 @@ setSelectionOrigin(view, "pointer") | ||
handlers.touchmove = view => { | ||
view.input.lastTouch = Date.now() | ||
setSelectionOrigin(view, "pointer") | ||
} | ||
handlers.contextmenu = view => forceDOMFlush(view) | ||
@@ -658,3 +667,2 @@ | ||
let $mouse = view.state.doc.resolve(eventPos.pos) | ||
if (!$mouse) return | ||
let slice = dragging && dragging.slice | ||
@@ -704,2 +712,3 @@ if (slice) { | ||
handlers.focus = view => { | ||
view.input.lastFocus = Date.now() | ||
if (!view.focused) { | ||
@@ -706,0 +715,0 @@ view.domObserver.stop() |
@@ -712,3 +712,3 @@ import {DOMSerializer, Fragment, Mark, Node, ParseRule} from "prosemirror-model" | ||
let compositionInChild = composition && composition.pos < 0 | ||
let updater = new ViewTreeUpdater(this, localComposition && localComposition.node) | ||
let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view) | ||
iterDeco(this.node, this.innerDeco, (widget, i, insideNode) => { | ||
@@ -1113,3 +1113,3 @@ if (widget.spec.marks) | ||
constructor(top: NodeViewDesc, readonly lock: DOMNode | null) { | ||
constructor(top: NodeViewDesc, readonly lock: DOMNode | null, private readonly view: EditorView) { | ||
this.top = top | ||
@@ -1278,3 +1278,4 @@ this.preMatch = preMatch(top.node.content, top) | ||
!(lastChild instanceof TextViewDesc) || | ||
/\n$/.test(lastChild.node.text!)) { | ||
/\n$/.test(lastChild.node.text!) || | ||
(this.view.requiresGeckoHackNode && /\s$/.test(lastChild.node.text!))) { | ||
// Avoid bugs in Safari's cursor drawing (#1165) and Chrome's mouse selection (#1152) | ||
@@ -1281,0 +1282,0 @@ if ((browser.safari || browser.chrome) && lastChild && (lastChild.dom as HTMLElement).contentEditable == "false") |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
751985
23
16154