1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-17 20:51:20 +02:00

Data property for Operation model (#2373)

* Add possibility to add arbitrary data to operations
Using a data property similar to the node models (block, inline, etc)

* Fix broken example 'Syncing Operations'
Using data property on operations that are applied
This commit is contained in:
Dundercover
2018-11-05 06:02:05 +01:00
committed by Ian Storm Taylor
parent 220dd476e3
commit b773d44ae9
5 changed files with 107 additions and 24 deletions

View File

@@ -239,35 +239,43 @@ class SyncingOperationsExample extends React.Component {
}
/**
* When editor one changes, send document-alterting operations to edtior two.
* When editor one changes, send document-altering operations to editor two.
*
* @param {Array} operations
*/
onOneChange = change => {
const ops = change.operations
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
.filter(
o =>
o.type != 'set_selection' &&
o.type != 'set_value' &&
(!o.data || !o.data.has('source'))
)
.toJS()
.map(o => ({ ...o, data: { source: 'one' } }))
setTimeout(() => {
ops.forEach(o => this.two.applyOperation(o))
})
setTimeout(() => this.two.applyOperations(ops))
}
/**
* When editor two changes, send document-alterting operations to edtior one.
* When editor two changes, send document-altering operations to editor one.
*
* @param {Array} operations
*/
onTwoChange = change => {
const ops = change.operations
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
.filter(
o =>
o.type != 'set_selection' &&
o.type != 'set_value' &&
(!o.data || !o.data.has('source'))
)
.toJS()
.map(o => ({ ...o, data: { source: 'two' } }))
setTimeout(() => {
ops.forEach(o => this.one.applyOperation(o))
})
setTimeout(() => this.one.applyOperations(ops))
}
}

View File

@@ -1,5 +1,5 @@
import isPlainObject from 'is-plain-object'
import { List, Record } from 'immutable'
import { List, Record, Map } from 'immutable'
import Mark from './mark'
import Node from './node'
@@ -16,19 +16,19 @@ import invert from '../operations/invert'
*/
const OPERATION_ATTRIBUTES = {
add_mark: ['value', 'path', 'offset', 'length', 'mark'],
insert_node: ['value', 'path', 'node'],
insert_text: ['value', 'path', 'offset', 'text', 'marks'],
merge_node: ['value', 'path', 'position', 'properties', 'target'],
move_node: ['value', 'path', 'newPath'],
remove_mark: ['value', 'path', 'offset', 'length', 'mark'],
remove_node: ['value', 'path', 'node'],
remove_text: ['value', 'path', 'offset', 'text', 'marks'],
set_mark: ['value', 'path', 'offset', 'length', 'mark', 'properties'],
set_node: ['value', 'path', 'node', 'properties'],
set_selection: ['value', 'selection', 'properties'],
set_value: ['value', 'properties'],
split_node: ['value', 'path', 'position', 'properties', 'target'],
add_mark: ['value', 'path', 'offset', 'length', 'mark', 'data'],
insert_node: ['value', 'path', 'node', 'data'],
insert_text: ['value', 'path', 'offset', 'text', 'marks', 'data'],
merge_node: ['value', 'path', 'position', 'properties', 'target', 'data'],
move_node: ['value', 'path', 'newPath', 'data'],
remove_mark: ['value', 'path', 'offset', 'length', 'mark', 'data'],
remove_node: ['value', 'path', 'node', 'data'],
remove_text: ['value', 'path', 'offset', 'text', 'marks', 'data'],
set_mark: ['value', 'path', 'offset', 'length', 'mark', 'properties', 'data'],
set_node: ['value', 'path', 'node', 'properties', 'data'],
set_selection: ['value', 'selection', 'properties', 'data'],
set_value: ['value', 'properties', 'data'],
split_node: ['value', 'path', 'position', 'properties', 'target', 'data'],
}
/**
@@ -52,6 +52,7 @@ const DEFAULTS = {
text: undefined,
type: undefined,
value: undefined,
data: undefined,
}
/**
@@ -133,6 +134,9 @@ class Operation extends Record(DEFAULTS) {
if (key == 'value') continue
if (key == 'node' && type != 'insert_node') continue
// Skip optional user defined data
if (key == 'data') continue
throw new Error(
`\`Operation.fromJSON\` was passed a "${type}" operation without the required "${key}" attribute.`
)
@@ -186,6 +190,10 @@ class Operation extends Record(DEFAULTS) {
v = Node.createProperties(v)
}
if (key === 'data') {
v = Map(v)
}
attrs[key] = v
}
@@ -303,6 +311,10 @@ class Operation extends Record(DEFAULTS) {
value = v
}
if (key === 'data' && value) {
value = value.toJSON()
}
json[key] = value
}

View File

@@ -33,6 +33,14 @@ describe('slate', () => {
assert.deepEqual(actual, expected)
})
fixtures(__dirname, 'models/operation', ({ module }) => {
const { input, output } = module
const fn = module.default
const actual = fn(input).toJSON()
const expected = output
assert.deepEqual(actual, expected)
})
fixtures(__dirname, 'models/point', ({ module }) => {
const { input, output } = module
const fn = module.default

View File

@@ -0,0 +1,28 @@
import Operation from '../../../../src/models/operation'
export const input = {
type: 'add_mark',
path: [2, 1],
offset: 3,
length: 5,
mark: 'b',
data: { info: 'user supplied text', flag: true },
}
export default function(op) {
return Operation.create(op)
}
export const output = {
object: 'operation',
type: 'add_mark',
path: [2, 1],
offset: 3,
length: 5,
mark: {
data: {},
object: 'mark',
type: 'b',
},
data: { info: 'user supplied text', flag: true },
}

View File

@@ -0,0 +1,27 @@
import Operation from '../../../../src/models/operation'
export const input = {
type: 'add_mark',
path: [2, 1],
offset: 3,
length: 5,
mark: 'b',
}
export default function(op) {
return Operation.create(op)
}
export const output = {
object: 'operation',
type: 'add_mark',
path: [2, 1],
offset: 3,
length: 5,
mark: {
data: {},
object: 'mark',
type: 'b',
},
data: undefined,
}