mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-29 09:59:48 +02:00
move groupByMarks util into Text model as methods
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
|
||||
import Leaf from './leaf'
|
||||
import React from 'react'
|
||||
import groupByMarks from '../utils/group-by-marks'
|
||||
import { List } from 'immutable'
|
||||
|
||||
/**
|
||||
@@ -59,8 +58,7 @@ class Text extends React.Component {
|
||||
|
||||
renderLeaves() {
|
||||
const { node } = this.props
|
||||
const { characters, decorations } = node
|
||||
const ranges = groupByMarks(decorations || characters)
|
||||
const ranges = node.getDecoratedRanges()
|
||||
|
||||
return ranges.map((range, i, original) => {
|
||||
const previous = original.slice(0, i)
|
||||
|
@@ -1,10 +1,19 @@
|
||||
|
||||
import Character from './character'
|
||||
import Mark from './mark'
|
||||
import groupByMarks from '../utils/group-by-marks'
|
||||
import memoize from '../utils/memoize'
|
||||
import uid from '../utils/uid'
|
||||
import { List, Record } from 'immutable'
|
||||
import { List, Record, Set } from 'immutable'
|
||||
|
||||
/**
|
||||
* Range.
|
||||
*/
|
||||
|
||||
const Range = new Record({
|
||||
kind: 'range',
|
||||
marks: new Set(),
|
||||
text: ''
|
||||
})
|
||||
|
||||
/**
|
||||
* Default properties.
|
||||
@@ -103,6 +112,16 @@ class Text extends new Record(DEFAULTS) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decorated characters grouped by marks.
|
||||
*
|
||||
* @return {List}
|
||||
*/
|
||||
|
||||
getDecoratedRanges() {
|
||||
return this.getRangesForCharacters(this.decorations || this.characters)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the characters grouped by marks.
|
||||
*
|
||||
@@ -110,7 +129,53 @@ class Text extends new Record(DEFAULTS) {
|
||||
*/
|
||||
|
||||
getRanges() {
|
||||
return groupByMarks(this.decorations || this.characters)
|
||||
return this.getRangesForCharacters(this.characters)
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the ranges for a list of `characters`.
|
||||
*
|
||||
* @param {List} characters
|
||||
* @return {List}
|
||||
*/
|
||||
|
||||
getRangesForCharacters(characters) {
|
||||
if (characters.size == 0) {
|
||||
let ranges = new List()
|
||||
ranges = ranges.push(new Range())
|
||||
return ranges
|
||||
}
|
||||
|
||||
return characters
|
||||
.toList()
|
||||
.reduce((ranges, char, i) => {
|
||||
const { marks, text } = char
|
||||
|
||||
// The first one can always just be created.
|
||||
if (i == 0) {
|
||||
return ranges.push(new Range({ text, marks }))
|
||||
}
|
||||
|
||||
// Otherwise, compare to the previous and see if a new range should be
|
||||
// created, or whether the text should be added to the previous range.
|
||||
const previous = characters.get(i - 1)
|
||||
const prevMarks = previous.marks
|
||||
const added = marks.filterNot(mark => prevMarks.includes(mark))
|
||||
const removed = prevMarks.filterNot(mark => marks.includes(mark))
|
||||
const isSame = !added.size && !removed.size
|
||||
|
||||
// If the marks are the same, add the text to the previous range.
|
||||
if (isSame) {
|
||||
const index = ranges.size - 1
|
||||
let prevRange = ranges.get(index)
|
||||
let prevText = prevRange.get('text')
|
||||
prevRange = prevRange.set('text', prevText += text)
|
||||
return ranges.set(index, prevRange)
|
||||
}
|
||||
|
||||
// Otherwise, create a new range.
|
||||
return ranges.push(new Range({ text, marks }))
|
||||
}, new List())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +234,9 @@ class Text extends new Record(DEFAULTS) {
|
||||
*/
|
||||
|
||||
memoize(Text.prototype, [
|
||||
'getRanges'
|
||||
'getDecoratedRanges',
|
||||
'getRanges',
|
||||
'getRangesForCharacters'
|
||||
])
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,6 @@ import ReactDOM from 'react-dom/server'
|
||||
import State from '../models/state'
|
||||
import Text from '../models/text'
|
||||
import cheerio from 'cheerio'
|
||||
import groupByMarks from '../utils/group-by-marks'
|
||||
import { Record } from 'immutable'
|
||||
|
||||
/**
|
||||
@@ -235,7 +234,7 @@ class Html {
|
||||
|
||||
serializeNode = (node) => {
|
||||
if (node.kind == 'text') {
|
||||
const ranges = groupByMarks(node.characters)
|
||||
const ranges = node.getRanges()
|
||||
return ranges.map(this.serializeRange)
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,6 @@ import Inline from '../models/inline'
|
||||
import Mark from '../models/mark'
|
||||
import State from '../models/state'
|
||||
import Text from '../models/text'
|
||||
import groupByMarks from '../utils/group-by-marks'
|
||||
|
||||
/**
|
||||
* Serialize a `state`.
|
||||
@@ -36,7 +35,7 @@ function serializeNode(node) {
|
||||
case 'text': {
|
||||
const obj = {}
|
||||
obj.kind = node.kind
|
||||
obj.ranges = serializeCharacters(node.characters)
|
||||
obj.ranges = serializeRanges(node)
|
||||
return obj
|
||||
}
|
||||
case 'block':
|
||||
@@ -56,14 +55,15 @@ function serializeNode(node) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a list of `characters`.
|
||||
* Serialize the ranges of a text `node`.
|
||||
*
|
||||
* @param {List} characters
|
||||
* @param {Text} text
|
||||
* @return {Array}
|
||||
*/
|
||||
|
||||
function serializeCharacters(characters) {
|
||||
return groupByMarks(characters)
|
||||
function serializeRanges(text) {
|
||||
return text
|
||||
.getRanges()
|
||||
.toArray()
|
||||
.map((range) => {
|
||||
const obj = {}
|
||||
@@ -182,7 +182,7 @@ function deserializeMark(object) {
|
||||
|
||||
export default {
|
||||
serialize,
|
||||
serializeCharacters,
|
||||
serializeRanges,
|
||||
serializeMark,
|
||||
serializeNode,
|
||||
deserialize,
|
||||
|
@@ -1,64 +0,0 @@
|
||||
|
||||
import { List, Map, Record, Set } from 'immutable'
|
||||
|
||||
/**
|
||||
* Range.
|
||||
*/
|
||||
|
||||
const Range = new Record({
|
||||
kind: 'range',
|
||||
marks: new Set(),
|
||||
text: ''
|
||||
})
|
||||
|
||||
/**
|
||||
* Group a list of `characters` into ranges by the marks they have.
|
||||
*
|
||||
* @param {List} characters
|
||||
* @return {List} ranges
|
||||
*/
|
||||
|
||||
function groupByMarks(characters) {
|
||||
if (characters.size == 0) {
|
||||
let ranges = new List()
|
||||
ranges = ranges.push(new Range())
|
||||
return ranges
|
||||
}
|
||||
|
||||
return characters
|
||||
.toList()
|
||||
.reduce((ranges, char, i) => {
|
||||
const { marks, text } = char
|
||||
|
||||
// The first one can always just be created.
|
||||
if (i == 0) {
|
||||
return ranges.push(new Range({ text, marks }))
|
||||
}
|
||||
|
||||
// Otherwise, compare to the previous and see if a new range should be
|
||||
// created, or whether the text should be added to the previous range.
|
||||
const previous = characters.get(i - 1)
|
||||
const prevMarks = previous.marks
|
||||
const added = marks.filterNot(mark => prevMarks.includes(mark))
|
||||
const removed = prevMarks.filterNot(mark => marks.includes(mark))
|
||||
const isSame = !added.size && !removed.size
|
||||
|
||||
// If the marks are the same, add the text to the previous range.
|
||||
if (isSame) {
|
||||
const index = ranges.size - 1
|
||||
let prevRange = ranges.get(index)
|
||||
let prevText = prevRange.get('text')
|
||||
prevRange = prevRange.set('text', prevText += text)
|
||||
return ranges.set(index, prevRange)
|
||||
}
|
||||
|
||||
// Otherwise, create a new range.
|
||||
return ranges.push(new Range({ text, marks }))
|
||||
}, new List())
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default groupByMarks
|
@@ -23,7 +23,7 @@ const SELECTOR = `[${ATTRIBUTE}]`
|
||||
|
||||
function findBounds(key, index, state) {
|
||||
const text = state.document.assertDescendant(key)
|
||||
const ranges = text.getRanges()
|
||||
const ranges = text.getDecoratedRanges()
|
||||
const range = ranges.get(index)
|
||||
const start = ranges
|
||||
.slice(0, index)
|
||||
|
Reference in New Issue
Block a user