mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-27 17:09:53 +02:00
Core component will deduce the context from the dispatched event.target element
This commit is contained in:
@@ -9,6 +9,7 @@ import TYPES from '../utils/types'
|
|||||||
import includes from 'lodash/includes'
|
import includes from 'lodash/includes'
|
||||||
import keycode from 'keycode'
|
import keycode from 'keycode'
|
||||||
import { IS_FIREFOX, IS_MAC } from '../utils/environment'
|
import { IS_FIREFOX, IS_MAC } from '../utils/environment'
|
||||||
|
import findElementWindow from '../utils/find-element-window'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug.
|
* Debug.
|
||||||
@@ -380,11 +381,13 @@ class Content extends React.Component {
|
|||||||
// Resolve the point where the drop occured.
|
// Resolve the point where the drop occured.
|
||||||
let range
|
let range
|
||||||
|
|
||||||
|
const contextWindow = findElementWindow(e.nativeEvent.target)
|
||||||
|
|
||||||
// COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
|
// COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
|
||||||
if (window.document.caretRangeFromPoint) {
|
if (contextWindow.document.caretRangeFromPoint) {
|
||||||
range = window.document.caretRangeFromPoint(x, y)
|
range = contextWindow.document.caretRangeFromPoint(x, y)
|
||||||
} else {
|
} else {
|
||||||
range = window.document.createRange()
|
range = contextWindow.document.createRange()
|
||||||
range.setStart(e.nativeEvent.rangeParent, e.nativeEvent.rangeOffset)
|
range.setStart(e.nativeEvent.rangeParent, e.nativeEvent.rangeOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,9 +462,11 @@ class Content extends React.Component {
|
|||||||
if (isNonEditable(e)) return
|
if (isNonEditable(e)) return
|
||||||
debug('onInput')
|
debug('onInput')
|
||||||
|
|
||||||
|
const contextWindow = findElementWindow(e.nativeEvent.target)
|
||||||
|
|
||||||
let { state, renderDecorations } = this.props
|
let { state, renderDecorations } = this.props
|
||||||
const { selection } = state
|
const { selection } = state
|
||||||
const native = window.getSelection()
|
const native = contextWindow.getSelection()
|
||||||
const { anchorNode, anchorOffset, focusOffset } = native
|
const { anchorNode, anchorOffset, focusOffset } = native
|
||||||
const point = this.getPoint(anchorNode, anchorOffset)
|
const point = this.getPoint(anchorNode, anchorOffset)
|
||||||
const { key, index, start, end } = point
|
const { key, index, start, end } = point
|
||||||
@@ -624,9 +629,11 @@ class Content extends React.Component {
|
|||||||
if (this.tmp.isComposing) return
|
if (this.tmp.isComposing) return
|
||||||
if (isNonEditable(e)) return
|
if (isNonEditable(e)) return
|
||||||
|
|
||||||
|
const contextWindow = findElementWindow(e.nativeEvent.target)
|
||||||
|
|
||||||
const { state, renderDecorations } = this.props
|
const { state, renderDecorations } = this.props
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
const native = window.getSelection()
|
const native = contextWindow.getSelection()
|
||||||
const data = {}
|
const data = {}
|
||||||
|
|
||||||
// If there are no ranges, the editor was blurred natively.
|
// If there are no ranges, the editor was blurred natively.
|
||||||
|
@@ -3,7 +3,7 @@ import Debug from 'debug'
|
|||||||
import OffsetKey from '../utils/offset-key'
|
import OffsetKey from '../utils/offset-key'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
|
import findElementWindow from '../utils/find-element-window'
|
||||||
/**
|
/**
|
||||||
* Debugger.
|
* Debugger.
|
||||||
*
|
*
|
||||||
@@ -135,14 +135,16 @@ class Leaf extends React.Component {
|
|||||||
focusOffset = 0
|
focusOffset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contextWindow = findElementWindow(ReactDOM.findDOMNode(this));
|
||||||
|
|
||||||
// We have a selection to render, so prepare a few things...
|
// We have a selection to render, so prepare a few things...
|
||||||
const native = window.getSelection()
|
const native = contextWindow.getSelection()
|
||||||
const el = findDeepestNode(ReactDOM.findDOMNode(this))
|
const el = findDeepestNode(ReactDOM.findDOMNode(this))
|
||||||
|
|
||||||
// If both the start and end are here, set the selection all at once.
|
// If both the start and end are here, set the selection all at once.
|
||||||
if (hasAnchor && hasFocus) {
|
if (hasAnchor && hasFocus) {
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
const range = window.document.createRange()
|
const range = contextWindow.document.createRange()
|
||||||
range.setStart(el, anchorOffset - start)
|
range.setStart(el, anchorOffset - start)
|
||||||
native.addRange(range)
|
native.addRange(range)
|
||||||
native.extend(el, focusOffset - start)
|
native.extend(el, focusOffset - start)
|
||||||
@@ -155,7 +157,7 @@ class Leaf extends React.Component {
|
|||||||
if (selection.isForward) {
|
if (selection.isForward) {
|
||||||
if (hasAnchor) {
|
if (hasAnchor) {
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
const range = window.document.createRange()
|
const range = contextWindow.document.createRange()
|
||||||
range.setStart(el, anchorOffset - start)
|
range.setStart(el, anchorOffset - start)
|
||||||
native.addRange(range)
|
native.addRange(range)
|
||||||
} else if (hasFocus) {
|
} else if (hasFocus) {
|
||||||
@@ -170,14 +172,14 @@ class Leaf extends React.Component {
|
|||||||
else {
|
else {
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
const range = window.document.createRange()
|
const range = contextWindow.document.createRange()
|
||||||
range.setStart(el, focusOffset - start)
|
range.setStart(el, focusOffset - start)
|
||||||
native.addRange(range)
|
native.addRange(range)
|
||||||
} else if (hasAnchor) {
|
} else if (hasAnchor) {
|
||||||
const endNode = native.focusNode
|
const endNode = native.focusNode
|
||||||
const endOffset = native.focusOffset
|
const endOffset = native.focusOffset
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
const range = window.document.createRange()
|
const range = contextWindow.document.createRange()
|
||||||
range.setStart(el, anchorOffset - start)
|
range.setStart(el, anchorOffset - start)
|
||||||
native.addRange(range)
|
native.addRange(range)
|
||||||
native.extend(endNode, endOffset)
|
native.extend(endNode, endOffset)
|
||||||
|
@@ -5,6 +5,7 @@ import Debug from 'debug'
|
|||||||
import Placeholder from '../components/placeholder'
|
import Placeholder from '../components/placeholder'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import String from '../utils/string'
|
import String from '../utils/string'
|
||||||
|
import findElementWindow from '../utils/find-element-window'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug.
|
* Debug.
|
||||||
@@ -28,7 +29,7 @@ function Plugin(options = {}) {
|
|||||||
const {
|
const {
|
||||||
placeholder,
|
placeholder,
|
||||||
placeholderClassName,
|
placeholderClassName,
|
||||||
placeholderStyle
|
placeholderStyle,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,7 +205,9 @@ function Plugin(options = {}) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function onCutOrCopy(e, data, state) {
|
function onCutOrCopy(e, data, state) {
|
||||||
const native = window.getSelection()
|
const contextWindow = findElementWindow(e.nativeEvent.target)
|
||||||
|
|
||||||
|
const native = contextWindow.getSelection()
|
||||||
if (!native.rangeCount) return
|
if (!native.rangeCount) return
|
||||||
|
|
||||||
const { fragment } = data
|
const { fragment } = data
|
||||||
@@ -214,10 +217,10 @@ function Plugin(options = {}) {
|
|||||||
// fragment attached as an attribute, so it will show up in the copied HTML.
|
// fragment attached as an attribute, so it will show up in the copied HTML.
|
||||||
const range = native.getRangeAt(0)
|
const range = native.getRangeAt(0)
|
||||||
const contents = range.cloneContents()
|
const contents = range.cloneContents()
|
||||||
const wrapper = window.document.createElement('span')
|
const wrapper = contextWindow.document.createElement('span')
|
||||||
const text = contents.childNodes[0]
|
const text = contents.childNodes[0]
|
||||||
const char = text.textContent.slice(0, 1)
|
const char = text.textContent.slice(0, 1)
|
||||||
const first = window.document.createTextNode(char)
|
const first = contextWindow.document.createTextNode(char)
|
||||||
const rest = text.textContent.slice(1)
|
const rest = text.textContent.slice(1)
|
||||||
text.textContent = rest
|
text.textContent = rest
|
||||||
wrapper.appendChild(first)
|
wrapper.appendChild(first)
|
||||||
@@ -225,8 +228,8 @@ function Plugin(options = {}) {
|
|||||||
contents.insertBefore(wrapper, text)
|
contents.insertBefore(wrapper, text)
|
||||||
|
|
||||||
// Add the phony content to the DOM, and select it, so it will be copied.
|
// Add the phony content to the DOM, and select it, so it will be copied.
|
||||||
const body = window.document.querySelector('body')
|
const body = contextWindow.document.querySelector('body')
|
||||||
const div = window.document.createElement('div')
|
const div = contextWindow.document.createElement('div')
|
||||||
div.setAttribute('contenteditable', true)
|
div.setAttribute('contenteditable', true)
|
||||||
div.style.position = 'absolute'
|
div.style.position = 'absolute'
|
||||||
div.style.left = '-9999px'
|
div.style.left = '-9999px'
|
||||||
@@ -235,7 +238,7 @@ function Plugin(options = {}) {
|
|||||||
|
|
||||||
// COMPAT: In Firefox, trying to use the terser `native.selectAllChildren`
|
// COMPAT: In Firefox, trying to use the terser `native.selectAllChildren`
|
||||||
// throws an error, so we use the older `range` equivalent. (2016/06/21)
|
// throws an error, so we use the older `range` equivalent. (2016/06/21)
|
||||||
const r = window.document.createRange()
|
const r = contextWindow.document.createRange()
|
||||||
r.selectNodeContents(div)
|
r.selectNodeContents(div)
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
native.addRange(r)
|
native.addRange(r)
|
||||||
|
12
lib/utils/find-element-window.js
Normal file
12
lib/utils/find-element-window.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Find the DOM context for the `node`, fallback to top level global window object.
|
||||||
|
*
|
||||||
|
* @param {Node} node
|
||||||
|
* @return {Element} el
|
||||||
|
*/
|
||||||
|
function findElementWindow (domNode) {
|
||||||
|
const doc = domNode.ownerDocument || domNode
|
||||||
|
return doc.defaultView || doc.parentWindow
|
||||||
|
}
|
||||||
|
|
||||||
|
export default findElementWindow
|
Reference in New Issue
Block a user