mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-09-01 11:12:42 +02:00
cleanup logging, fix inline void selection
This commit is contained in:
@@ -174,34 +174,34 @@ class Content extends React.Component {
|
|||||||
/**
|
/**
|
||||||
* On before input, bubble up.
|
* On before input, bubble up.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onBeforeInput = (e) => {
|
onBeforeInput = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
const data = {}
|
const data = {}
|
||||||
|
|
||||||
debug('onBeforeInput', data)
|
debug('onBeforeInput', { event, data })
|
||||||
this.props.onBeforeInput(e, data)
|
this.props.onBeforeInput(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On blur, update the selection to be not focused.
|
* On blur, update the selection to be not focused.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onBlur = (e) => {
|
onBlur = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (this.tmp.isCopying) return
|
if (this.tmp.isCopying) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
const data = {}
|
const data = {}
|
||||||
|
|
||||||
debug('onBlur', data)
|
debug('onBlur', { event, data })
|
||||||
this.props.onBlur(e, data)
|
this.props.onBlur(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -218,16 +218,16 @@ class Content extends React.Component {
|
|||||||
/**
|
/**
|
||||||
* On composition start, set the `isComposing` flag.
|
* On composition start, set the `isComposing` flag.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onCompositionStart = (e) => {
|
onCompositionStart = (event) => {
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
this.tmp.isComposing = true
|
this.tmp.isComposing = true
|
||||||
this.tmp.compositions++
|
this.tmp.compositions++
|
||||||
|
|
||||||
debug('onCompositionStart')
|
debug('onCompositionStart', { event })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,11 +235,11 @@ class Content extends React.Component {
|
|||||||
* increment the `forces` key, which will force the contenteditable element
|
* increment the `forces` key, which will force the contenteditable element
|
||||||
* to completely re-render, since IME puts React in an unreconcilable state.
|
* to completely re-render, since IME puts React in an unreconcilable state.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onCompositionEnd = (e) => {
|
onCompositionEnd = (event) => {
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
this.forces++
|
this.forces++
|
||||||
const count = this.tmp.compositions
|
const count = this.tmp.compositions
|
||||||
@@ -252,18 +252,18 @@ class Content extends React.Component {
|
|||||||
this.tmp.isComposing = false
|
this.tmp.isComposing = false
|
||||||
})
|
})
|
||||||
|
|
||||||
debug('onCompositionEnd')
|
debug('onCompositionEnd', { event })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On copy, defer to `onCutCopy`, then bubble up.
|
* On copy, defer to `onCutCopy`, then bubble up.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onCopy = (e) => {
|
onCopy = (event) => {
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
const window = getWindow(e.target)
|
const window = getWindow(event.target)
|
||||||
|
|
||||||
this.tmp.isCopying = true
|
this.tmp.isCopying = true
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
@@ -275,20 +275,20 @@ class Content extends React.Component {
|
|||||||
data.type = 'fragment'
|
data.type = 'fragment'
|
||||||
data.fragment = state.fragment
|
data.fragment = state.fragment
|
||||||
|
|
||||||
debug('onCopy', data)
|
debug('onCopy', { event, data })
|
||||||
this.props.onCopy(e, data)
|
this.props.onCopy(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On cut, defer to `onCutCopy`, then bubble up.
|
* On cut, defer to `onCutCopy`, then bubble up.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onCut = (e) => {
|
onCut = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
const window = getWindow(e.target)
|
const window = getWindow(event.target)
|
||||||
|
|
||||||
this.tmp.isCopying = true
|
this.tmp.isCopying = true
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
@@ -300,61 +300,61 @@ class Content extends React.Component {
|
|||||||
data.type = 'fragment'
|
data.type = 'fragment'
|
||||||
data.fragment = state.fragment
|
data.fragment = state.fragment
|
||||||
|
|
||||||
debug('onCut', data)
|
debug('onCut', { event, data })
|
||||||
this.props.onCut(e, data)
|
this.props.onCut(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On drag end, unset the `isDragging` flag.
|
* On drag end, unset the `isDragging` flag.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onDragEnd = (e) => {
|
onDragEnd = (event) => {
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
this.tmp.isDragging = false
|
this.tmp.isDragging = false
|
||||||
this.tmp.isInternalDrag = null
|
this.tmp.isInternalDrag = null
|
||||||
|
|
||||||
debug('onDragEnd')
|
debug('onDragEnd', { event })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On drag over, set the `isDragging` flag and the `isInternalDrag` flag.
|
* On drag over, set the `isDragging` flag and the `isInternalDrag` flag.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onDragOver = (e) => {
|
onDragOver = (event) => {
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
const { dataTransfer } = e.nativeEvent
|
const { dataTransfer } = event.nativeEvent
|
||||||
const transfer = new Transfer(dataTransfer)
|
const transfer = new Transfer(dataTransfer)
|
||||||
|
|
||||||
// Prevent default when nodes are dragged to allow dropping.
|
// Prevent default when nodes are dragged to allow dropping.
|
||||||
if (transfer.getType() == 'node') {
|
if (transfer.getType() == 'node') {
|
||||||
e.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tmp.isDragging) return
|
if (this.tmp.isDragging) return
|
||||||
this.tmp.isDragging = true
|
this.tmp.isDragging = true
|
||||||
this.tmp.isInternalDrag = false
|
this.tmp.isInternalDrag = false
|
||||||
|
|
||||||
debug('onDragOver')
|
debug('onDragOver', { event })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On drag start, set the `isDragging` flag and the `isInternalDrag` flag.
|
* On drag start, set the `isDragging` flag and the `isInternalDrag` flag.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onDragStart = (e) => {
|
onDragStart = (event) => {
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
this.tmp.isDragging = true
|
this.tmp.isDragging = true
|
||||||
this.tmp.isInternalDrag = true
|
this.tmp.isInternalDrag = true
|
||||||
const { dataTransfer } = e.nativeEvent
|
const { dataTransfer } = event.nativeEvent
|
||||||
const transfer = new Transfer(dataTransfer)
|
const transfer = new Transfer(dataTransfer)
|
||||||
|
|
||||||
// If it's a node being dragged, the data type is already set.
|
// If it's a node being dragged, the data type is already set.
|
||||||
@@ -365,24 +365,25 @@ class Content extends React.Component {
|
|||||||
const encoded = Base64.serializeNode(fragment)
|
const encoded = Base64.serializeNode(fragment)
|
||||||
dataTransfer.setData(TYPES.FRAGMENT, encoded)
|
dataTransfer.setData(TYPES.FRAGMENT, encoded)
|
||||||
|
|
||||||
debug('onDragStart')
|
debug('onDragStart', { event })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On drop.
|
* On drop.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onDrop = (e) => {
|
onDrop = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
e.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
const window = getWindow(e.target)
|
const window = getWindow(event.target)
|
||||||
const { state } = this.props
|
const { state } = this.props
|
||||||
const { dataTransfer, x, y } = e.nativeEvent
|
const { nativeEvent } = event
|
||||||
|
const { dataTransfer, x, y } = nativeEvent
|
||||||
const transfer = new Transfer(dataTransfer)
|
const transfer = new Transfer(dataTransfer)
|
||||||
const data = transfer.getData()
|
const data = transfer.getData()
|
||||||
|
|
||||||
@@ -394,7 +395,7 @@ class Content extends React.Component {
|
|||||||
range = window.document.caretRangeFromPoint(x, y)
|
range = window.document.caretRangeFromPoint(x, y)
|
||||||
} else {
|
} else {
|
||||||
range = window.document.createRange()
|
range = window.document.createRange()
|
||||||
range.setStart(e.nativeEvent.rangeParent, e.nativeEvent.rangeOffset)
|
range.setStart(nativeEvent.rangeParent, nativeEvent.rangeOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
const startNode = range.startContainer
|
const startNode = range.startContainer
|
||||||
@@ -419,24 +420,24 @@ class Content extends React.Component {
|
|||||||
data.isInternal = this.tmp.isInternalDrag
|
data.isInternal = this.tmp.isInternalDrag
|
||||||
}
|
}
|
||||||
|
|
||||||
debug('onDrop', data)
|
debug('onDrop', { event, data })
|
||||||
this.props.onDrop(e, data)
|
this.props.onDrop(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On input, handle spellcheck and other similar edits that don't go trigger
|
* On input, handle spellcheck and other similar edits that don't go trigger
|
||||||
* the `onBeforeInput` and instead update the DOM directly.
|
* the `onBeforeInput` and instead update the DOM directly.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onInput = (e) => {
|
onInput = (event) => {
|
||||||
if (this.tmp.isComposing) return
|
if (this.tmp.isComposing) return
|
||||||
if (this.props.state.isBlurred) return
|
if (this.props.state.isBlurred) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
debug('onInput')
|
debug('onInput', { event })
|
||||||
|
|
||||||
const window = getWindow(e.target)
|
const window = getWindow(event.target)
|
||||||
|
|
||||||
// Get the selection point.
|
// Get the selection point.
|
||||||
const native = window.getSelection()
|
const native = window.getSelection()
|
||||||
@@ -498,14 +499,15 @@ class Content extends React.Component {
|
|||||||
* On key down, prevent the default behavior of certain commands that will
|
* On key down, prevent the default behavior of certain commands that will
|
||||||
* leave the editor in an out-of-sync state, then bubble up.
|
* leave the editor in an out-of-sync state, then bubble up.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onKeyDown = (e) => {
|
onKeyDown = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
const key = keycode(e.which)
|
const { altKey, ctrlKey, metaKey, shiftKey, which } = event
|
||||||
|
const key = keycode(which)
|
||||||
const data = {}
|
const data = {}
|
||||||
|
|
||||||
// When composing, these characters commit the composition but also move the
|
// When composing, these characters commit the composition but also move the
|
||||||
@@ -515,22 +517,22 @@ class Content extends React.Component {
|
|||||||
this.tmp.isComposing &&
|
this.tmp.isComposing &&
|
||||||
(key == 'left' || key == 'right' || key == 'up' || key == 'down')
|
(key == 'left' || key == 'right' || key == 'up' || key == 'down')
|
||||||
) {
|
) {
|
||||||
e.preventDefault()
|
event.preventDefault()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add helpful properties for handling hotkeys to the data object.
|
// Add helpful properties for handling hotkeys to the data object.
|
||||||
data.code = e.which
|
data.code = which
|
||||||
data.key = key
|
data.key = key
|
||||||
data.isAlt = e.altKey
|
data.isAlt = altKey
|
||||||
data.isCmd = IS_MAC ? e.metaKey && !e.altKey : false
|
data.isCmd = IS_MAC ? metaKey && !altKey : false
|
||||||
data.isCtrl = e.ctrlKey && !e.altKey
|
data.isCtrl = ctrlKey && !altKey
|
||||||
data.isLine = IS_MAC ? e.metaKey : false
|
data.isLine = IS_MAC ? metaKey : false
|
||||||
data.isMeta = e.metaKey
|
data.isMeta = metaKey
|
||||||
data.isMod = IS_MAC ? e.metaKey && !e.altKey : e.ctrlKey && !e.altKey
|
data.isMod = IS_MAC ? metaKey && !altKey : ctrlKey && !altKey
|
||||||
data.isModAlt = IS_MAC ? e.metaKey && e.altKey : e.ctrlKey && e.altKey
|
data.isModAlt = IS_MAC ? metaKey && altKey : ctrlKey && altKey
|
||||||
data.isShift = e.shiftKey
|
data.isShift = shiftKey
|
||||||
data.isWord = IS_MAC ? e.altKey : e.ctrlKey
|
data.isWord = IS_MAC ? altKey : ctrlKey
|
||||||
|
|
||||||
// These key commands have native behavior in contenteditable elements which
|
// These key commands have native behavior in contenteditable elements which
|
||||||
// will cause our state to be out of sync, so prevent them.
|
// will cause our state to be out of sync, so prevent them.
|
||||||
@@ -543,44 +545,44 @@ class Content extends React.Component {
|
|||||||
(key == 'y' && data.isMod) ||
|
(key == 'y' && data.isMod) ||
|
||||||
(key == 'z' && data.isMod)
|
(key == 'z' && data.isMod)
|
||||||
) {
|
) {
|
||||||
e.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
debug('onKeyDown', data)
|
debug('onKeyDown', { event, data })
|
||||||
this.props.onKeyDown(e, data)
|
this.props.onKeyDown(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On paste, determine the type and bubble up.
|
* On paste, determine the type and bubble up.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onPaste = (e) => {
|
onPaste = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
e.preventDefault()
|
event.preventDefault()
|
||||||
const transfer = new Transfer(e.clipboardData)
|
const transfer = new Transfer(event.clipboardData)
|
||||||
const data = transfer.getData()
|
const data = transfer.getData()
|
||||||
|
|
||||||
debug('onPaste', data)
|
debug('onPaste', { event, data })
|
||||||
this.props.onPaste(e, data)
|
this.props.onPaste(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On select, update the current state's selection.
|
* On select, update the current state's selection.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onSelect = (e) => {
|
onSelect = (event) => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (this.tmp.isCopying) return
|
if (this.tmp.isCopying) return
|
||||||
if (this.tmp.isComposing) return
|
if (this.tmp.isComposing) return
|
||||||
if (!this.isInContentEditable(e)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
const window = getWindow(e.target)
|
const window = getWindow(event.target)
|
||||||
const { state } = this.props
|
const { state } = this.props
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
const native = window.getSelection()
|
const native = window.getSelection()
|
||||||
@@ -626,8 +628,8 @@ class Content extends React.Component {
|
|||||||
.normalize(document)
|
.normalize(document)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug('onSelect', { data, selection: data.selection.toJS() })
|
debug('onSelect', { event, data })
|
||||||
this.props.onSelect(e, data)
|
this.props.onSelect(event, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -637,9 +639,8 @@ class Content extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
debug('render')
|
const { props } = this
|
||||||
|
const { className, readOnly, state } = props
|
||||||
const { className, readOnly, state } = this.props
|
|
||||||
const { document } = state
|
const { document } = state
|
||||||
const children = document.nodes
|
const children = document.nodes
|
||||||
.map(node => this.renderNode(node))
|
.map(node => this.renderNode(node))
|
||||||
@@ -657,13 +658,15 @@ class Content extends React.Component {
|
|||||||
// weird ways. This hides that. (2016/06/21)
|
// weird ways. This hides that. (2016/06/21)
|
||||||
...(readOnly ? {} : { WebkitUserModify: 'read-write-plaintext-only' }),
|
...(readOnly ? {} : { WebkitUserModify: 'read-write-plaintext-only' }),
|
||||||
// Allow for passed-in styles to override anything.
|
// Allow for passed-in styles to override anything.
|
||||||
...this.props.style,
|
...props.style,
|
||||||
}
|
}
|
||||||
|
|
||||||
// COMPAT: In Firefox, spellchecking can remove entire wrapping elements
|
// COMPAT: In Firefox, spellchecking can remove entire wrapping elements
|
||||||
// including inline ones like `<a>`, which is jarring for the user but also
|
// including inline ones like `<a>`, which is jarring for the user but also
|
||||||
// causes the DOM to get into an irreconcilable state. (2016/09/01)
|
// causes the DOM to get into an irreconcilable state. (2016/09/01)
|
||||||
const spellCheck = IS_FIREFOX ? false : this.props.spellCheck
|
const spellCheck = IS_FIREFOX ? false : props.spellCheck
|
||||||
|
|
||||||
|
debug('render', { props })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@@ -258,25 +258,25 @@ class Editor extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
debug('render')
|
const { props, state } = this
|
||||||
|
const handlers = { onChange: this.onChange }
|
||||||
const handlers = {}
|
|
||||||
|
|
||||||
for (const property of EVENT_HANDLERS) {
|
for (const property of EVENT_HANDLERS) {
|
||||||
handlers[property] = this[property]
|
handlers[property] = this[property]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug('render', { props, state })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Content
|
<Content
|
||||||
{...handlers}
|
{...handlers}
|
||||||
className={this.props.className}
|
className={props.className}
|
||||||
editor={this}
|
editor={this}
|
||||||
onChange={this.onChange}
|
readOnly={props.readOnly}
|
||||||
readOnly={this.props.readOnly}
|
schema={state.schema}
|
||||||
schema={this.state.schema}
|
spellCheck={props.spellCheck}
|
||||||
spellCheck={this.props.spellCheck}
|
state={state.state}
|
||||||
state={this.state.state}
|
style={props.style}
|
||||||
style={this.props.style}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ 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 getWindow from 'get-window'
|
import getWindow from 'get-window'
|
||||||
|
import { IS_FIREFOX } from '../constants/environment'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debugger.
|
* Debugger.
|
||||||
@@ -133,13 +134,13 @@ class Leaf extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
updateSelection() {
|
updateSelection() {
|
||||||
const { state, ranges, isVoid } = this.props
|
const { state, ranges } = this.props
|
||||||
const { selection } = state
|
const { selection } = state
|
||||||
|
|
||||||
// If the selection is blurred we have nothing to do.
|
// If the selection is blurred we have nothing to do.
|
||||||
if (selection.isBlurred) return
|
if (selection.isBlurred) return
|
||||||
|
|
||||||
let { anchorOffset, focusOffset } = selection
|
const { anchorOffset, focusOffset } = selection
|
||||||
const { node, index } = this.props
|
const { node, index } = this.props
|
||||||
const { start, end } = OffsetKey.findBounds(index, ranges)
|
const { start, end } = OffsetKey.findBounds(index, ranges)
|
||||||
|
|
||||||
@@ -148,13 +149,6 @@ class Leaf extends React.Component {
|
|||||||
const hasFocus = selection.hasFocusBetween(node, start, end)
|
const hasFocus = selection.hasFocusBetween(node, start, end)
|
||||||
if (!hasAnchor && !hasFocus) return
|
if (!hasAnchor && !hasFocus) return
|
||||||
|
|
||||||
// If the leaf is a void leaf, ensure that it has no width. This is due to
|
|
||||||
// void nodes always rendering an empty leaf, for browser compatibility.
|
|
||||||
if (isVoid) {
|
|
||||||
anchorOffset = 0
|
|
||||||
focusOffset = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have a selection to render, so prepare a few things...
|
// We have a selection to render, so prepare a few things...
|
||||||
const ref = ReactDOM.findDOMNode(this)
|
const ref = ReactDOM.findDOMNode(this)
|
||||||
const el = findDeepestNode(ref)
|
const el = findDeepestNode(ref)
|
||||||
@@ -165,6 +159,7 @@ class Leaf extends React.Component {
|
|||||||
// COMPAT: In Firefox, it's not enough to create a range, you also need to
|
// COMPAT: In Firefox, it's not enough to create a range, you also need to
|
||||||
// focus the contenteditable element. (2016/11/16)
|
// focus the contenteditable element. (2016/11/16)
|
||||||
function focus() {
|
function focus() {
|
||||||
|
if (!IS_FIREFOX) return
|
||||||
if (parent) setTimeout(() => parent.focus())
|
if (parent) setTimeout(() => parent.focus())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +213,7 @@ class Leaf extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.debug('updateSelection')
|
this.debug('updateSelection', { selection })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -228,8 +223,6 @@ class Leaf extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.debug('render')
|
|
||||||
|
|
||||||
const { props } = this
|
const { props } = this
|
||||||
const { node, index } = props
|
const { node, index } = props
|
||||||
const offsetKey = OffsetKey.stringify({
|
const offsetKey = OffsetKey.stringify({
|
||||||
@@ -243,6 +236,9 @@ class Leaf extends React.Component {
|
|||||||
// get out of sync, causing it to not realize the DOM needs updating.
|
// get out of sync, causing it to not realize the DOM needs updating.
|
||||||
this.tmp.renders++
|
this.tmp.renders++
|
||||||
|
|
||||||
|
|
||||||
|
this.debug('render', { props })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span key={this.tmp.renders} data-offset-key={offsetKey}>
|
<span key={this.tmp.renders} data-offset-key={offsetKey}>
|
||||||
{this.renderMarks(props)}
|
{this.renderMarks(props)}
|
||||||
|
@@ -1,15 +1,12 @@
|
|||||||
|
|
||||||
import Immutable from 'immutable'
|
|
||||||
import Base64 from '../serializers/base-64'
|
import Base64 from '../serializers/base-64'
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import TYPES from '../constants/types'
|
import TYPES from '../constants/types'
|
||||||
import IS_DEV from '../constants/is-dev'
|
|
||||||
import Leaf from './leaf'
|
import Leaf from './leaf'
|
||||||
import Void from './void'
|
import Void from './void'
|
||||||
import scrollTo from '../utils/scroll-to'
|
import scrollTo from '../utils/scroll-to'
|
||||||
import warn from '../utils/warn'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug.
|
* Debug.
|
||||||
@@ -232,9 +229,11 @@ class Node extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
this.debug('render')
|
const { props } = this
|
||||||
|
|
||||||
const { node } = this.props
|
const { node } = this.props
|
||||||
|
|
||||||
|
this.debug('render', { props })
|
||||||
|
|
||||||
return node.kind == 'text'
|
return node.kind == 'text'
|
||||||
? this.renderText()
|
? this.renderText()
|
||||||
: this.renderElement()
|
: this.renderElement()
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
import Debug from 'debug'
|
||||||
import Leaf from './leaf'
|
import Leaf from './leaf'
|
||||||
import Mark from '../models/mark'
|
import Mark from '../models/mark'
|
||||||
import OffsetKey from '../utils/offset-key'
|
import OffsetKey from '../utils/offset-key'
|
||||||
@@ -6,6 +7,14 @@ import React from 'react'
|
|||||||
import noop from '../utils/noop'
|
import noop from '../utils/noop'
|
||||||
import { IS_FIREFOX } from '../constants/environment'
|
import { IS_FIREFOX } from '../constants/environment'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug.
|
||||||
|
*
|
||||||
|
* @type {Function}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const debug = Debug('slate:void')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Void.
|
* Void.
|
||||||
*
|
*
|
||||||
@@ -30,18 +39,38 @@ class Void extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When one of the wrapper elements it clicked, select the void node.
|
* Debug.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {String} message
|
||||||
|
* @param {Mixed} ...args
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onClick = (e) => {
|
debug = (message, ...args) => {
|
||||||
e.preventDefault()
|
const { node } = this.props
|
||||||
|
const { key, type } = node
|
||||||
|
let id = `${key} (${type})`
|
||||||
|
debug(message, `${id}`, ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When one of the wrapper elements it clicked, select the void node.
|
||||||
|
*
|
||||||
|
* @param {Event} event
|
||||||
|
*/
|
||||||
|
|
||||||
|
onClick = (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
this.debug('onClick', { event })
|
||||||
|
|
||||||
const { node, editor } = this.props
|
const { node, editor } = this.props
|
||||||
const next = editor
|
const next = editor
|
||||||
.getState()
|
.getState()
|
||||||
.transform()
|
.transform()
|
||||||
.collapseToStartOf(node)
|
// COMPAT: In Chrome & Safari, selections that are at the zero offset of
|
||||||
|
// an inline node will be automatically replaced to be at the last offset
|
||||||
|
// of a previous inline node, which screws us up, so we always want to set
|
||||||
|
// it to the end of the node. (2016/11/29)
|
||||||
|
.collapseToEndOf(node)
|
||||||
.focus()
|
.focus()
|
||||||
.apply()
|
.apply()
|
||||||
|
|
||||||
@@ -55,7 +84,8 @@ class Void extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
const { children, node } = this.props
|
const { props } = this
|
||||||
|
const { children, node } = props
|
||||||
const Tag = node.kind == 'block' ? 'div' : 'span'
|
const Tag = node.kind == 'block' ? 'div' : 'span'
|
||||||
|
|
||||||
// Make the outer wrapper relative, so the spacer can overlay it.
|
// Make the outer wrapper relative, so the spacer can overlay it.
|
||||||
@@ -63,6 +93,8 @@ class Void extends React.Component {
|
|||||||
position: 'relative'
|
position: 'relative'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.debug('render', { props })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tag style={style} onClick={this.onClick}>
|
<Tag style={style} onClick={this.onClick}>
|
||||||
{this.renderSpacer()}
|
{this.renderSpacer()}
|
||||||
|
@@ -544,10 +544,17 @@ function Plugin(options = {}) {
|
|||||||
|
|
||||||
debug('onKeyDownRight', { data })
|
debug('onKeyDownRight', { data })
|
||||||
|
|
||||||
|
// COMPAT: In Chrome & Safari, selections that are at the zero offset of
|
||||||
|
// an inline node will be automatically replaced to be at the last offset
|
||||||
|
// of a previous inline node, which screws us up, so we always want to set
|
||||||
|
// it to the end of the node. (2016/11/29)
|
||||||
|
const hasNextVoidParent = document.hasVoidParent(nextText.key)
|
||||||
|
const method = hasNextVoidParent ? 'collapseToEndOf' : 'collapseToStartOf'
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
return state
|
return state
|
||||||
.transform()
|
.transform()
|
||||||
.collapseToStartOf(nextText)
|
[method](nextText)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user