diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 000000000..3bc2f9ed4
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,128 @@
+{
+ "env": {
+ "browser": true,
+ "node": true
+ },
+ "parser": "babel-eslint",
+ "parserOptions": {
+ "ecmaFeatures": {
+ "jsx": true
+ }
+ },
+ "plugins": [
+ "import",
+ "react"
+ ],
+ "rules": {
+ "block-spacing": "error",
+ "comma-dangle": ["error", "only-multiline"],
+ "comma-spacing": ["error", { "before": false, "after": true }],
+ "comma-style": ["error", "last"],
+ "computed-property-spacing": ["error", "never"],
+ "constructor-super": "error",
+ "curly": ["error", "multi-line"],
+ "dot-location": ["error", "property"],
+ "dot-notation": ["error", { "allowKeywords": true }],
+ "eol-last": "error",
+ "func-style": ["error", "declaration"],
+ "import/default": "error",
+ "import/export": "error",
+ "import/named": "error",
+ "import/namespace": "error",
+ "import/newline-after-import": "error",
+ "import/no-deprecated": "error",
+ "import/no-extraneous-dependencies": "error",
+ "import/no-mutable-exports": "error",
+ "import/no-named-as-default": "error",
+ "import/no-named-as-default-member": "error",
+ "import/no-unresolved": "error",
+ "key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
+ "lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": true }],
+ "new-parens": "error",
+ "no-array-constructor": "error",
+ "no-class-assign": "error",
+ "no-console": "warn",
+ "no-const-assign": "error",
+ "no-debugger": "warn",
+ "no-dupe-args": "error",
+ "no-dupe-class-members": "error",
+ "no-dupe-keys": "error",
+ "no-duplicate-case": "error",
+ "no-empty": "error",
+ "no-empty-character-class": "error",
+ "no-empty-pattern": "error",
+ "no-ex-assign": "error",
+ "no-extend-native": "error",
+ "no-func-assign": "error",
+ "no-invalid-regexp": "error",
+ "no-mixed-spaces-and-tabs": ["error", false],
+ "no-multi-spaces": "error",
+ "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
+ "no-native-reassign": "error",
+ "no-negated-in-lhs": "error",
+ "no-new-object": "error",
+ "no-new-symbol": "error",
+ "no-redeclare": "error",
+ "no-regex-spaces": "error",
+ "no-sequences": "error",
+ "no-shadow": "error",
+ "no-shadow-restricted-names": "error",
+ "no-spaced-func": "error",
+ "no-throw-literal": "error",
+ "no-trailing-spaces": "error",
+ "no-undef": "error",
+ "no-unreachable": "error",
+ "no-unsafe-finally": "error",
+ "no-unused-expressions": "error",
+ "no-useless-call": "error",
+ "no-useless-computed-key": "error",
+ "no-useless-constructor": "error",
+ "no-useless-rename": "error",
+ "no-var": "error",
+ "no-void": "error",
+ "no-whitespace-before-property": "error",
+ "no-with": "error",
+ "object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
+ "object-shorthand": ["error", "always"],
+ "padded-blocks": ["error", "never"],
+ "prefer-arrow-callback": "error",
+ "prefer-rest-params": "error",
+ "prefer-spread": "error",
+ "prefer-template": "error",
+ "radix": "error",
+ "react/jsx-boolean-value": ["error", "never"],
+ "react/jsx-closing-bracket-location": "error",
+ "react/jsx-curly-spacing": ["error", "never"],
+ "react/jsx-equals-spacing": "error",
+ "react/jsx-first-prop-new-line": ["error", "multiline"],
+ "react/jsx-key": "error",
+ "react/jsx-no-bind": "error",
+ "react/jsx-no-duplicate-props": "error",
+ "react/jsx-no-undef": "error",
+ "react/jsx-space-before-closing": ["error", "always"],
+ "react/no-deprecated": "error",
+ "react/no-did-mount-set-state": "error",
+ "react/no-did-update-set-state": "error",
+ "react/no-string-refs": "error",
+ "react/no-unknown-property": "error",
+ "react/react-in-jsx-scope": "error",
+ "react/self-closing-comp": "error",
+ "react/sort-prop-types": "error",
+ "react/wrap-multilines": "error",
+ "rest-spread-spacing": ["error", "never"],
+ "semi": ["error", "never"],
+ "space-before-blocks": "error",
+ "space-before-function-paren": ["error", { "anonymous": "always", "named": "never" }],
+ "space-in-parens": "error",
+ "space-infix-ops": "error",
+ "space-unary-ops": ["error", { "words": true, "nonwords": false }],
+ "spaced-comment": ["error", "always", { "exceptions": ["-"]}],
+ "template-curly-spacing": "error",
+ "unicode-bom": ["error", "never"],
+ "use-isnan": "error",
+ "valid-jsdoc": ["error", { "prefer": { "return": "returns" }, "requireReturn": false }],
+ "valid-typeof": "error",
+ "yield-star-spacing": ["error", "after"],
+ "yoda": ["error", "never"]
+ }
+}
diff --git a/Makefile b/Makefile
index 192b85e0d..fbd01525c 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ bin = ./node_modules/.bin
babel = $(bin)/babel
browserify = $(bin)/browserify
exorcist = $(bin)/exorcist
-standard = $(bin)/standard
+eslint = $(bin)/eslint
mocha = $(bin)/mocha
mocha-phantomjs = $(bin)/mocha-phantomjs
node = node
@@ -20,6 +20,9 @@ ifeq ($(DEBUG),true)
node += debug
endif
+# Run all of the checks.
+check: lint test
+
# Remove the generated files.
clean:
@ rm -rf ./dist
@@ -46,7 +49,7 @@ install:
# Lint the sources files with Standard JS.
lint:
- @ $(standard) ./lib
+ @ $(eslint) "lib/**/*.js"
# Build the test source.
test/browser/support/build.js: $(shell find ./lib) ./test/browser.js
@@ -62,8 +65,6 @@ test: test-browser test-server
test-browser: ./test/support/build.js
@ $(mocha-phantomjs) \
--reporter spec \
- --timeout 5000 \
- --fgrep "$(GREP)" \
./test/support/browser.html
# Run the server-side tests.
@@ -72,7 +73,6 @@ test-server:
--compilers js:babel-core/register \
--require source-map-support/register \
--reporter spec \
- --timeout 5000 \
--fgrep "$(GREP)" \
./test/server.js
diff --git a/lib/components/content.js b/lib/components/content.js
index cc0b09091..4a524d91d 100644
--- a/lib/components/content.js
+++ b/lib/components/content.js
@@ -48,7 +48,7 @@ class Content extends React.Component {
* @return {Boolean} shouldUpdate
*/
- shouldComponentUpdate(props, state) {
+ shouldComponentUpdate = (props, state) => {
if (props.state.isNative) return false
return (
props.state.selection != this.props.state.selection ||
@@ -63,21 +63,21 @@ class Content extends React.Component {
* @param {Object} props
*/
- componentWillMount() {
+ componentWillMount = () => {
this.tmp.isRendering = true
}
- componentWillUpdate(props, state) {
+ componentWillUpdate = (props, state) => {
this.tmp.isRendering = true
}
- componentDidMount() {
+ componentDidMount = () => {
setTimeout(() => {
this.tmp.isRendering = false
})
}
- componentDidUpdate(props, state) {
+ componentDidUpdate = (props, state) => {
setTimeout(() => {
this.tmp.isRendering = false
})
@@ -89,7 +89,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onBeforeInput(e) {
+ onBeforeInput = (e) => {
this.props.onBeforeInput(e)
}
@@ -99,7 +99,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onBlur(e) {
+ onBlur = (e) => {
if (this.tmp.isCopying) return
let { state } = this.props
@@ -117,7 +117,7 @@ class Content extends React.Component {
* @param {State} state
*/
- onChange(state) {
+ onChange = (state) => {
this.props.onChange(state)
}
@@ -127,7 +127,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onCopy(e) {
+ onCopy = (e) => {
this.onCutCopy(e)
}
@@ -137,7 +137,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onCut(e) {
+ onCut = (e) => {
this.onCutCopy(e)
// Once the cut has successfully executed, delete the current selection.
@@ -154,7 +154,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onCutCopy(e) {
+ onCutCopy = (e) => {
const native = window.getSelection()
if (!native.rangeCount) return
@@ -207,7 +207,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onKeyDown(e) {
+ onKeyDown = (e) => {
const key = keycode(e.which)
if (
@@ -231,7 +231,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onPaste(e) {
+ onPaste = (e) => {
e.preventDefault()
const data = e.clipboardData
const { types } = data
@@ -287,7 +287,7 @@ class Content extends React.Component {
* @param {Event} e
*/
- onSelect(e) {
+ onSelect = (e) => {
if (this.tmp.isRendering) return
if (this.tmp.isCopying) return
@@ -326,7 +326,7 @@ class Content extends React.Component {
* @return {Element} element
*/
- render() {
+ render = () => {
const { state } = this.props
const { document } = state
const children = document.nodes
@@ -343,13 +343,13 @@ class Content extends React.Component {
this.onBeforeInput(e)}
- onBlur={e => this.onBlur(e)}
- onCopy={e => this.onCopy(e)}
- onCut={e => this.onCut(e)}
- onKeyDown={e => this.onKeyDown(e)}
- onPaste={e => this.onPaste(e)}
- onSelect={e => this.onSelect(e)}
+ onBeforeInput={this.onBeforeInput}
+ onBlur={this.onBlur}
+ onCopy={this.onCopy}
+ onCut={this.onCut}
+ onKeyDown={this.onKeyDown}
+ onPaste={this.onPaste}
+ onSelect={this.onSelect}
>
{children}
@@ -363,7 +363,7 @@ class Content extends React.Component {
* @return {Element} element
*/
- renderNode(node) {
+ renderNode = (node) => {
switch (node.kind) {
case 'block':
case 'inline':
@@ -380,7 +380,7 @@ class Content extends React.Component {
* @return {Element} element
*/
- renderElement(node) {
+ renderElement = (node) => {
const { editor, renderNode, state } = this.props
const Component = renderNode(node)
const children = node.nodes
@@ -411,7 +411,7 @@ class Content extends React.Component {
* @return {Element} element
*/
- renderVoid(element, node) {
+ renderVoid = (element, node) => {
const { editor, state } = this.props
return (
{
const { editor, renderMark, state } = this.props
return (
{
this.setState({ plugins: this.resolvePlugins(props) })
this.setState({ state: this.resolveState(props.state) })
}
@@ -57,7 +57,7 @@ class Editor extends React.Component {
* @return {State} state
*/
- getState() {
+ getState = () => {
return this.state.state
}
@@ -67,7 +67,7 @@ class Editor extends React.Component {
* @param {State} state
*/
- onChange(state) {
+ onChange = (state) => {
if (state == this.state.state) return
for (const plugin of this.state.plugins) {
@@ -88,7 +88,7 @@ class Editor extends React.Component {
* @param {Mixed} ...args
*/
- onEvent(name, ...args) {
+ onEvent = (name, ...args) => {
for (const plugin of this.state.plugins) {
if (!plugin[name]) continue
const newState = plugin[name](...args, this.state.state, this)
@@ -98,23 +98,53 @@ class Editor extends React.Component {
}
}
+ /**
+ * On before input.
+ *
+ * @param {Mixed} ...args
+ */
+
+ onBeforeInput = (...args) => {
+ this.onEvent('onBeforeInput', ...args)
+ }
+
+ /**
+ * On key down.
+ *
+ * @param {Mixed} ...args
+ */
+
+ onKeyDown = (...args) => {
+ this.onEvent('onKeyDown', ...args)
+ }
+
+ /**
+ * On paste.
+ *
+ * @param {Mixed} ...args
+ */
+
+ onPaste = (...args) => {
+ this.onEvent('onPaste', ...args)
+ }
+
/**
* Render the editor.
*
* @return {Element} element
*/
- render() {
+ render = () => {
return (
this.onChange(state)}
- renderMark={mark => this.renderMark(mark)}
- renderNode={node => this.renderNode(node)}
- onPaste={(e, paste) => this.onEvent('onPaste', e, paste)}
- onBeforeInput={e => this.onEvent('onBeforeInput', e)}
- onKeyDown={e => this.onEvent('onKeyDown', e)}
+ onChange={this.onChange}
+ renderMark={this.renderMark}
+ renderNode={this.renderNode}
+ onPaste={this.onPaste}
+ onBeforeInput={this.onBeforeInput}
+ onKeyDown={this.onKeyDown}
/>
)
}
@@ -126,7 +156,7 @@ class Editor extends React.Component {
* @return {Element} element
*/
- renderNode(node) {
+ renderNode = (node) => {
for (const plugin of this.state.plugins) {
if (!plugin.renderNode) continue
const component = plugin.renderNode(node, this.state.state, this)
@@ -142,7 +172,7 @@ class Editor extends React.Component {
* @return {Object} style
*/
- renderMark(mark) {
+ renderMark = (mark) => {
for (const plugin of this.state.plugins) {
if (!plugin.renderMark) continue
const style = plugin.renderMark(mark, this.state.state, this)
@@ -165,7 +195,7 @@ class Editor extends React.Component {
* @return {Array} plugins
*/
- resolvePlugins(props) {
+ resolvePlugins = (props) => {
const { onChange, plugins, ...editorPlugin } = props
return [
editorPlugin,
@@ -184,7 +214,7 @@ class Editor extends React.Component {
* @return {State} state
*/
- resolveState(state) {
+ resolveState = (state) => {
const { plugins } = this.state
let { document } = state
diff --git a/lib/components/leaf.js b/lib/components/leaf.js
index 0b465a7e9..a44aaa3be 100644
--- a/lib/components/leaf.js
+++ b/lib/components/leaf.js
@@ -14,11 +14,11 @@ class Leaf extends React.Component {
*/
static propTypes = {
+ end: React.PropTypes.number.isRequired,
marks: React.PropTypes.object.isRequired,
node: React.PropTypes.object.isRequired,
- start: React.PropTypes.number.isRequired,
- end: React.PropTypes.number.isRequired,
renderMark: React.PropTypes.func.isRequired,
+ start: React.PropTypes.number.isRequired,
state: React.PropTypes.object.isRequired,
text: React.PropTypes.string.isRequired
};
@@ -122,9 +122,9 @@ class Leaf extends React.Component {
end
})
- const style = marks.reduce((style, mark) => {
+ const style = marks.reduce((memo, mark) => {
return {
- ...style,
+ ...memo,
...renderMark(mark),
}
}, {})
@@ -134,7 +134,7 @@ class Leaf extends React.Component {
data-offset-key={offsetKey}
style={style}
>
- {text ||
}
+ {text ||
}
)
}
diff --git a/lib/components/text.js b/lib/components/text.js
index c84f50013..5b66f997d 100644
--- a/lib/components/text.js
+++ b/lib/components/text.js
@@ -62,10 +62,10 @@ class Text extends React.Component {
const { characters, decorations } = node
const ranges = groupByMarks(decorations || characters)
- return ranges.map((range, i, ranges) => {
- const previous = ranges.slice(0, i)
+ return ranges.map((range, i, original) => {
+ const previous = original.slice(0, i)
const offset = previous.size
- ? previous.map(range => range.text).join('').length
+ ? previous.map(r => r.text).join('').length
: 0
return this.renderLeaf(range, offset)
})
diff --git a/lib/components/void.js b/lib/components/void.js
index 07be30a78..5def92d80 100644
--- a/lib/components/void.js
+++ b/lib/components/void.js
@@ -19,7 +19,7 @@ class Void extends React.Component {
state: React.PropTypes.object.isRequired
};
- render() {
+ render = () => {
const { children, node } = this.props
const Tag = node.kind == 'block' ? 'div' : 'span'
const style = {
@@ -34,7 +34,7 @@ class Void extends React.Component {
)
}
- renderSpacer() {
+ renderSpacer = () => {
const style = {
position: 'absolute',
top: '0px',
@@ -49,7 +49,7 @@ class Void extends React.Component {
)
}
- renderLeaf() {
+ renderLeaf = () => {
const { node, state } = this.props
const child = node.getTextNodes().first()
const text = ''
@@ -64,7 +64,8 @@ class Void extends React.Component {
return (
this.leaf = el}
+ ref={this.renderLeafRefs}
+ renderMark={this.renderLeafMark}
key={offsetKey}
state={state}
node={child}
@@ -72,11 +73,18 @@ class Void extends React.Component {
end={end}
text={text}
marks={marks}
- renderMark={mark => {}}
/>
)
}
+ renderLeafMark = (mark) => {
+ return {}
+ }
+
+ renderLeafRefs = (el) => {
+ this.leaf = el
+ }
+
}
/**
diff --git a/lib/models/block.js b/lib/models/block.js
index a518c5750..89426814f 100644
--- a/lib/models/block.js
+++ b/lib/models/block.js
@@ -33,7 +33,7 @@ const DEFAULTS = {
* Block.
*/
-class Block extends Record(DEFAULTS) {
+class Block extends new Record(DEFAULTS) {
/**
* Create a new `Block` with `properties`.
@@ -50,7 +50,7 @@ class Block extends Record(DEFAULTS) {
properties.key = uid(4)
properties.data = Data.create(properties.data)
- properties.isVoid = !! properties.isVoid
+ properties.isVoid = !!properties.isVoid
properties.nodes = Block.createList(properties.nodes)
return new Block(properties).normalize()
diff --git a/lib/models/document.js b/lib/models/document.js
index 600105f01..d34deb6f6 100644
--- a/lib/models/document.js
+++ b/lib/models/document.js
@@ -26,7 +26,7 @@ const DEFAULTS = {
* Document.
*/
-class Document extends Record(DEFAULTS) {
+class Document extends new Record(DEFAULTS) {
/**
* Create a new `Document` with `properties`.
diff --git a/lib/models/inline.js b/lib/models/inline.js
index fee08ebbc..500f463ae 100644
--- a/lib/models/inline.js
+++ b/lib/models/inline.js
@@ -33,7 +33,7 @@ const DEFAULTS = {
* Inline.
*/
-class Inline extends Record(DEFAULTS) {
+class Inline extends new Record(DEFAULTS) {
/**
* Create a new `Inline` with `properties`.
@@ -50,7 +50,7 @@ class Inline extends Record(DEFAULTS) {
properties.key = uid(4)
properties.data = Data.create(properties.data)
- properties.isVoid = !! properties.isVoid
+ properties.isVoid = !!properties.isVoid
properties.nodes = Inline.createList(properties.nodes)
let inline = new Inline(properties)
diff --git a/lib/models/mark.js b/lib/models/mark.js
index 3a39ad081..60cc7d9c5 100644
--- a/lib/models/mark.js
+++ b/lib/models/mark.js
@@ -15,7 +15,7 @@ const DEFAULTS = {
* Mark.
*/
-class Mark extends Record(DEFAULTS) {
+class Mark extends new Record(DEFAULTS) {
/**
* Create a new `Mark` with `properties`.
diff --git a/lib/models/node.js b/lib/models/node.js
index 88c5fd952..26d13380c 100644
--- a/lib/models/node.js
+++ b/lib/models/node.js
@@ -301,8 +301,8 @@ const Node = {
getDeepestBlocks() {
const texts = this.getTextNodes()
- const set = texts.reduce((set, text) => {
- return set.add(this.getClosestBlock(text))
+ const set = texts.reduce((memo, text) => {
+ return memo.add(this.getClosestBlock(text))
}, new OrderedSet())
return set.toList()
@@ -500,7 +500,7 @@ const Node = {
// Otherwise, get a set of the marks for each character in the range.
return this
.getCharactersAtRange(range)
- .reduce((marks, char) => marks.union(char.marks), marks)
+ .reduce((memo, char) => memo.union(char.marks), marks)
},
/**
@@ -573,8 +573,8 @@ const Node = {
// Calculate the offset of the nodes before the highest child.
const child = this.getHighestChild(key)
const offset = this.nodes
- .takeUntil(node => node == child)
- .reduce((offset, child) => offset + child.length, 0)
+ .takeUntil(n => n == child)
+ .reduce((memo, n) => memo + n.length, 0)
// Recurse if need be.
return this.hasChild(key)
@@ -744,7 +744,7 @@ const Node = {
hasChild(key) {
key = normalizeKey(key)
- return !! this.nodes.find(node => node.key == key)
+ return !!this.nodes.find(node => node.key == key)
},
/**
@@ -756,7 +756,7 @@ const Node = {
hasDescendant(key) {
key = normalizeKey(key)
- return !! this.nodes.find((node) => {
+ return !!this.nodes.find((node) => {
return node.kind == 'text'
? node.key == key
: node.key == key || node.hasDescendant(key)
@@ -829,9 +829,9 @@ const Node = {
*/
mapDescendants(iterator) {
- const nodes = this.nodes.map((node, i, nodes) => {
+ const nodes = this.nodes.map((node, i, original) => {
if (node.kind != 'text') node = node.mapDescendants(iterator)
- return iterator(node, i, nodes)
+ return iterator(node, i, original)
})
return this.merge({ nodes })
@@ -850,7 +850,6 @@ const Node = {
const keys = []
node = node.mapDescendants((desc) => {
-
// That there are no duplicate keys.
if (keys.includes(desc.key)) desc = desc.set('key', uid())
keys.push(desc.key)
@@ -1026,7 +1025,7 @@ function isInRange(index, text, range) {
* Transforms.
*/
-for (var key in Transforms) {
+for (const key in Transforms) {
Node[key] = Transforms[key]
}
diff --git a/lib/models/selection.js b/lib/models/selection.js
index 178153236..7dd078d9b 100644
--- a/lib/models/selection.js
+++ b/lib/models/selection.js
@@ -18,7 +18,7 @@ const DEFAULTS = {
* Selection.
*/
-class Selection extends Record(DEFAULTS) {
+class Selection extends new Record(DEFAULTS) {
/**
* Create a new `Selection` with `properties`.
@@ -50,8 +50,8 @@ class Selection extends Record(DEFAULTS) {
get isCollapsed() {
return (
- this.anchorKey === this.focusKey &&
- this.anchorOffset === this.focusOffset
+ this.anchorKey == this.focusKey &&
+ this.anchorOffset == this.focusOffset
)
}
diff --git a/lib/models/state.js b/lib/models/state.js
index 1b403fb3d..eeda0b8ec 100644
--- a/lib/models/state.js
+++ b/lib/models/state.js
@@ -1,4 +1,5 @@
+
import Document from './document'
import Selection from './selection'
import Transform from './transform'
@@ -29,7 +30,7 @@ const DEFAULTS = {
* State.
*/
-class State extends Record(DEFAULTS) {
+class State extends new Record(DEFAULTS) {
/**
* Create a new `State` with `properties`.
@@ -465,38 +466,8 @@ class State extends Record(DEFAULTS) {
document = document.insertFragmentAtRange(selection, fragment)
// Determine what the selection should be after inserting.
- // if (texts.size == 1) {
- // after = selection
- // .moveToStart()
- // .moveForward(fragment.length)
- // }
-
- // else if (!nextText) {
- // const text = document.getTextNodes().last()
- // after = selection
- // .moveToStartOf(text)
- // .moveForward(lastText.length)
- // }
-
- // else if (nextBlock != startBlock || lastInline || startInline) {
- // const text = document.getPreviousText(nextText)
- // after = selection
- // .moveToStartOf(text)
- // .moveForward(lastText.length)
- // }
-
- // else {
- // const text = nextNextText
- // ? document.getPreviousText(nextNextText)
- // : document.getPreviousText(document.getTextNodes().last())
-
- // after = selection
- // .moveToStartOf(text)
- // .moveForward(lastText.length)
- // }
-
const keys = docTexts.map(text => text.key)
- const text = document.getTextNodes().findLast(text => !keys.includes(text.key))
+ const text = document.getTextNodes().findLast(n => !keys.includes(n.key))
after = text
? selection.moveToStartOf(text).moveForward(lastText.length)
@@ -508,9 +479,6 @@ class State extends Record(DEFAULTS) {
return state
}
-
-
-
/**
* Insert a `text` string at the current selection.
*
@@ -868,13 +836,9 @@ class State extends Record(DEFAULTS) {
document = document.wrapInlineAtRange(selection, type, data)
// Determine what the selection should be after wrapping.
- if (selection.isCollapsed) {
- selection = selection
- }
-
- else {
- const startText = document.getNextText(selection.startKey)
- const endText = document.getPreviousText(selection.endKey)
+ if (selection.isExpanded) {
+ const start = document.getNextText(selection.startKey)
+ const end = document.getPreviousText(selection.endKey)
selection = selection.moveToRangeOf(start, end)
selection = selection.normalize(document)
}
diff --git a/lib/models/text.js b/lib/models/text.js
index 4e5f0862c..82e03405b 100644
--- a/lib/models/text.js
+++ b/lib/models/text.js
@@ -19,7 +19,7 @@ const DEFAULTS = {
* Text.
*/
-class Text extends Record(DEFAULTS) {
+class Text extends new Record(DEFAULTS) {
/**
* Create a new `Text` with `properties`.
diff --git a/lib/models/transform.js b/lib/models/transform.js
index f0de04491..a1c0e164e 100644
--- a/lib/models/transform.js
+++ b/lib/models/transform.js
@@ -7,7 +7,7 @@ import { List, Record } from 'immutable'
* Snapshot, with a state-like shape.
*/
-const Snapshot = Record({
+const Snapshot = new Record({
document: null,
selection: null,
steps: new List()
@@ -17,7 +17,7 @@ const Snapshot = Record({
* Step.
*/
-const Step = Record({
+const Step = new Record({
type: null,
args: null
})
@@ -119,7 +119,7 @@ const DEFAULT_PROPERTIES = {
* Transform.
*/
-class Transform extends Record(DEFAULT_PROPERTIES) {
+class Transform extends new Record(DEFAULT_PROPERTIES) {
/**
* Create a history-ready snapshot of the current state.
@@ -183,12 +183,12 @@ class Transform extends Record(DEFAULT_PROPERTIES) {
}
// Apply each of the steps in the transform, arriving at a new state.
- state = steps.reduce((state, step) => this.applyStep(state, step), state)
+ state = steps.reduce((memo, step) => this.applyStep(memo, step), state)
// Apply the "isNative" flag, which is used to allow for natively-handled
// content changes to skip rerendering the editor for performance.
state = state.merge({
- isNative: !! options.isNative
+ isNative: !!options.isNative
})
return state
diff --git a/lib/models/transforms.js b/lib/models/transforms.js
index 3438a1cd0..b1e2cc595 100644
--- a/lib/models/transforms.js
+++ b/lib/models/transforms.js
@@ -190,7 +190,7 @@ const Transforms = {
if (!fragment.length) return node
// Make sure each node in the fragment has a unique key.
- fragment = fragment.mapDescendants(node => node.set('key', uid()))
+ fragment = fragment.mapDescendants(child => child.set('key', uid()))
// Split the inlines if need be.
if (!node.isInlineSplitAtRange(range)) {
@@ -414,8 +414,8 @@ const Transforms = {
const { startKey } = range
const firstText = node.getDescendant(startKey)
const secondText = node.getNextText(startKey)
- const firstChild = node.getFurthestInline(firstText) || firstText
- const secondChild = node.getFurthestInline(secondText) || secondText
+ let firstChild = node.getFurthestInline(firstText) || firstText
+ let secondChild = node.getFurthestInline(secondText) || secondText
let parent = node.getClosestBlock(firstChild)
let firstChildren = parent.nodes.takeUntil(n => n == firstChild).push(firstChild)
let secondChildren = parent.nodes.skipUntil(n => n == secondChild)
@@ -423,8 +423,8 @@ const Transforms = {
// While the parent is a block, split the block nodes.
while (parent && d < depth) {
- const firstChild = parent.merge({ nodes: firstChildren })
- const secondChild = Block.create({
+ firstChild = parent.merge({ nodes: firstChildren })
+ secondChild = Block.create({
nodes: secondChildren,
type: parent.type,
data: parent.data
@@ -615,7 +615,7 @@ const Transforms = {
// Find the closest wrapping blocks of each text node.
const texts = node.getBlocksAtRange(range)
- const wrappers = texts.reduce((wrappers, text) => {
+ const wrappers = texts.reduce((memo, text) => {
const match = node.getClosest(text, (parent) => {
if (parent.kind != 'block') return false
if (type && parent.type != type) return false
@@ -623,8 +623,8 @@ const Transforms = {
return true
})
- if (match) wrappers = wrappers.add(match)
- return wrappers
+ if (match) memo = memo.add(match)
+ return memo
}, new Set())
// Replace each of the wrappers with their child nodes.
@@ -669,7 +669,7 @@ const Transforms = {
// Find the closest matching inline wrappers of each text node.
const texts = this.getTextNodes()
- const wrappers = texts.reduce((wrappers, text) => {
+ const wrappers = texts.reduce((memo, text) => {
const match = node.getClosest(text, (parent) => {
if (parent.kind != 'inline') return false
if (type && parent.type != type) return false
@@ -677,8 +677,8 @@ const Transforms = {
return true
})
- if (match) wrappers = wrappers.add(match)
- return wrappers
+ if (match) memo = memo.add(match)
+ return memo
}, new Set())
// Replace each of the wrappers with their child nodes.
@@ -718,19 +718,19 @@ const Transforms = {
const da = node.getDepth(a)
const db = node.getDepth(b)
if (da == db) return 0
- if (da > db) return -1
- if (da < db) return 1
+ else if (da > db) return -1
+ else return 1
})
// Get the lowest common siblings, relative to the highest block.
const highest = sorted.first()
const depth = node.getDepth(highest)
- const siblings = blocks.reduce((siblings, block) => {
+ const siblings = blocks.reduce((memo, block) => {
const sibling = node.getDepth(block) == depth
? block
: node.getClosest(block, (p) => node.getDepth(p) == depth)
- siblings = siblings.push(sibling)
- return siblings
+ memo = memo.push(sibling)
+ return memo
}, Block.createList())
// Wrap the siblings in a new block.
@@ -745,9 +745,9 @@ const Transforms = {
const last = siblings.last()
const parent = node.getParent(highest)
const nodes = parent.nodes
- .takeUntil(node => node == first)
+ .takeUntil(n => n == first)
.push(wrapper)
- .concat(parent.nodes.skipUntil(node => node == last).rest())
+ .concat(parent.nodes.skipUntil(n => n == last).rest())
// Update the parent.
node = parent == node
diff --git a/lib/plugins/core.js b/lib/plugins/core.js
index 252679a3a..af7687985 100644
--- a/lib/plugins/core.js
+++ b/lib/plugins/core.js
@@ -6,17 +6,25 @@ import { IS_WINDOWS, IS_MAC } from '../utils/environment'
/**
* Default block renderer.
+ *
+ * @param {Object} props
+ * @return {Element} element
*/
-const DEFAULT_BLOCK = props => {props.children}
+function DEFAULT_BLOCK(props) {
+ return {props.children}
+}
/**
* Default inline renderer.
*
- * @type {Component}
+ * @param {Object} props
+ * @return {Element} element
*/
-const DEFAULT_INLINE = props => {props.children}
+function DEFAULT_INLINE(props) {
+ return {props.children}
+}
/**
* Default mark renderer.
diff --git a/lib/serializers/html.js b/lib/serializers/html.js
index 67e279c85..b2ab0cb7d 100644
--- a/lib/serializers/html.js
+++ b/lib/serializers/html.js
@@ -78,16 +78,16 @@ class Html {
let nodes = this.deserializeElements(children)
// HACK: ensure for now that all top-level inline are wrapping into a block.
- nodes = nodes.reduce((nodes, node, i, original) => {
+ nodes = nodes.reduce((memo, node, i, original) => {
if (node.kind == 'block') {
- nodes.push(node)
- return nodes
+ memo.push(node)
+ return memo
}
if (i > 0 && original[i - 1].kind != 'block') {
- const block = nodes[nodes.length - 1]
+ const block = memo[memo.length - 1]
block.nodes.push(node)
- return nodes
+ return memo
}
const block = {
@@ -96,8 +96,8 @@ class Html {
nodes: [node]
}
- nodes.push(block)
- return nodes
+ memo.push(block)
+ return memo
}, [])
const state = Raw.deserialize({ nodes })
@@ -151,9 +151,7 @@ class Html {
: ret
}
- return node
- ? node
- : next(element.children)
+ return node || next(element.children)
}
/**
diff --git a/lib/serializers/raw.js b/lib/serializers/raw.js
index 688ff3e86..4e4bd822f 100644
--- a/lib/serializers/raw.js
+++ b/lib/serializers/raw.js
@@ -7,7 +7,6 @@ import Mark from '../models/mark'
import State from '../models/state'
import Text from '../models/text'
import groupByMarks from '../utils/group-by-marks'
-import { Map } from 'immutable'
/**
* Serialize a `state`.
@@ -31,7 +30,7 @@ function serializeNode(node) {
switch (node.kind) {
case 'document': {
return {
- nodes: node.nodes.toArray().map(node => serializeNode(node))
+ nodes: node.nodes.toArray().map(child => serializeNode(child))
}
}
case 'text': {
@@ -45,11 +44,14 @@ function serializeNode(node) {
const obj = {}
obj.kind = node.kind
obj.type = node.type
- obj.nodes = node.nodes.toArray().map(node => serializeNode(node))
+ obj.nodes = node.nodes.toArray().map(child => serializeNode(child))
if (node.isVoid) obj.isVoid = node.isVoid
if (node.data.size) obj.data = node.data.toJSON()
return obj
}
+ default: {
+ throw new Error(`Unknown node kind "${node.kind}".`)
+ }
}
}
@@ -130,6 +132,9 @@ function deserializeNode(object) {
characters: deserializeRanges(object.ranges)
})
}
+ default: {
+ throw new Error(`Unknown node kind "${object.kind}".`)
+ }
}
}
@@ -145,7 +150,7 @@ function deserializeRanges(array) {
const marks = object.marks || []
const chars = object.text
.split('')
- .map(char => {
+ .map((char) => {
return Character.create({
text: char,
marks: Mark.createSet(marks.map(deserializeMark))
diff --git a/lib/utils/environment.js b/lib/utils/environment.js
index abc994f34..3c594a932 100644
--- a/lib/utils/environment.js
+++ b/lib/utils/environment.js
@@ -6,13 +6,13 @@ import Parser from 'ua-parser-js'
* Export.
*/
-export const IS_ANDROID = process.browser && browser.name === 'android'
-export const IS_CHROME = process.browser && browser.name === 'chrome'
-export const IS_EDGE = process.browser && browser.name === 'edge'
-export const IS_FIREFOX = process.browser && browser.name === 'firefox'
-export const IS_IE = process.browser && browser.name === 'ie'
-export const IS_IOS = process.browser && browser.name === 'ios'
-export const IS_MAC = process.browser && new Parser().getOS().name === 'Mac OS'
-export const IS_SAFARI = process.browser && browser.name === 'safari'
-export const IS_UBUNTU = process.browser && new Parser().getOS().name === 'Ubuntu'
+export const IS_ANDROID = process.browser && browser.name == 'android'
+export const IS_CHROME = process.browser && browser.name == 'chrome'
+export const IS_EDGE = process.browser && browser.name == 'edge'
+export const IS_FIREFOX = process.browser && browser.name == 'firefox'
+export const IS_IE = process.browser && browser.name == 'ie'
+export const IS_IOS = process.browser && browser.name == 'ios'
+export const IS_MAC = process.browser && new Parser().getOS().name == 'Mac OS'
+export const IS_SAFARI = process.browser && browser.name == 'safari'
+export const IS_UBUNTU = process.browser && new Parser().getOS().name == 'Ubuntu'
export const IS_WINDOWS = process.browser && new Parser().getOS().name.includes('Windows')
diff --git a/lib/utils/offset-key.js b/lib/utils/offset-key.js
index 908a976d6..b2516731e 100644
--- a/lib/utils/offset-key.js
+++ b/lib/utils/offset-key.js
@@ -37,7 +37,7 @@ function findKey(node) {
}
// Shouldn't get here... else we have an edge case to handle.
- console.error('No offset key found for node:', node)
+ throw new Error('No offset key found for node.')
}
/**
diff --git a/package.json b/package.json
index 3372f0bdf..89a42df6b 100644
--- a/package.json
+++ b/package.json
@@ -3,11 +3,13 @@
"version": "0.1.0",
"license": "MIT",
"repository": "git://github.com/ianstormtaylor/slate.git",
- "main": "./lib/index.js",
+ "main": "./dist/index.js",
"scripts": {
+ "prepublish": "make dist",
"test": "make test"
},
"dependencies": {
+ "cheerio": "^0.20.0",
"detect-browser": "^1.3.3",
"immutable": "^3.8.1",
"keycode": "^2.1.2",
@@ -22,14 +24,17 @@
"devDependencies": {
"babel-cli": "^6.10.1",
"babel-core": "^6.9.1",
+ "babel-eslint": "^6.1.0",
"babel-polyfill": "^6.9.1",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-0": "^6.5.0",
"babelify": "^7.3.0",
"browserify": "^13.0.1",
- "cheerio": "^0.20.0",
"component-type": "^1.2.1",
+ "eslint": "^3.0.1",
+ "eslint-plugin-import": "^1.10.2",
+ "eslint-plugin-react": "^5.2.2",
"exorcist": "^0.4.0",
"mocha": "^2.5.3",
"mocha-phantomjs": "^4.0.2",
@@ -41,11 +46,9 @@
"read-metadata": "^1.0.0",
"selection-position": "^1.0.0",
"source-map-support": "^0.4.0",
- "standard": "^7.1.2",
"to-camel-case": "^1.0.0",
"to-title-case": "^1.0.0",
- "watchify": "^3.7.0",
- "xml2js": "^0.4.16"
+ "watchify": "^3.7.0"
},
"keywords": [
"canvas",