mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-18 21:21:21 +02:00
deprecate data, add getEventRange and getEventTransfer helpers (#1243)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
|
||||
import Editor from './components/editor'
|
||||
import Placeholder from './components/placeholder'
|
||||
import getEventRange from './utils/get-event-range'
|
||||
import getEventTransfer from './utils/get-event-transfer'
|
||||
import findDOMNode from './utils/find-dom-node'
|
||||
import findDOMRange from './utils/find-dom-range'
|
||||
import findNode from './utils/find-node'
|
||||
@@ -15,6 +17,8 @@ import findRange from './utils/find-range'
|
||||
export {
|
||||
Editor,
|
||||
Placeholder,
|
||||
getEventRange,
|
||||
getEventTransfer,
|
||||
findDOMNode,
|
||||
findDOMRange,
|
||||
findNode,
|
||||
@@ -24,6 +28,8 @@ export {
|
||||
export default {
|
||||
Editor,
|
||||
Placeholder,
|
||||
getEventRange,
|
||||
getEventTransfer,
|
||||
findDOMNode,
|
||||
findDOMRange,
|
||||
findNode,
|
||||
|
@@ -12,6 +12,9 @@ import Content from '../components/content'
|
||||
import Placeholder from '../components/placeholder'
|
||||
import findDOMNode from '../utils/find-dom-node'
|
||||
import findPoint from '../utils/find-point'
|
||||
import findRange from '../utils/find-range'
|
||||
import getEventRange from '../utils/get-event-range'
|
||||
import getEventTransfer from '../utils/get-event-transfer'
|
||||
import { IS_CHROME, IS_MAC, IS_SAFARI } from '../constants/environment'
|
||||
|
||||
/**
|
||||
@@ -39,6 +42,8 @@ function AfterPlugin(options = {}) {
|
||||
placeholderStyle,
|
||||
} = options
|
||||
|
||||
let isDraggingInternally = null
|
||||
|
||||
/**
|
||||
* On before change, enforce the editor's schema.
|
||||
*
|
||||
@@ -143,7 +148,7 @@ function AfterPlugin(options = {}) {
|
||||
|
||||
// Create a fake selection so that we can add a Base64-encoded copy of the
|
||||
// fragment to the HTML, to decode on future pastes.
|
||||
const { fragment } = data
|
||||
const { fragment } = state
|
||||
const encoded = Base64.serializeNode(fragment)
|
||||
const range = native.getRangeAt(0)
|
||||
let contents = range.cloneContents()
|
||||
@@ -233,6 +238,51 @@ function AfterPlugin(options = {}) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* On drag end.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
|
||||
function onDragEnd(event, data, change, editor) {
|
||||
debug('onDragEnd', { event })
|
||||
|
||||
isDraggingInternally = null
|
||||
}
|
||||
|
||||
/**
|
||||
* On drag over.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
|
||||
function onDragOver(event, data, change, editor) {
|
||||
debug('onDragOver', { event })
|
||||
|
||||
isDraggingInternally = false
|
||||
}
|
||||
|
||||
/**
|
||||
* On drag start.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
|
||||
function onDragStart(event, data, change, editor) {
|
||||
debug('onDragStart', { event })
|
||||
|
||||
isDraggingInternally = true
|
||||
}
|
||||
|
||||
/**
|
||||
* On drop.
|
||||
*
|
||||
@@ -241,39 +291,23 @@ function AfterPlugin(options = {}) {
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
function onDrop(event, data, change) {
|
||||
debug('onDrop', { data })
|
||||
|
||||
switch (data.type) {
|
||||
case 'text':
|
||||
case 'html':
|
||||
return onDropText(event, data, change)
|
||||
case 'fragment':
|
||||
return onDropFragment(event, data, change)
|
||||
case 'node':
|
||||
return onDropNode(event, data, change)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On drop node.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
function onDropNode(event, data, change) {
|
||||
debug('onDropNode', { data })
|
||||
function onDrop(event, data, change, editor) {
|
||||
debug('onDrop', { event })
|
||||
|
||||
const { state } = change
|
||||
const { selection } = state
|
||||
let { node, target, isInternal } = data
|
||||
let target = getEventRange(event, state)
|
||||
if (!target) return
|
||||
|
||||
const transfer = getEventTransfer(event)
|
||||
const { type, fragment, node, text } = transfer
|
||||
|
||||
change.focus()
|
||||
|
||||
// If the drag is internal and the target is after the selection, it
|
||||
// needs to account for the selection's content being deleted.
|
||||
if (
|
||||
isInternal &&
|
||||
isDraggingInternally &&
|
||||
selection.endKey == target.endKey &&
|
||||
selection.endOffset < target.endOffset
|
||||
) {
|
||||
@@ -282,103 +316,47 @@ function AfterPlugin(options = {}) {
|
||||
: 0 - selection.endOffset)
|
||||
}
|
||||
|
||||
if (isInternal) {
|
||||
if (isDraggingInternally) {
|
||||
change.delete()
|
||||
}
|
||||
|
||||
if (Block.isBlock(node)) {
|
||||
change
|
||||
.select(target)
|
||||
.focus()
|
||||
.insertBlock(node)
|
||||
.removeNodeByKey(node.key)
|
||||
}
|
||||
change.select(target)
|
||||
|
||||
if (Inline.isInline(node)) {
|
||||
change
|
||||
.select(target)
|
||||
.focus()
|
||||
.insertInline(node)
|
||||
.removeNodeByKey(node.key)
|
||||
}
|
||||
}
|
||||
if (type == 'text' || type == 'html') {
|
||||
const { anchorKey } = target
|
||||
let hasVoidParent = document.hasVoidParent(anchorKey)
|
||||
|
||||
/**
|
||||
* On drop fragment.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
*/
|
||||
if (hasVoidParent) {
|
||||
let n = document.getNode(anchorKey)
|
||||
|
||||
function onDropFragment(event, data, change) {
|
||||
debug('onDropFragment', { data })
|
||||
while (hasVoidParent) {
|
||||
n = document.getNextText(n.key)
|
||||
if (!n) break
|
||||
hasVoidParent = document.hasVoidParent(n.key)
|
||||
}
|
||||
|
||||
const { state } = change
|
||||
const { selection } = state
|
||||
let { fragment, target, isInternal } = data
|
||||
|
||||
// If the drag is internal and the target is after the selection, it
|
||||
// needs to account for the selection's content being deleted.
|
||||
if (
|
||||
isInternal &&
|
||||
selection.endKey == target.endKey &&
|
||||
selection.endOffset < target.endOffset
|
||||
) {
|
||||
target = target.move(selection.startKey == selection.endKey
|
||||
? 0 - selection.endOffset + selection.startOffset
|
||||
: 0 - selection.endOffset)
|
||||
}
|
||||
|
||||
if (isInternal) {
|
||||
change.delete()
|
||||
}
|
||||
|
||||
change
|
||||
.select(target)
|
||||
.focus()
|
||||
.insertFragment(fragment)
|
||||
}
|
||||
|
||||
/**
|
||||
* On drop text.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
function onDropText(event, data, change) {
|
||||
debug('onDropText', { data })
|
||||
|
||||
const { state } = change
|
||||
const { document } = state
|
||||
const { text, target } = data
|
||||
const { anchorKey } = target
|
||||
|
||||
change.select(target).focus()
|
||||
|
||||
let hasVoidParent = document.hasVoidParent(anchorKey)
|
||||
|
||||
// Insert text into nearest text node
|
||||
if (hasVoidParent) {
|
||||
let node = document.getNode(anchorKey)
|
||||
|
||||
while (hasVoidParent) {
|
||||
node = document.getNextText(node.key)
|
||||
if (!node) break
|
||||
hasVoidParent = document.hasVoidParent(node.key)
|
||||
if (n) change.collapseToStartOf(n)
|
||||
}
|
||||
|
||||
if (node) change.collapseToStartOf(node)
|
||||
text
|
||||
.split('\n')
|
||||
.forEach((line, i) => {
|
||||
if (i > 0) change.splitBlock()
|
||||
change.insertText(line)
|
||||
})
|
||||
}
|
||||
|
||||
text
|
||||
.split('\n')
|
||||
.forEach((line, i) => {
|
||||
if (i > 0) change.splitBlock()
|
||||
change.insertText(line)
|
||||
})
|
||||
if (type == 'fragment') {
|
||||
change.insertFragment(fragment)
|
||||
}
|
||||
|
||||
if (type == 'node' && Block.isBlock(node)) {
|
||||
change.insertBlock(node).removeNodeByKey(node.key)
|
||||
}
|
||||
|
||||
if (type == 'node' && Inline.isInline(node)) {
|
||||
change.insertInline(node).removeNodeByKey(node.key)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -733,48 +711,23 @@ function AfterPlugin(options = {}) {
|
||||
function onPaste(event, data, change) {
|
||||
debug('onPaste', { data })
|
||||
|
||||
switch (data.type) {
|
||||
case 'fragment':
|
||||
return onPasteFragment(event, data, change)
|
||||
case 'text':
|
||||
case 'html':
|
||||
return onPasteText(event, data, change)
|
||||
const transfer = getEventTransfer(event)
|
||||
const { type, fragment, text } = transfer
|
||||
|
||||
if (type == 'fragment') {
|
||||
change.insertFragment(fragment)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On paste fragment.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
*/
|
||||
if (type == 'text' || type == 'html') {
|
||||
const { state } = change
|
||||
const { document, selection, startBlock } = state
|
||||
if (startBlock.isVoid) return
|
||||
|
||||
function onPasteFragment(event, data, change) {
|
||||
debug('onPasteFragment', { data })
|
||||
change.insertFragment(data.fragment)
|
||||
}
|
||||
|
||||
/**
|
||||
* On paste text, split blocks at new lines.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
function onPasteText(event, data, change) {
|
||||
debug('onPasteText', { data })
|
||||
|
||||
const { state } = change
|
||||
const { document, selection, startBlock } = state
|
||||
if (startBlock.isVoid) return
|
||||
|
||||
const { text } = data
|
||||
const defaultBlock = startBlock
|
||||
const defaultMarks = document.getMarksAtRange(selection.collapseToStart())
|
||||
const fragment = Plain.deserialize(text, { defaultBlock, defaultMarks }).document
|
||||
change.insertFragment(fragment)
|
||||
const defaultBlock = startBlock
|
||||
const defaultMarks = document.getMarksAtRange(selection.collapseToStart())
|
||||
const frag = Plain.deserialize(text, { defaultBlock, defaultMarks }).document
|
||||
change.insertFragment(frag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -787,7 +740,73 @@ function AfterPlugin(options = {}) {
|
||||
|
||||
function onSelect(event, data, change) {
|
||||
debug('onSelect', { data })
|
||||
change.select(data.selection)
|
||||
|
||||
const window = getWindow(event.target)
|
||||
const { state } = change
|
||||
const { document } = state
|
||||
const native = window.getSelection()
|
||||
|
||||
// If there are no ranges, the editor was blurred natively.
|
||||
if (!native.rangeCount) {
|
||||
change.blur()
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, determine the Slate selection from the native one.
|
||||
let range = findRange(native, state)
|
||||
if (!range) return
|
||||
|
||||
const { anchorKey, anchorOffset, focusKey, focusOffset } = range
|
||||
const anchorText = document.getNode(anchorKey)
|
||||
const focusText = document.getNode(focusKey)
|
||||
const anchorInline = document.getClosestInline(anchorKey)
|
||||
const focusInline = document.getClosestInline(focusKey)
|
||||
const focusBlock = document.getClosestBlock(focusKey)
|
||||
const anchorBlock = document.getClosestBlock(anchorKey)
|
||||
|
||||
// COMPAT: If the anchor point is at the start of a non-void, and the
|
||||
// focus point is inside a void node with an offset that isn't `0`, set
|
||||
// the focus offset to `0`. This is due to void nodes <span>'s being
|
||||
// positioned off screen, resulting in the offset always being greater
|
||||
// than `0`. Since we can't know what it really should be, and since an
|
||||
// offset of `0` is less destructive because it creates a hanging
|
||||
// selection, go with `0`. (2017/09/07)
|
||||
if (
|
||||
anchorBlock &&
|
||||
!anchorBlock.isVoid &&
|
||||
anchorOffset == 0 &&
|
||||
focusBlock &&
|
||||
focusBlock.isVoid &&
|
||||
focusOffset != 0
|
||||
) {
|
||||
range = range.set('focusOffset', 0)
|
||||
}
|
||||
|
||||
// COMPAT: If the selection is at the end of a non-void inline node, and
|
||||
// there is a node after it, put it in the node after instead. This
|
||||
// standardizes the behavior, since it's indistinguishable to the user.
|
||||
if (
|
||||
anchorInline &&
|
||||
!anchorInline.isVoid &&
|
||||
anchorOffset == anchorText.text.length
|
||||
) {
|
||||
const block = document.getClosestBlock(anchorKey)
|
||||
const next = block.getNextText(anchorKey)
|
||||
if (next) range = range.moveAnchorTo(next.key, 0)
|
||||
}
|
||||
|
||||
if (
|
||||
focusInline &&
|
||||
!focusInline.isVoid &&
|
||||
focusOffset == focusText.text.length
|
||||
) {
|
||||
const block = document.getClosestBlock(focusKey)
|
||||
const next = block.getNextText(focusKey)
|
||||
if (next) range = range.moveFocusTo(next.key, 0)
|
||||
}
|
||||
|
||||
range = range.normalize(document)
|
||||
change.select(range)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -899,6 +918,9 @@ function AfterPlugin(options = {}) {
|
||||
onBlur,
|
||||
onCopy,
|
||||
onCut,
|
||||
onDragEnd,
|
||||
onDragOver,
|
||||
onDragStart,
|
||||
onDrop,
|
||||
onInput,
|
||||
onKeyDown,
|
||||
|
@@ -9,7 +9,8 @@ import { findDOMNode } from 'react-dom'
|
||||
import HOTKEYS from '../constants/hotkeys'
|
||||
import TRANSFER_TYPES from '../constants/transfer-types'
|
||||
import findRange from '../utils/find-range'
|
||||
import getTransferData from '../utils/get-transfer-data'
|
||||
import getEventRange from '../utils/get-event-range'
|
||||
import getEventTransfer from '../utils/get-event-transfer'
|
||||
import setTransferData from '../utils/set-transfer-data'
|
||||
import { IS_FIREFOX, IS_MAC, SUPPORTED_EVENTS } from '../constants/environment'
|
||||
|
||||
@@ -135,8 +136,8 @@ function BeforePlugin() {
|
||||
window.requestAnimationFrame(() => isCopying = false)
|
||||
|
||||
const { state } = change
|
||||
data.type = 'fragment'
|
||||
data.fragment = state.fragment
|
||||
defineDeprecatedData(data, 'type', 'fragment')
|
||||
defineDeprecatedData(data, 'fragment', state.fragment)
|
||||
|
||||
debug('onCopy', { event })
|
||||
}
|
||||
@@ -158,8 +159,8 @@ function BeforePlugin() {
|
||||
window.requestAnimationFrame(() => isCopying = false)
|
||||
|
||||
const { state } = change
|
||||
data.type = 'fragment'
|
||||
data.fragment = state.fragment
|
||||
defineDeprecatedData(data, 'type', 'fragment')
|
||||
defineDeprecatedData(data, 'fragment', state.fragment)
|
||||
|
||||
debug('onCut', { event })
|
||||
}
|
||||
@@ -212,12 +213,16 @@ function BeforePlugin() {
|
||||
isDragging = true
|
||||
isInternalDrag = true
|
||||
|
||||
const { dataTransfer } = event.nativeEvent
|
||||
const d = getTransferData(dataTransfer)
|
||||
Object.assign(data, d)
|
||||
const d = getEventTransfer(event)
|
||||
const { nativeEvent } = event
|
||||
const { dataTransfer } = nativeEvent
|
||||
|
||||
if (data.type != 'node') {
|
||||
const { state } = this.props
|
||||
Object.keys(d).forEach((key) => {
|
||||
defineDeprecatedData(data, key, d[key])
|
||||
})
|
||||
|
||||
if (d.type != 'node') {
|
||||
const { state } = change
|
||||
const { fragment } = state
|
||||
const encoded = Base64.serializeNode(fragment)
|
||||
setTransferData(dataTransfer, TRANSFER_TYPES.FRAGMENT, encoded)
|
||||
@@ -243,60 +248,29 @@ function BeforePlugin() {
|
||||
|
||||
const { state } = change
|
||||
const { nativeEvent } = event
|
||||
const { dataTransfer, x, y } = nativeEvent
|
||||
const d = getTransferData(dataTransfer)
|
||||
Object.assign(data, d)
|
||||
const { dataTransfer } = nativeEvent
|
||||
const d = getEventTransfer(event)
|
||||
|
||||
// Resolve a range from the caret position where the drop occured.
|
||||
const window = getWindow(event.target)
|
||||
let range
|
||||
Object.keys(d).forEach((key) => {
|
||||
defineDeprecatedData(data, key, d[key])
|
||||
})
|
||||
|
||||
// COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
|
||||
if (window.document.caretRangeFromPoint) {
|
||||
range = window.document.caretRangeFromPoint(x, y)
|
||||
} else {
|
||||
const position = window.document.caretPositionFromPoint(x, y)
|
||||
range = window.document.createRange()
|
||||
range.setStart(position.offsetNode, position.offset)
|
||||
range.setEnd(position.offsetNode, position.offset)
|
||||
}
|
||||
|
||||
// Resolve a Slate range from the DOM range.
|
||||
let selection = findRange(range, state)
|
||||
if (!selection) return true
|
||||
|
||||
const { document } = state
|
||||
const node = document.getNode(selection.anchorKey)
|
||||
const parent = document.getParent(node.key)
|
||||
const el = findDOMNode(parent)
|
||||
|
||||
// If the drop target is inside a void node, move it into either the next or
|
||||
// previous node, depending on which side the `x` and `y` coordinates are
|
||||
// closest to.
|
||||
if (parent.isVoid) {
|
||||
const rect = el.getBoundingClientRect()
|
||||
const isPrevious = parent.kind == 'inline'
|
||||
? x - rect.left < rect.left + rect.width - x
|
||||
: y - rect.top < rect.top + rect.height - y
|
||||
|
||||
selection = isPrevious
|
||||
? selection.moveToEndOf(document.getPreviousText(node.key))
|
||||
: selection.moveToStartOf(document.getNextText(node.key))
|
||||
}
|
||||
const range = getEventRange(event, state)
|
||||
if (!range) return true
|
||||
|
||||
// Add drop-specific information to the data.
|
||||
data.target = selection
|
||||
defineDeprecatedData(data, 'target', range)
|
||||
|
||||
// COMPAT: Edge throws "Permission denied" errors when
|
||||
// accessing `dropEffect` or `effectAllowed` (2017/7/12)
|
||||
try {
|
||||
data.effect = dataTransfer.dropEffect
|
||||
defineDeprecatedData(data, 'effect', dataTransfer.dropEffect)
|
||||
} catch (err) {
|
||||
data.effect = null
|
||||
defineDeprecatedData(data, 'effect', null)
|
||||
}
|
||||
|
||||
if (d.type == 'fragment' || d.type == 'node') {
|
||||
data.isInternal = isInternalDrag
|
||||
defineDeprecatedData(data, 'isInternal', isInternalDrag)
|
||||
}
|
||||
|
||||
debug('onDrop', { event })
|
||||
@@ -421,19 +395,14 @@ function BeforePlugin() {
|
||||
if (editor.props.readOnly) return
|
||||
|
||||
event.preventDefault()
|
||||
const d = getTransferData(event.clipboardData)
|
||||
Object.assign(data, d)
|
||||
const d = getEventTransfer(event)
|
||||
|
||||
// COMPAT: Attach the `isShift` flag, so that people can use it to trigger
|
||||
// "Paste and Match Style" logic.
|
||||
Object.defineProperty(data, 'isShift', {
|
||||
enumerable: true,
|
||||
get() {
|
||||
logger.deprecate('0.28.0', 'The `data.isShift` property of paste events has been deprecated. If you need this functionality, you\'ll need to keep track of that state with `onKeyDown` and `onKeyUp` events instead')
|
||||
return isShifting
|
||||
}
|
||||
Object.keys(d).forEach((key) => {
|
||||
defineDeprecatedData(data, key, d[key])
|
||||
})
|
||||
|
||||
defineDeprecatedData(data, 'isShift', isShifting)
|
||||
|
||||
debug('onPaste', { event })
|
||||
}
|
||||
|
||||
@@ -458,7 +427,7 @@ function BeforePlugin() {
|
||||
|
||||
// If there are no ranges, the editor was blurred natively.
|
||||
if (!native.rangeCount) {
|
||||
data.selection = selection.blur()
|
||||
defineDeprecatedData(data, 'selection', selection.blur())
|
||||
}
|
||||
|
||||
// Otherwise, determine the Slate selection from the native one.
|
||||
@@ -516,7 +485,7 @@ function BeforePlugin() {
|
||||
}
|
||||
|
||||
range = range.normalize(document)
|
||||
data.selection = range
|
||||
defineDeprecatedData(data, 'selection', range)
|
||||
}
|
||||
|
||||
debug('onSelect', { event })
|
||||
@@ -549,37 +518,33 @@ function BeforePlugin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add deprecated `data` fields from a key `event`.
|
||||
*
|
||||
* @param {Object} data
|
||||
* @param {Object} event
|
||||
* Deprecated.
|
||||
*/
|
||||
|
||||
function defineDeprecatedData(data, key, value) {
|
||||
Object.defineProperty(data, key, {
|
||||
enumerable: true,
|
||||
get() {
|
||||
logger.deprecate('slate-react@0.5.0', `Accessing the \`data.${key}\` property is deprecated, please use the native \`event\` properties instead, or one of the newly exposed helper utilities.`)
|
||||
return value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function addDeprecatedKeyProperties(data, event) {
|
||||
const { altKey, ctrlKey, metaKey, shiftKey, which } = event
|
||||
const name = keycode(which)
|
||||
|
||||
function define(key, value) {
|
||||
Object.defineProperty(data, key, {
|
||||
enumerable: true,
|
||||
get() {
|
||||
logger.deprecate('0.28.0', `The \`data.${key}\` property of keyboard events is deprecated, please use the native \`event\` properties instead.`)
|
||||
return value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
define('code', which)
|
||||
define('key', name)
|
||||
define('isAlt', altKey)
|
||||
define('isCmd', IS_MAC ? metaKey && !altKey : false)
|
||||
define('isCtrl', ctrlKey && !altKey)
|
||||
define('isLine', IS_MAC ? metaKey : false)
|
||||
define('isMeta', metaKey)
|
||||
define('isMod', IS_MAC ? metaKey && !altKey : ctrlKey && !altKey)
|
||||
define('isModAlt', IS_MAC ? metaKey && altKey : ctrlKey && altKey)
|
||||
define('isShift', shiftKey)
|
||||
define('isWord', IS_MAC ? altKey : ctrlKey)
|
||||
defineDeprecatedData(data, 'code', which)
|
||||
defineDeprecatedData(data, 'key', name)
|
||||
defineDeprecatedData(data, 'isAlt', altKey)
|
||||
defineDeprecatedData(data, 'isCmd', IS_MAC ? metaKey && !altKey : false)
|
||||
defineDeprecatedData(data, 'isCtrl', ctrlKey && !altKey)
|
||||
defineDeprecatedData(data, 'isLine', IS_MAC ? metaKey : false)
|
||||
defineDeprecatedData(data, 'isMeta', metaKey)
|
||||
defineDeprecatedData(data, 'isMod', IS_MAC ? metaKey && !altKey : ctrlKey && !altKey)
|
||||
defineDeprecatedData(data, 'isModAlt', IS_MAC ? metaKey && altKey : ctrlKey && altKey)
|
||||
defineDeprecatedData(data, 'isShift', shiftKey)
|
||||
defineDeprecatedData(data, 'isWord', IS_MAC ? altKey : ctrlKey)
|
||||
}
|
||||
|
||||
/**
|
||||
|
69
packages/slate-react/src/utils/get-event-range.js
Normal file
69
packages/slate-react/src/utils/get-event-range.js
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
import getWindow from 'get-window'
|
||||
|
||||
import findDOMNode from './find-dom-node'
|
||||
import findRange from './find-range'
|
||||
|
||||
/**
|
||||
* Get the target range from a DOM `event`.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {State} state
|
||||
* @return {Range}
|
||||
*/
|
||||
|
||||
function getEventRange(event, state) {
|
||||
if (event.nativeEvent) {
|
||||
event = event.nativeEvent
|
||||
}
|
||||
|
||||
const { x, y } = event
|
||||
if (x == null || y == null) return null
|
||||
|
||||
// Resolve a range from the caret position where the drop occured.
|
||||
const window = getWindow(event.target)
|
||||
let r
|
||||
|
||||
// COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
|
||||
if (window.document.caretRangeFromPoint) {
|
||||
r = window.document.caretRangeFromPoint(x, y)
|
||||
} else {
|
||||
const position = window.document.caretPositionFromPoint(x, y)
|
||||
r = window.document.createRange()
|
||||
r.setStart(position.offsetNode, position.offset)
|
||||
r.setEnd(position.offsetNode, position.offset)
|
||||
}
|
||||
|
||||
// Resolve a Slate range from the DOM range.
|
||||
let range = findRange(r, state)
|
||||
if (!range) return null
|
||||
|
||||
const { document } = state
|
||||
const node = document.getNode(range.anchorKey)
|
||||
const parent = document.getParent(node.key)
|
||||
const el = findDOMNode(parent)
|
||||
|
||||
// If the drop target is inside a void node, move it into either the next or
|
||||
// previous node, depending on which side the `x` and `y` coordinates are
|
||||
// closest to.
|
||||
if (parent.isVoid) {
|
||||
const rect = el.getBoundingClientRect()
|
||||
const isPrevious = parent.kind == 'inline'
|
||||
? x - rect.left < rect.left + rect.width - x
|
||||
: y - rect.top < rect.top + rect.height - y
|
||||
|
||||
range = isPrevious
|
||||
? range.moveToEndOf(document.getPreviousText(node.key))
|
||||
: range.moveToStartOf(document.getNextText(node.key))
|
||||
}
|
||||
|
||||
return range
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
export default getEventRange
|
@@ -12,13 +12,18 @@ import TRANSFER_TYPES from '../constants/transfer-types'
|
||||
const FRAGMENT_MATCHER = / data-slate-fragment="([^\s"]+)"/
|
||||
|
||||
/**
|
||||
* Get the data and type from a native data `transfer`.
|
||||
* Get the transfer data from an `event`.
|
||||
*
|
||||
* @param {DataTransfer} transfer
|
||||
* @param {Event} event
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
function getTransferData(transfer) {
|
||||
function getEventTransfer(event) {
|
||||
if (event.nativeEvent) {
|
||||
event = event.nativeEvent
|
||||
}
|
||||
|
||||
const transfer = event.dataTransfer || event.clipboardData
|
||||
let fragment = getType(transfer, TRANSFER_TYPES.FRAGMENT)
|
||||
let node = getType(transfer, TRANSFER_TYPES.NODE)
|
||||
const html = getType(transfer, 'text/html')
|
||||
@@ -148,4 +153,4 @@ function getType(transfer, type) {
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
export default getTransferData
|
||||
export default getEventTransfer
|
Reference in New Issue
Block a user