1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-28 09:29:49 +02:00

fix wrapInline selecting, add rendering tests

This commit is contained in:
Ian Storm Taylor
2016-07-13 18:56:03 -07:00
parent 36ddc0fa34
commit 2aa8239448
24 changed files with 292 additions and 6 deletions

View File

@@ -14,6 +14,7 @@
},
"env": {
"browser": true,
"mocha": true,
"node": true
},
"rules": {

View File

@@ -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()

View File

@@ -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)
}

View 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
}

View 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

View 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>

View 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
}

View 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

View File

@@ -0,0 +1,10 @@
<div contenteditable="true">
<div>
<a href="https://google.com">
<span>
<span>word</span>
</span>
</a>
</div>
</div>

View File

@@ -0,0 +1,4 @@
/**
* Nothing, pure defaults.
*/

View File

@@ -0,0 +1,11 @@
nodes:
- kind: block
type: default
nodes:
- kind: inline
type: default
nodes:
- kind: text
ranges:
- text: word

View File

@@ -0,0 +1,10 @@
<div contenteditable="true">
<div>
<span>
<span>
<span>word</span>
</span>
</span>
</div>
</div>

View File

@@ -0,0 +1,4 @@
/**
* Nothing, pure defaults.
*/

View File

@@ -0,0 +1,8 @@
nodes:
- kind: block
type: default
nodes:
- kind: text
ranges:
- text: word

View File

@@ -0,0 +1,8 @@
<div contenteditable="true">
<div>
<span>
<span>word</span>
</span>
</div>
</div>

View 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
}

View 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

View 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>

View 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
}

View 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

View 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
View 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()
}

View File

@@ -1,2 +1,3 @@
import './rendering'
import './transforms'

View File

@@ -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)