mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-20 06:01:24 +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:
committed by
Ian Storm Taylor
parent
220dd476e3
commit
b773d44ae9
@@ -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
|
* @param {Array} operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onOneChange = change => {
|
onOneChange = change => {
|
||||||
const ops = change.operations
|
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()
|
.toJS()
|
||||||
|
.map(o => ({ ...o, data: { source: 'one' } }))
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => this.two.applyOperations(ops))
|
||||||
ops.forEach(o => this.two.applyOperation(o))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @param {Array} operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onTwoChange = change => {
|
onTwoChange = change => {
|
||||||
const ops = change.operations
|
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()
|
.toJS()
|
||||||
|
.map(o => ({ ...o, data: { source: 'two' } }))
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => this.one.applyOperations(ops))
|
||||||
ops.forEach(o => this.one.applyOperation(o))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import isPlainObject from 'is-plain-object'
|
import isPlainObject from 'is-plain-object'
|
||||||
import { List, Record } from 'immutable'
|
import { List, Record, Map } from 'immutable'
|
||||||
|
|
||||||
import Mark from './mark'
|
import Mark from './mark'
|
||||||
import Node from './node'
|
import Node from './node'
|
||||||
@@ -16,19 +16,19 @@ import invert from '../operations/invert'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const OPERATION_ATTRIBUTES = {
|
const OPERATION_ATTRIBUTES = {
|
||||||
add_mark: ['value', 'path', 'offset', 'length', 'mark'],
|
add_mark: ['value', 'path', 'offset', 'length', 'mark', 'data'],
|
||||||
insert_node: ['value', 'path', 'node'],
|
insert_node: ['value', 'path', 'node', 'data'],
|
||||||
insert_text: ['value', 'path', 'offset', 'text', 'marks'],
|
insert_text: ['value', 'path', 'offset', 'text', 'marks', 'data'],
|
||||||
merge_node: ['value', 'path', 'position', 'properties', 'target'],
|
merge_node: ['value', 'path', 'position', 'properties', 'target', 'data'],
|
||||||
move_node: ['value', 'path', 'newPath'],
|
move_node: ['value', 'path', 'newPath', 'data'],
|
||||||
remove_mark: ['value', 'path', 'offset', 'length', 'mark'],
|
remove_mark: ['value', 'path', 'offset', 'length', 'mark', 'data'],
|
||||||
remove_node: ['value', 'path', 'node'],
|
remove_node: ['value', 'path', 'node', 'data'],
|
||||||
remove_text: ['value', 'path', 'offset', 'text', 'marks'],
|
remove_text: ['value', 'path', 'offset', 'text', 'marks', 'data'],
|
||||||
set_mark: ['value', 'path', 'offset', 'length', 'mark', 'properties'],
|
set_mark: ['value', 'path', 'offset', 'length', 'mark', 'properties', 'data'],
|
||||||
set_node: ['value', 'path', 'node', 'properties'],
|
set_node: ['value', 'path', 'node', 'properties', 'data'],
|
||||||
set_selection: ['value', 'selection', 'properties'],
|
set_selection: ['value', 'selection', 'properties', 'data'],
|
||||||
set_value: ['value', 'properties'],
|
set_value: ['value', 'properties', 'data'],
|
||||||
split_node: ['value', 'path', 'position', 'properties', 'target'],
|
split_node: ['value', 'path', 'position', 'properties', 'target', 'data'],
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,6 +52,7 @@ const DEFAULTS = {
|
|||||||
text: undefined,
|
text: undefined,
|
||||||
type: undefined,
|
type: undefined,
|
||||||
value: undefined,
|
value: undefined,
|
||||||
|
data: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,6 +134,9 @@ class Operation extends Record(DEFAULTS) {
|
|||||||
if (key == 'value') continue
|
if (key == 'value') continue
|
||||||
if (key == 'node' && type != 'insert_node') continue
|
if (key == 'node' && type != 'insert_node') continue
|
||||||
|
|
||||||
|
// Skip optional user defined data
|
||||||
|
if (key == 'data') continue
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`\`Operation.fromJSON\` was passed a "${type}" operation without the required "${key}" attribute.`
|
`\`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)
|
v = Node.createProperties(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key === 'data') {
|
||||||
|
v = Map(v)
|
||||||
|
}
|
||||||
|
|
||||||
attrs[key] = v
|
attrs[key] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,6 +311,10 @@ class Operation extends Record(DEFAULTS) {
|
|||||||
value = v
|
value = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key === 'data' && value) {
|
||||||
|
value = value.toJSON()
|
||||||
|
}
|
||||||
|
|
||||||
json[key] = value
|
json[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,14 @@ describe('slate', () => {
|
|||||||
assert.deepEqual(actual, expected)
|
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 }) => {
|
fixtures(__dirname, 'models/point', ({ module }) => {
|
||||||
const { input, output } = module
|
const { input, output } = module
|
||||||
const fn = module.default
|
const fn = module.default
|
||||||
|
@@ -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 },
|
||||||
|
}
|
@@ -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,
|
||||||
|
}
|
Reference in New Issue
Block a user