mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-28 17:39:57 +02:00
fix wrapInline selecting, add rendering tests
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"mocha": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
|
@@ -72,7 +72,6 @@ class Leaf extends React.Component {
|
||||
const native = window.getSelection()
|
||||
const el = ReactDOM.findDOMNode(this).firstChild
|
||||
|
||||
|
||||
// If both the start and end are here, set the selection all at once.
|
||||
if (hasStart && hasEnd) {
|
||||
native.removeAllRanges()
|
||||
|
@@ -858,10 +858,19 @@ class State extends new Record(DEFAULTS) {
|
||||
document = document.wrapInlineAtRange(selection, type, data)
|
||||
|
||||
// Determine what the selection should be after wrapping.
|
||||
if (selection.isExpanded) {
|
||||
const start = document.getNextText(selection.startKey)
|
||||
const end = document.getPreviousText(selection.endKey)
|
||||
selection = selection.moveToRangeOf(start, end)
|
||||
if (selection.isCollapsed) {
|
||||
selection = selection
|
||||
}
|
||||
|
||||
else if (selection.startOffset == 0) {
|
||||
const text = document.getDescendant(selection.startKey)
|
||||
selection = selection.moveToRangeOf(text)
|
||||
selection = selection.normalize(document)
|
||||
}
|
||||
|
||||
else {
|
||||
const text = document.getNextText(selection.startKey)
|
||||
selection = selection.moveToRangeOf(text)
|
||||
selection = selection.normalize(document)
|
||||
}
|
||||
|
||||
|
10
test/rendering/fixtures/custom-block/index.js
Normal file
10
test/rendering/fixtures/custom-block/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
function Code(props) {
|
||||
return <pre {...props.attributes}><code>{props.children}</code></pre>
|
||||
}
|
||||
|
||||
export function renderNode(node) {
|
||||
if (node.type == 'code') return Code
|
||||
}
|
14
test/rendering/fixtures/custom-block/input.yaml
Normal file
14
test/rendering/fixtures/custom-block/input.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: word
|
||||
- kind: block
|
||||
type: code
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: another
|
15
test/rendering/fixtures/custom-block/output.html
Normal file
15
test/rendering/fixtures/custom-block/output.html
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
<div contenteditable="true">
|
||||
<div>
|
||||
<span>
|
||||
<span>word</span>
|
||||
</span>
|
||||
</div>
|
||||
<pre>
|
||||
<code>
|
||||
<span>
|
||||
<span>another</span>
|
||||
</span>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
11
test/rendering/fixtures/custom-inline/index.js
Normal file
11
test/rendering/fixtures/custom-inline/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
function Link(props) {
|
||||
const href = props.node.data.get('href')
|
||||
return <a {...props.attributes} href={href}>{props.children}</a>
|
||||
}
|
||||
|
||||
export function renderNode(node) {
|
||||
if (node.type == 'link') return Link
|
||||
}
|
13
test/rendering/fixtures/custom-inline/input.yaml
Normal file
13
test/rendering/fixtures/custom-inline/input.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: inline
|
||||
type: link
|
||||
data:
|
||||
href: https://google.com
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: word
|
10
test/rendering/fixtures/custom-inline/output.html
Normal file
10
test/rendering/fixtures/custom-inline/output.html
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
<div contenteditable="true">
|
||||
<div>
|
||||
<a href="https://google.com">
|
||||
<span>
|
||||
<span>word</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,4 @@
|
||||
|
||||
/**
|
||||
* Nothing, pure defaults.
|
||||
*/
|
11
test/rendering/fixtures/default-block-and-inline/input.yaml
Normal file
11
test/rendering/fixtures/default-block-and-inline/input.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: inline
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: word
|
10
test/rendering/fixtures/default-block-and-inline/output.html
Normal file
10
test/rendering/fixtures/default-block-and-inline/output.html
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
<div contenteditable="true">
|
||||
<div>
|
||||
<span>
|
||||
<span>
|
||||
<span>word</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
4
test/rendering/fixtures/default-block/index.js
Normal file
4
test/rendering/fixtures/default-block/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
/**
|
||||
* Nothing, pure defaults.
|
||||
*/
|
8
test/rendering/fixtures/default-block/input.yaml
Normal file
8
test/rendering/fixtures/default-block/input.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: word
|
8
test/rendering/fixtures/default-block/output.html
Normal file
8
test/rendering/fixtures/default-block/output.html
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
<div contenteditable="true">
|
||||
<div>
|
||||
<span>
|
||||
<span>word</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
10
test/rendering/fixtures/multiple-custom-block/index.js
Normal file
10
test/rendering/fixtures/multiple-custom-block/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
function Code(props) {
|
||||
return <pre {...props.attributes}><code>{props.children}</code></pre>
|
||||
}
|
||||
|
||||
export function renderNode(node) {
|
||||
if (node.type == 'code') return Code
|
||||
}
|
20
test/rendering/fixtures/multiple-custom-block/input.yaml
Normal file
20
test/rendering/fixtures/multiple-custom-block/input.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: word
|
||||
- kind: block
|
||||
type: code
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: another
|
||||
- kind: block
|
||||
type: code
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: third
|
22
test/rendering/fixtures/multiple-custom-block/output.html
Normal file
22
test/rendering/fixtures/multiple-custom-block/output.html
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
<div contenteditable="true">
|
||||
<div>
|
||||
<span>
|
||||
<span>word</span>
|
||||
</span>
|
||||
</div>
|
||||
<pre>
|
||||
<code>
|
||||
<span>
|
||||
<span>another</span>
|
||||
</span>
|
||||
</code>
|
||||
</pre>
|
||||
<pre>
|
||||
<code>
|
||||
<span>
|
||||
<span>third</span>
|
||||
</span>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
11
test/rendering/fixtures/multiple-custom-inline/index.js
Normal file
11
test/rendering/fixtures/multiple-custom-inline/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
function Link(props) {
|
||||
const href = props.node.data.get('href')
|
||||
return <a {...props.attributes} href={href}>{props.children}</a>
|
||||
}
|
||||
|
||||
export function renderNode(node) {
|
||||
if (node.type == 'link') return Link
|
||||
}
|
21
test/rendering/fixtures/multiple-custom-inline/input.yaml
Normal file
21
test/rendering/fixtures/multiple-custom-inline/input.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: inline
|
||||
type: link
|
||||
data:
|
||||
href: https://google.com
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: another
|
||||
- kind: inline
|
||||
type: link
|
||||
data:
|
||||
href: https://google.com
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: word
|
15
test/rendering/fixtures/multiple-custom-inline/output.html
Normal file
15
test/rendering/fixtures/multiple-custom-inline/output.html
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
<div contenteditable="true">
|
||||
<div>
|
||||
<a href="https://google.com">
|
||||
<span>
|
||||
<span>another</span>
|
||||
</span>
|
||||
</a>
|
||||
<a href="https://google.com">
|
||||
<span>
|
||||
<span>word</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
59
test/rendering/index.js
Normal file
59
test/rendering/index.js
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/server'
|
||||
import assert from 'assert'
|
||||
import cheerio from 'cheerio'
|
||||
import fs from 'fs'
|
||||
import readMetadata from 'read-metadata'
|
||||
import { Editor, Raw } from '../..'
|
||||
import { resolve } from 'path'
|
||||
|
||||
/**
|
||||
* Tests.
|
||||
*/
|
||||
|
||||
describe('rendering', () => {
|
||||
const tests = fs.readdirSync(resolve(__dirname, './fixtures'))
|
||||
|
||||
for (const test of tests) {
|
||||
it(test, () => {
|
||||
const dir = resolve(__dirname, './fixtures', test)
|
||||
const input = readMetadata.sync(resolve(dir, 'input.yaml'))
|
||||
const output = fs.readFileSync(resolve(dir, 'output.html'), 'utf8')
|
||||
const props = {
|
||||
state: Raw.deserialize(input),
|
||||
onChange: () => {},
|
||||
...require(dir)
|
||||
}
|
||||
|
||||
const string = ReactDOM.renderToStaticMarkup(<Editor {...props} />)
|
||||
const expected = cheerio
|
||||
.load(output)
|
||||
.html()
|
||||
.trim()
|
||||
.replace(/\n/gm, '')
|
||||
.replace(/>\s*</g, '><')
|
||||
|
||||
assert.equal(clean(string), expected)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Clean a renderer `html` string, removing dynamic attributes.
|
||||
*
|
||||
* @param {String} html
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
function clean(html) {
|
||||
const $ = cheerio.load(html)
|
||||
|
||||
$('*').each((i, el) => {
|
||||
$(el).removeAttr('data-key')
|
||||
$(el).removeAttr('data-offset-key')
|
||||
$(el).removeAttr('style')
|
||||
})
|
||||
|
||||
return $.html()
|
||||
}
|
@@ -1,2 +1,3 @@
|
||||
|
||||
import './rendering'
|
||||
import './transforms'
|
||||
|
@@ -16,7 +16,7 @@ describe('transforms', () => {
|
||||
const transforms = fs.readdirSync(dir)
|
||||
|
||||
for (const transform of transforms) {
|
||||
describe(toCamel(transform), () => {
|
||||
describe(`${toCamel(transform)}()`, () => {
|
||||
const dir = resolve(__dirname, './fixtures', transform)
|
||||
const tests = fs.readdirSync(dir)
|
||||
|
||||
|
Reference in New Issue
Block a user