1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-19 05:31:56 +02:00

WIP: Add transform wrapText (#227)

* Add basic implementation of wrapText

* Default suffix for wrapText to prefix

* Add more tests for afterText

* Add tests "whole-block" and "empty-block" for wrapText

* Add tests for across-blocks and across-inlines

* Preserve selection on wrapText

* Remove comment about cursor position

* Document transformation "wratTextAtRange"
This commit is contained in:
Samy Pessé
2016-08-09 18:11:21 +02:00
committed by Ian Storm Taylor
parent 10cfb6e48b
commit 17f703cecb
28 changed files with 490 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ Transform methods can either operate on the [`Document`](./document.md), the [`S
- [`unwrapInline`](#unwrapinline)
- [`wrapBlock`](#wrapblock)
- [`wrapInline`](#wrapinline)
- [`wrapText`](#wraptext)
- [Selection Transforms](#selection-transforms)
- [`blur`](#blur)
- [`collapseTo{Edge}Of`](#collapsetoedgeof)
@@ -67,6 +68,7 @@ Transform methods can either operate on the [`Document`](./document.md), the [`S
- [`unwrapInlineAtRange`](#unwrapinlineatrange)
- [`wrapBlockAtRange`](#wrapblockatrange)
- [`wrapInlineAtRange`](#wrapinlineatrange)
- [`wrapTextAtRange`](#wraptextatrange)
- [History Transforms](#history-transforms)
- [`redo`](#redo)
- [`undo`](#undo)
@@ -185,6 +187,11 @@ Wrap the [`Block`](./block.md) nodes in the current selection with a new [`Block
Wrap the [`Inline`](./inline.md) nodes in the current selection with a new [`Inline`](./inline.md) node of `type`, with optional `data`.
### `wrapText`
`wrapText(before: String, after: String) => Transform`
Surround the text in the current selection.
## Selection Transforms
@@ -370,6 +377,10 @@ Wrap the [`Block`](./block.md) nodes in a `range` with a new [`Block`](./block.m
Wrap the [`Inline`](./inline.md) nodes in a `range` with a new [`Inline`](./inline.md) node with `properties`. For convenience, you can pass a `type` string or `properties` object.
### `wrapTextAtRange`
`wrapTextAtRange(range: Selection, prefix: String, suffix: String) => Transform`
Surround the text in a `range`.
## History Transforms

View File

@@ -1137,6 +1137,32 @@ class State extends new Record(DEFAULTS) {
return state
}
/**
* Wrap the current selection with prefix/suffix.
*
* @param {String} prefix
* @param {String} suffix
* @return {State} state
*/
wrapText(prefix, suffix = prefix) {
let { document, selection } = this
let { startKey, endKey, startOffset, endOffset } = selection
let acrossBlocks = (startKey !== endKey)
document = document.wrapTextAtRange(selection, prefix, suffix)
selection = selection
.merge({
anchorKey: startKey,
anchorOffset: startOffset + prefix.length,
focusKey: endKey,
focusOffset: acrossBlocks ? endOffset : endOffset + prefix.length
})
return this.merge({ document, selection })
}
/**
* Unwrap the current selection from an inline parent with `properties`.
*

View File

@@ -45,6 +45,7 @@ const DOCUMENT_RANGE_TRANSFORMS = [
'unwrapInlineAtRange',
'wrapBlockAtRange',
'wrapInlineAtRange',
'wrapTextAtRange'
]
/**
@@ -101,7 +102,8 @@ const STATE_DOCUMENT_TRANSFORMS = [
'unwrapBlock',
'unwrapInline',
'wrapBlock',
'wrapInline'
'wrapInline',
'wrapText'
]
/**

View File

@@ -1017,6 +1017,28 @@ const Transforms = {
})
return node.normalize()
},
/**
* Wrap the text in a `range` in a prefix/suffix.
*
* @param {Selection} range
* @param {String} prefix
* @param {String} suffix
* @return {Node} node
*/
wrapTextAtRange(range, prefix, suffix = prefix) {
let withPrefix = this.insertTextAtRange(range.collapseToAnchor(), prefix)
let acrossBlocks = (range.startKey !== range.endKey)
let withSuffix = withPrefix.insertTextAtRange(
range
.collapseToFocus()
.moveForward(acrossBlocks ? 0 : prefix.length),
suffix
)
return withSuffix
}
}

View File

@@ -0,0 +1,37 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const last = texts.last()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: last.key,
focusOffset: 2
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts()
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.get(0).key,
anchorOffset: 4,
focusKey: updated.get(1).key,
focusOffset: 2,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,12 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word
- kind: block
type: paragraph
nodes:
- kind: text
text: another

View File

@@ -0,0 +1,12 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: wo[[rd
- kind: block
type: paragraph
nodes:
- kind: text
text: an]]other

View File

@@ -0,0 +1,37 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const last = texts.last()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: last.key,
focusOffset: 2
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts()
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.get(0).key,
anchorOffset: 4,
focusKey: updated.get(1).key,
focusOffset: 2,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,15 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: text
text: word
- kind: inline
type: link
nodes:
- kind: text
text: another

View File

@@ -0,0 +1,15 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: text
text: wo[[rd
- kind: inline
type: link
nodes:
- kind: text
text: an]]other

View File

@@ -0,0 +1,36 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 0,
focusKey: first.key,
focusOffset: 0
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts().get(0)
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.key,
anchorOffset: 2,
focusKey: updated.key,
focusOffset: 2,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: ""

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: "[[]]"

View File

@@ -0,0 +1,36 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: first.key,
focusOffset: 4
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts().get(0)
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.key,
anchorOffset: 4,
focusKey: updated.key,
focusOffset: 6,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: wo[[rd]]

View File

@@ -0,0 +1,36 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 1,
focusKey: first.key,
focusOffset: 3
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts().get(0)
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.key,
anchorOffset: 3,
focusKey: updated.key,
focusOffset: 5,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: w[[or]]d

View File

@@ -0,0 +1,36 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 0,
focusKey: first.key,
focusOffset: 2
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts().get(0)
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.key,
anchorOffset: 2,
focusKey: updated.key,
focusOffset: 4,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: "[[wo]]rd"

View File

@@ -0,0 +1,36 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 0,
focusKey: first.key,
focusOffset: 4
})
const next = state
.transform()
.moveTo(range)
.wrapText('[[', ']]')
.apply()
const updated = next.document.getTexts().get(0)
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.key,
anchorOffset: 2,
focusKey: updated.key,
focusOffset: 6,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: "[[word]]"

View File

@@ -0,0 +1,36 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 1,
focusKey: first.key,
focusOffset: 3
})
const next = state
.transform()
.moveTo(range)
.wrapText('**')
.apply()
const updated = next.document.getTexts().get(0)
assert.deepEqual(
next.selection.toJS(),
range.merge({
anchorKey: updated.key,
anchorOffset: 3,
focusKey: updated.key,
focusOffset: 5,
isBackward: false
}).toJS()
)
return next
}

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word

View File

@@ -0,0 +1,7 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: w**or**d