diff --git a/src/components/EditorView.tsx b/src/components/EditorView.tsx index 05f26137..2fc5983f 100644 --- a/src/components/EditorView.tsx +++ b/src/components/EditorView.tsx @@ -22,7 +22,6 @@ import { EditorViewInternal } from "../prosemirror-internal/EditorViewInternal.j import * as browser from "../prosemirror-internal/browser.js"; import { DOMNode, - DOMSelection, deepActiveElement, safariShadowSelectionRange, } from "../prosemirror-internal/dom.js"; diff --git a/src/hooks/useContentEditable.ts b/src/hooks/useContentEditable.ts index ddc11d4f..1dd54c22 100644 --- a/src/hooks/useContentEditable.ts +++ b/src/hooks/useContentEditable.ts @@ -19,7 +19,7 @@ export function useContentEditable( viewRef.current, viewRef.current.state.selection.from, viewRef.current.state.selection.to, - event.data ?? "" + event.data ) ) { event.preventDefault(); diff --git a/src/prosemirror-internal/capturekeys.ts b/src/prosemirror-internal/capturekeys.ts deleted file mode 100644 index f9ffa520..00000000 --- a/src/prosemirror-internal/capturekeys.ts +++ /dev/null @@ -1,336 +0,0 @@ -import {Selection, NodeSelection, TextSelection, AllSelection, EditorState} from "prosemirror-state" -import { EditorViewInternal as EditorView } from "./EditorViewInternal.js" -import * as browser from "./browser" -import {domIndex, selectionCollapsed, hasBlockDesc} from "./dom" -import {selectionToDOM} from "./selection.js" - -function moveSelectionBlock(state: EditorState, dir: number) { - let {$anchor, $head} = state.selection - let $side = dir > 0 ? $anchor.max($head) : $anchor.min($head) - let $start = !$side.parent.inlineContent ? $side : $side.depth ? state.doc.resolve(dir > 0 ? $side.after() : $side.before()) : null - return $start && Selection.findFrom($start, dir) -} - -function apply(view: EditorView, sel: Selection) { - view.dispatch(view.state.tr.setSelection(sel).scrollIntoView()) - return true -} - -function selectHorizontally(view: EditorView, dir: number, mods: string) { - let sel = view.state.selection - if (sel instanceof TextSelection) { - if (!sel.empty || mods.indexOf("s") > -1) { - return false - } else if (view.endOfTextblock(dir > 0 ? "forward" : "backward")) { - let next = moveSelectionBlock(view.state, dir) - if (next && (next instanceof NodeSelection)) return apply(view, next) - return false - } else if (!(browser.mac && mods.indexOf("m") > -1)) { - let $head = sel.$head, node = $head.textOffset ? null : dir < 0 ? $head.nodeBefore : $head.nodeAfter, desc - if (!node || node.isText) return false - let nodePos = dir < 0 ? $head.pos - node.nodeSize : $head.pos - if (!(node.isAtom || (desc = view.docView.descAt(nodePos)) && !desc.contentDOM)) return false - if (NodeSelection.isSelectable(node)) { - return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head)) - } else if (browser.webkit) { - // Chrome and Safari will introduce extra pointless cursor - // positions around inline uneditable nodes, so we have to - // take over and move the cursor past them (#937) - return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize))) - } else { - return false - } - } - } else if (sel instanceof NodeSelection && sel.node.isInline) { - return apply(view, new TextSelection(dir > 0 ? sel.$to : sel.$from)) - } else { - let next = moveSelectionBlock(view.state, dir) - if (next) return apply(view, next) - return false - } -} - -function nodeLen(node: Node) { - return node.nodeType == 3 ? node.nodeValue!.length : node.childNodes.length -} - -function isIgnorable(dom: Node) { - if ((dom as HTMLElement).contentEditable == "false") return true - let desc = dom.pmViewDesc - return desc && desc.size == 0 && (dom.nextSibling || dom.nodeName != "BR") -} - -function skipIgnoredNodes(view: EditorView, dir: number) { - return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view) -} - -// Make sure the cursor isn't directly after one or more ignored -// nodes, which will confuse the browser's cursor motion logic. -function skipIgnoredNodesBefore(view: EditorView) { - let sel = view.domSelectionRange() - let node = sel.focusNode!, offset = sel.focusOffset - if (!node) return - let moveNode, moveOffset: number | undefined, force = false - // Gecko will do odd things when the selection is directly in front - // of a non-editable node, so in that case, move it into the next - // node if possible. Issue prosemirror/prosemirror#832. - if (browser.gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset])) force = true - for (;;) { - if (offset > 0) { - if (node.nodeType != 1) { - break - } else { - let before = node.childNodes[offset - 1] - if (isIgnorable(before)) { - moveNode = node - moveOffset = --offset - } else if (before.nodeType == 3) { - node = before - offset = node.nodeValue!.length - } else break - } - } else if (isBlockNode(node)) { - break - } else { - let prev = node.previousSibling - while (prev && isIgnorable(prev)) { - moveNode = node.parentNode - moveOffset = domIndex(prev) - prev = prev.previousSibling - } - if (!prev) { - node = node.parentNode! - if (node == view.dom) break - offset = 0 - } else { - node = prev - offset = nodeLen(node) - } - } - } - if (force) setSelFocus(view, node, offset) - else if (moveNode) setSelFocus(view, moveNode, moveOffset!) -} - -// Make sure the cursor isn't directly before one or more ignored -// nodes. -function skipIgnoredNodesAfter(view: EditorView) { - let sel = view.domSelectionRange() - let node = sel.focusNode!, offset = sel.focusOffset - if (!node) return - let len = nodeLen(node) - let moveNode, moveOffset: number | undefined - for (;;) { - if (offset < len) { - if (node.nodeType != 1) break - let after = node.childNodes[offset] - if (isIgnorable(after)) { - moveNode = node - moveOffset = ++offset - } - else break - } else if (isBlockNode(node)) { - break - } else { - let next = node.nextSibling - while (next && isIgnorable(next)) { - moveNode = next.parentNode - moveOffset = domIndex(next) + 1 - next = next.nextSibling - } - if (!next) { - node = node.parentNode! - if (node == view.dom) break - offset = len = 0 - } else { - node = next - offset = 0 - len = nodeLen(node) - } - } - } - if (moveNode) setSelFocus(view, moveNode, moveOffset!) -} - -function isBlockNode(dom: Node) { - let desc = dom.pmViewDesc - return desc && desc.node && desc.node.isBlock -} - -function textNodeAfter(node: Node | null, offset: number): Text | undefined { - while (node && offset == node.childNodes.length && !hasBlockDesc(node)) { - offset = domIndex(node) + 1 - node = node.parentNode - } - while (node && offset < node.childNodes.length) { - node = node.childNodes[offset] - if (node.nodeType == 3) return node as Text - offset = 0 - } -} - -function textNodeBefore(node: Node | null, offset: number): Text | undefined { - while (node && !offset && !hasBlockDesc(node)) { - offset = domIndex(node) - node = node.parentNode - } - while (node && offset) { - node = node.childNodes[offset - 1] - if (node.nodeType == 3) return node as Text - offset = node.childNodes.length - } -} - -function setSelFocus(view: EditorView, node: Node, offset: number) { - if (node.nodeType != 3) { - let before, after - if (after = textNodeAfter(node, offset)) { - node = after - offset = 0 - } else if (before = textNodeBefore(node, offset)) { - node = before - offset = before.nodeValue!.length - } - } - - let sel = view.domSelection() - if (selectionCollapsed(sel)) { - let range = document.createRange() - range.setEnd(node, offset) - range.setStart(node, offset) - sel.removeAllRanges() - sel.addRange(range) - } else if (sel.extend) { - sel.extend(node, offset) - } - view.domObserver.setCurSelection() - let {state} = view - // If no state update ends up happening, reset the selection. - setTimeout(() => { - if (view.state == state) selectionToDOM(view) - }, 50) -} - -function findDirection(view: EditorView, pos: number): "rtl" | "ltr" { - let $pos = view.state.doc.resolve(pos) - if (!(browser.chrome || browser.windows) && $pos.parent.inlineContent) { - let coords = view.coordsAtPos(pos) - if (pos > $pos.start()) { - let before = view.coordsAtPos(pos - 1) - let mid = (before.top + before.bottom) / 2 - if (mid > coords.top && mid < coords.bottom && Math.abs(before.left - coords.left) > 1) - return before.left < coords.left ? "ltr" : "rtl" - } - if (pos < $pos.end()) { - let after = view.coordsAtPos(pos + 1) - let mid = (after.top + after.bottom) / 2 - if (mid > coords.top && mid < coords.bottom && Math.abs(after.left - coords.left) > 1) - return after.left > coords.left ? "ltr" : "rtl" - } - } - let computed = getComputedStyle(view.dom).direction - return computed == "rtl" ? "rtl" : "ltr" -} - -// Check whether vertical selection motion would involve node -// selections. If so, apply it (if not, the result is left to the -// browser) -function selectVertically(view: EditorView, dir: number, mods: string) { - let sel = view.state.selection - if (sel instanceof TextSelection && !sel.empty || mods.indexOf("s") > -1) return false - if (browser.mac && mods.indexOf("m") > -1) return false - let {$from, $to} = sel - - if (!$from.parent.inlineContent || view.endOfTextblock(dir < 0 ? "up" : "down")) { - let next = moveSelectionBlock(view.state, dir) - if (next && (next instanceof NodeSelection)) - return apply(view, next) - } - if (!$from.parent.inlineContent) { - let side = dir < 0 ? $from : $to - let beyond = sel instanceof AllSelection ? Selection.near(side, dir) : Selection.findFrom(side, dir) - return beyond ? apply(view, beyond) : false - } - return false -} - -function stopNativeHorizontalDelete(view: EditorView, dir: number) { - if (!(view.state.selection instanceof TextSelection)) return true - let {$head, $anchor, empty} = view.state.selection - if (!$head.sameParent($anchor)) return true - if (!empty) return false - if (view.endOfTextblock(dir > 0 ? "forward" : "backward")) return true - let nextNode = !$head.textOffset && (dir < 0 ? $head.nodeBefore : $head.nodeAfter) - if (nextNode && !nextNode.isText) { - let tr = view.state.tr - if (dir < 0) tr.delete($head.pos - nextNode.nodeSize, $head.pos) - else tr.delete($head.pos, $head.pos + nextNode.nodeSize) - view.dispatch(tr) - return true - } - return false -} - -function switchEditable(view: EditorView, node: HTMLElement, state: string) { - view.domObserver.stop() - node.contentEditable = state - view.domObserver.start() -} - -// Issue #867 / #1090 / https://bugs.chromium.org/p/chromium/issues/detail?id=903821 -// In which Safari (and at some point in the past, Chrome) does really -// wrong things when the down arrow is pressed when the cursor is -// directly at the start of a textblock and has an uneditable node -// after it -function safariDownArrowBug(view: EditorView) { - if (!browser.safari || view.state.selection.$head.parentOffset > 0) return false - let {focusNode, focusOffset} = view.domSelectionRange() - if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 && - focusNode.firstChild && (focusNode.firstChild as HTMLElement).contentEditable == "false") { - let child = focusNode.firstChild as HTMLElement - switchEditable(view, child, "true") - setTimeout(() => switchEditable(view, child, "false"), 20) - } - return false -} - -// A backdrop key mapping used to make sure we always suppress keys -// that have a dangerous default effect, even if the commands they are -// bound to return false, and to make sure that cursor-motion keys -// find a cursor (as opposed to a node selection) when pressed. For -// cursor-motion keys, the code in the handlers also takes care of -// block selections. - -function getMods(event: KeyboardEvent) { - let result = "" - if (event.ctrlKey) result += "c" - if (event.metaKey) result += "m" - if (event.altKey) result += "a" - if (event.shiftKey) result += "s" - return result -} - -export function captureKeyDown(view: EditorView, event: KeyboardEvent) { - let code = event.keyCode, mods = getMods(event) - if (code == 8 || (browser.mac && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac - return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodes(view, -1) - } else if ((code == 46 && !event.shiftKey) || (browser.mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac - return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodes(view, 1) - } else if (code == 13 || code == 27) { // Enter, Esc - return true - } else if (code == 37 || (browser.mac && code == 66 && mods == "c")) { // Left arrow, Ctrl-b on Mac - let dir = code == 37 ? (findDirection(view, view.state.selection.from) == "ltr" ? -1 : 1) : -1 - return selectHorizontally(view, dir, mods) || skipIgnoredNodes(view, dir) - } else if (code == 39 || (browser.mac && code == 70 && mods == "c")) { // Right arrow, Ctrl-f on Mac - let dir = code == 39 ? (findDirection(view, view.state.selection.from) == "ltr" ? 1 : -1) : 1 - return selectHorizontally(view, dir, mods) || skipIgnoredNodes(view, dir) - } else if (code == 38 || (browser.mac && code == 80 && mods == "c")) { // Up arrow, Ctrl-p on Mac - return selectVertically(view, -1, mods) || skipIgnoredNodes(view, -1) - } else if (code == 40 || (browser.mac && code == 78 && mods == "c")) { // Down arrow, Ctrl-n on Mac - return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodesAfter(view) - } else if (mods == (browser.mac ? "m" : "c") && - (code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz] - return true - } - return false -} diff --git a/src/prosemirror-internal/input.ts b/src/prosemirror-internal/input.ts index 3a6b6f5a..5ea80ac0 100644 --- a/src/prosemirror-internal/input.ts +++ b/src/prosemirror-internal/input.ts @@ -3,9 +3,12 @@ import {dropPoint} from "prosemirror-transform" import {Slice, Node} from "prosemirror-model" import * as browser from "./browser" -import {captureKeyDown} from "./capturekeys.js" +// $$FORK: trying to drop this for now +// import {captureKeyDown} from "./capturekeys.js" import {parseFromClipboard, serializeForClipboard} from "./clipboard.js" -import {selectionBetween, selectionToDOM, selectionFromDOM} from "./selection.js" +// $$FORK: selectionToDOM is handled in our sync selection hook +// import {selectionBetween, selectionToDOM, selectionFromDOM} from "./selection.js" +import {selectionBetween, selectionFromDOM} from "./selection.js" import {keyEvent, DOMNode} from "./dom" import { EditorViewInternal as EditorView } from "./EditorViewInternal.js" import {ViewDesc} from "../descriptors/ViewDesc.js" @@ -124,7 +127,10 @@ editHandlers.keydown = (view: EditorView, _event: Event) => { view.input.lastIOSEnter = 0 } }, 200) - } else if (view.someProp("handleKeyDown", f => f(view, event)) || captureKeyDown(view, event)) { + // $$FORK: drop capturekeydown? As far as I can tell, everything it's attempting to + // do just works natively. + // } else if (view.someProp("handleKeyDown", f => f(view, event)) || captureKeyDown(view, event)) { + } else if (view.someProp("handleKeyDown", f => f(view, event))) { event.preventDefault() } else { setSelectionOrigin(view, "key") @@ -145,13 +151,14 @@ editHandlers.keypress = (view, _event) => { return } - let sel = view.state.selection - if (!(sel instanceof TextSelection) || !sel.$from.sameParent(sel.$to)) { - let text = String.fromCharCode(event.charCode) - if (!/[\r\n]/.test(text) && !view.someProp("handleTextInput", f => f(view, sel.$from.pos, sel.$to.pos, text))) - view.dispatch(view.state.tr.insertText(text).scrollIntoView()) - event.preventDefault() - } + // $$FORK: We handle this in our beforeinput handler + // let sel = view.state.selection + // if (!(sel instanceof TextSelection) || !sel.$from.sameParent(sel.$to)) { + // let text = String.fromCharCode(event.charCode) + // if (!/[\r\n]/.test(text) && !view.someProp("handleTextInput", f => f(view, sel.$from.pos, sel.$to.pos, text))) + // view.dispatch(view.state.tr.insertText(text).scrollIntoView()) + // event.preventDefault() + // } } function eventCoords(event: MouseEvent) { return {left: event.clientX, top: event.clientY} } @@ -743,7 +750,7 @@ handlers.focus = view => { } handlers.blur = (view, _event) => { - let event = _event as FocusEvent + // let event = _event as FocusEvent if (view.focused) { // $$FORK: We don't use a dom observer // view.domObserver.stop() diff --git a/src/prosemirror-internal/selection.ts b/src/prosemirror-internal/selection.ts index dae0c845..7825b4a2 100644 --- a/src/prosemirror-internal/selection.ts +++ b/src/prosemirror-internal/selection.ts @@ -1,8 +1,12 @@ -import {TextSelection, NodeSelection, Selection} from "prosemirror-state" +// $$FORK: We've commented out huge chunks of this file, +// so we don't need some of the imports +// import {TextSelection, NodeSelection, Selection} from "prosemirror-state" +import {TextSelection, NodeSelection} from "prosemirror-state" import {ResolvedPos} from "prosemirror-model" -import * as browser from "./browser" -import {isEquivalentPosition, domIndex, isOnEdge, selectionCollapsed} from "./dom" +// import * as browser from "./browser" +// import {isEquivalentPosition, domIndex, isOnEdge, selectionCollapsed} from "./dom" +import {isEquivalentPosition, isOnEdge, selectionCollapsed} from "./dom" import {EditorViewInternal as EditorView} from "./EditorViewInternal.js" import {NodeViewDesc} from "../descriptors/ViewDesc.js" @@ -35,145 +39,146 @@ export function selectionFromDOM(view: EditorView, origin: string | null = null) return selection } -function editorOwnsSelection(view: EditorView) { - return view.editable ? view.hasFocus() : - hasSelection(view) && document.activeElement && document.activeElement.contains(view.dom) -} - -export function selectionToDOM(view: EditorView, force = false) { - let sel = view.state.selection - syncNodeSelection(view, sel) - - if (!editorOwnsSelection(view)) return - - // The delayed drag selection causes issues with Cell Selections - // in Safari. And the drag selection delay is to workarond issues - // which only present in Chrome. - if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && browser.chrome) { - let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection - if (domSel.anchorNode && curSel.anchorNode && - isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, - curSel.anchorNode, curSel.anchorOffset)) { - view.input.mouseDown.delayedSelectionSync = true - view.domObserver.setCurSelection() - return - } - } - - view.domObserver.disconnectSelection() - - if (view.cursorWrapper) { - selectCursorWrapper(view) - } else { - let {anchor, head} = sel, resetEditableFrom, resetEditableTo - if (brokenSelectBetweenUneditable && !(sel instanceof TextSelection)) { - if (!sel.$from.parent.inlineContent) - resetEditableFrom = temporarilyEditableNear(view, sel.from) - if (!sel.empty && !sel.$from.parent.inlineContent) - resetEditableTo = temporarilyEditableNear(view, sel.to) - } - view.docView.setSelection(anchor, head, view.root, force) - if (brokenSelectBetweenUneditable) { - if (resetEditableFrom) resetEditable(resetEditableFrom) - if (resetEditableTo) resetEditable(resetEditableTo) - } - if (sel.visible) { - view.dom.classList.remove("ProseMirror-hideselection") - } else { - view.dom.classList.add("ProseMirror-hideselection") - if ("onselectionchange" in document) removeClassOnSelectionChange(view) - } - } - - view.domObserver.setCurSelection() - view.domObserver.connectSelection() -} +// function editorOwnsSelection(view: EditorView) { +// return view.editable ? view.hasFocus() : +// hasSelection(view) && document.activeElement && document.activeElement.contains(view.dom) +// } + +// $$FORK: For now, this is implemented in our sync selection hook +// export function selectionToDOM(view: EditorView, force = false) { +// let sel = view.state.selection +// syncNodeSelection(view, sel) + +// if (!editorOwnsSelection(view)) return + +// // The delayed drag selection causes issues with Cell Selections +// // in Safari. And the drag selection delay is to workarond issues +// // which only present in Chrome. +// if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && browser.chrome) { +// let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection +// if (domSel.anchorNode && curSel.anchorNode && +// isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, +// curSel.anchorNode, curSel.anchorOffset)) { +// view.input.mouseDown.delayedSelectionSync = true +// view.domObserver.setCurSelection() +// return +// } +// } + +// view.domObserver.disconnectSelection() + +// if (view.cursorWrapper) { +// selectCursorWrapper(view) +// } else { +// let {anchor, head} = sel, resetEditableFrom, resetEditableTo +// if (brokenSelectBetweenUneditable && !(sel instanceof TextSelection)) { +// if (!sel.$from.parent.inlineContent) +// resetEditableFrom = temporarilyEditableNear(view, sel.from) +// if (!sel.empty && !sel.$from.parent.inlineContent) +// resetEditableTo = temporarilyEditableNear(view, sel.to) +// } +// view.docView.setSelection(anchor, head, view.root, force) +// if (brokenSelectBetweenUneditable) { +// if (resetEditableFrom) resetEditable(resetEditableFrom) +// if (resetEditableTo) resetEditable(resetEditableTo) +// } +// if (sel.visible) { +// view.dom.classList.remove("ProseMirror-hideselection") +// } else { +// view.dom.classList.add("ProseMirror-hideselection") +// if ("onselectionchange" in document) removeClassOnSelectionChange(view) +// } +// } + +// view.domObserver.setCurSelection() +// view.domObserver.connectSelection() +// } // Kludge to work around Webkit not allowing a selection to start/end // between non-editable block nodes. We briefly make something // editable, set the selection, then set it uneditable again. -const brokenSelectBetweenUneditable = browser.safari || browser.chrome && browser.chrome_version < 63 - -function temporarilyEditableNear(view: EditorView, pos: number) { - let {node, offset} = view.docView.domFromPos(pos, 0) - let after = offset < node.childNodes.length ? node.childNodes[offset] : null - let before = offset ? node.childNodes[offset - 1] : null - if (browser.safari && after && (after as HTMLElement).contentEditable == "false") return setEditable(after as HTMLElement) - if ((!after || (after as HTMLElement).contentEditable == "false") && - (!before || (before as HTMLElement).contentEditable == "false")) { - if (after) return setEditable(after as HTMLElement) - else if (before) return setEditable(before as HTMLElement) - } -} - -function setEditable(element: HTMLElement) { - element.contentEditable = "true" - if (browser.safari && element.draggable) { element.draggable = false; (element as any).wasDraggable = true } - return element -} - -function resetEditable(element: HTMLElement) { - element.contentEditable = "false" - if ((element as any).wasDraggable) { element.draggable = true; (element as any).wasDraggable = null } -} - -function removeClassOnSelectionChange(view: EditorView) { - let doc = view.dom.ownerDocument - doc.removeEventListener("selectionchange", view.input.hideSelectionGuard!) - let domSel = view.domSelectionRange() - let node = domSel.anchorNode, offset = domSel.anchorOffset - doc.addEventListener("selectionchange", view.input.hideSelectionGuard = () => { - if (domSel.anchorNode != node || domSel.anchorOffset != offset) { - doc.removeEventListener("selectionchange", view.input.hideSelectionGuard!) - setTimeout(() => { - if (!editorOwnsSelection(view) || view.state.selection.visible) - view.dom.classList.remove("ProseMirror-hideselection") - }, 20) - } - }) -} - -function selectCursorWrapper(view: EditorView) { - let domSel = view.domSelection(), range = document.createRange() - let node = view.cursorWrapper!.dom, img = node.nodeName == "IMG" - if (img) range.setEnd(node.parentNode!, domIndex(node) + 1) - else range.setEnd(node, 0) - range.collapse(false) - domSel.removeAllRanges() - domSel.addRange(range) - // Kludge to kill 'control selection' in IE11 when selecting an - // invisible cursor wrapper, since that would result in those weird - // resize handles and a selection that considers the absolutely - // positioned wrapper, rather than the root editable node, the - // focused element. - if (!img && !view.state.selection.visible && browser.ie && browser.ie_version <= 11) { - ;(node as any).disabled = true - ;(node as any).disabled = false - } -} - -export function syncNodeSelection(view: EditorView, sel: Selection) { - if (sel instanceof NodeSelection) { - let desc = view.docView.descAt(sel.from) - if (desc != view.lastSelectedViewDesc) { - clearNodeSelection(view) - if (desc) (desc as NodeViewDesc).selectNode() - view.lastSelectedViewDesc = desc - } - } else { - clearNodeSelection(view) - } -} - -// Clear all DOM statefulness of the last node selection. -function clearNodeSelection(view: EditorView) { - if (view.lastSelectedViewDesc) { - if (view.lastSelectedViewDesc.parent) - (view.lastSelectedViewDesc as NodeViewDesc).deselectNode() - view.lastSelectedViewDesc = undefined - } -} +// const brokenSelectBetweenUneditable = browser.safari || browser.chrome && browser.chrome_version < 63 + +// function temporarilyEditableNear(view: EditorView, pos: number) { +// let {node, offset} = view.docView.domFromPos(pos, 0) +// let after = offset < node.childNodes.length ? node.childNodes[offset] : null +// let before = offset ? node.childNodes[offset - 1] : null +// if (browser.safari && after && (after as HTMLElement).contentEditable == "false") return setEditable(after as HTMLElement) +// if ((!after || (after as HTMLElement).contentEditable == "false") && +// (!before || (before as HTMLElement).contentEditable == "false")) { +// if (after) return setEditable(after as HTMLElement) +// else if (before) return setEditable(before as HTMLElement) +// } +// } + +// function setEditable(element: HTMLElement) { +// element.contentEditable = "true" +// if (browser.safari && element.draggable) { element.draggable = false; (element as any).wasDraggable = true } +// return element +// } + +// function resetEditable(element: HTMLElement) { +// element.contentEditable = "false" +// if ((element as any).wasDraggable) { element.draggable = true; (element as any).wasDraggable = null } +// } + +// function removeClassOnSelectionChange(view: EditorView) { +// let doc = view.dom.ownerDocument +// doc.removeEventListener("selectionchange", view.input.hideSelectionGuard!) +// let domSel = view.domSelectionRange() +// let node = domSel.anchorNode, offset = domSel.anchorOffset +// doc.addEventListener("selectionchange", view.input.hideSelectionGuard = () => { +// if (domSel.anchorNode != node || domSel.anchorOffset != offset) { +// doc.removeEventListener("selectionchange", view.input.hideSelectionGuard!) +// setTimeout(() => { +// if (!editorOwnsSelection(view) || view.state.selection.visible) +// view.dom.classList.remove("ProseMirror-hideselection") +// }, 20) +// } +// }) +// } + +// function selectCursorWrapper(view: EditorView) { +// let domSel = view.domSelection(), range = document.createRange() +// let node = view.cursorWrapper!.dom, img = node.nodeName == "IMG" +// if (img) range.setEnd(node.parentNode!, domIndex(node) + 1) +// else range.setEnd(node, 0) +// range.collapse(false) +// domSel.removeAllRanges() +// domSel.addRange(range) +// // Kludge to kill 'control selection' in IE11 when selecting an +// // invisible cursor wrapper, since that would result in those weird +// // resize handles and a selection that considers the absolutely +// // positioned wrapper, rather than the root editable node, the +// // focused element. +// if (!img && !view.state.selection.visible && browser.ie && browser.ie_version <= 11) { +// ;(node as any).disabled = true +// ;(node as any).disabled = false +// } +// } + +// export function syncNodeSelection(view: EditorView, sel: Selection) { +// if (sel instanceof NodeSelection) { +// let desc = view.docView.descAt(sel.from) +// if (desc != view.lastSelectedViewDesc) { +// clearNodeSelection(view) +// if (desc) (desc as NodeViewDesc).selectNode() +// view.lastSelectedViewDesc = desc +// } +// } else { +// clearNodeSelection(view) +// } +// } + +// // Clear all DOM statefulness of the last node selection. +// function clearNodeSelection(view: EditorView) { +// if (view.lastSelectedViewDesc) { +// if (view.lastSelectedViewDesc.parent) +// (view.lastSelectedViewDesc as NodeViewDesc).deselectNode() +// view.lastSelectedViewDesc = undefined +// } +// } export function selectionBetween(view: EditorView, $anchor: ResolvedPos, $head: ResolvedPos, bias?: number) { return view.someProp("createSelectionBetween", f => f(view, $anchor, $head))