2018-10-29 21:58:21 +01:00
|
|
|
/**
|
2018-11-25 03:17:00 +01:00
|
|
|
* @module utils
|
2018-10-29 21:58:21 +01:00
|
|
|
*/
|
2017-10-22 19:13:03 +02:00
|
|
|
|
2019-04-04 19:35:38 +02:00
|
|
|
import {
|
|
|
|
|
getState,
|
|
|
|
|
createID,
|
|
|
|
|
writeStructsFromTransaction,
|
|
|
|
|
writeDeleteSet,
|
|
|
|
|
DeleteSet,
|
|
|
|
|
sortAndMergeDeleteSet,
|
2019-04-05 00:37:09 +02:00
|
|
|
getStates,
|
2019-04-04 19:35:38 +02:00
|
|
|
AbstractType, AbstractItem, YEvent, ItemType, Y // eslint-disable-line
|
|
|
|
|
} from '../internals.js'
|
|
|
|
|
|
2019-03-10 23:26:53 +01:00
|
|
|
import * as encoding from 'lib0/encoding.js'
|
2019-03-01 23:26:40 +01:00
|
|
|
|
2018-03-05 03:03:40 +01:00
|
|
|
/**
|
2018-03-23 04:35:52 +01:00
|
|
|
* A transaction is created for every change on the Yjs model. It is possible
|
|
|
|
|
* to bundle changes on the Yjs model in a single transaction to
|
|
|
|
|
* minimize the number on messages sent and the number of observer calls.
|
|
|
|
|
* If possible the user of this library should bundle as many changes as
|
|
|
|
|
* possible. Here is an example to illustrate the advantages of bundling:
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* const map = y.define('map', YMap)
|
|
|
|
|
* // Log content when change is triggered
|
2018-11-25 03:17:00 +01:00
|
|
|
* map.observe(() => {
|
2018-03-23 04:35:52 +01:00
|
|
|
* console.log('change triggered')
|
|
|
|
|
* })
|
|
|
|
|
* // Each change on the map type triggers a log message:
|
|
|
|
|
* map.set('a', 0) // => "change triggered"
|
|
|
|
|
* map.set('b', 0) // => "change triggered"
|
|
|
|
|
* // When put in a transaction, it will trigger the log after the transaction:
|
2018-11-25 03:17:00 +01:00
|
|
|
* y.transact(() => {
|
2018-03-23 04:35:52 +01:00
|
|
|
* map.set('a', 1)
|
|
|
|
|
* map.set('b', 1)
|
|
|
|
|
* }) // => "change triggered"
|
2018-03-05 03:03:40 +01:00
|
|
|
*
|
|
|
|
|
*/
|
2018-11-25 03:17:00 +01:00
|
|
|
export class Transaction {
|
2019-03-26 01:14:15 +01:00
|
|
|
/**
|
|
|
|
|
* @param {Y} y
|
|
|
|
|
*/
|
2017-10-22 19:13:03 +02:00
|
|
|
constructor (y) {
|
2018-03-23 04:35:52 +01:00
|
|
|
/**
|
2018-11-25 03:17:00 +01:00
|
|
|
* @type {Y} The Yjs instance.
|
2018-03-23 04:35:52 +01:00
|
|
|
*/
|
2017-10-22 19:13:03 +02:00
|
|
|
this.y = y
|
2018-03-23 04:35:52 +01:00
|
|
|
/**
|
2019-04-02 23:08:58 +02:00
|
|
|
* Describes the set of deleted items by ids
|
|
|
|
|
* @type {DeleteSet}
|
2018-03-23 04:35:52 +01:00
|
|
|
*/
|
2019-04-02 23:08:58 +02:00
|
|
|
this.deleteSet = new DeleteSet()
|
2018-03-23 04:35:52 +01:00
|
|
|
/**
|
2019-04-05 00:37:09 +02:00
|
|
|
* Holds the state before the transaction started.
|
2018-03-23 04:35:52 +01:00
|
|
|
* @type {Map<Number,Number>}
|
|
|
|
|
*/
|
2019-04-05 12:38:02 +02:00
|
|
|
this.beforeState = getStates(y.store)
|
|
|
|
|
/**
|
|
|
|
|
* Holds the state after the transaction.
|
|
|
|
|
* @type {Map<Number,Number>}
|
|
|
|
|
*/
|
2019-04-05 00:37:09 +02:00
|
|
|
this.afterState = new Map()
|
2019-03-26 01:14:15 +01:00
|
|
|
/**
|
|
|
|
|
* All types that were directly modified (property added or child
|
|
|
|
|
* inserted/deleted). New types are not included in this Set.
|
|
|
|
|
* Maps from type to parentSubs (`item._parentSub = null` for YArray)
|
2019-04-03 03:08:10 +02:00
|
|
|
* @type {Map<AbstractType<YEvent>,Set<String|null>>}
|
2019-03-26 01:14:15 +01:00
|
|
|
*/
|
|
|
|
|
this.changed = new Map()
|
2018-03-23 04:35:52 +01:00
|
|
|
/**
|
|
|
|
|
* Stores the events for the types that observe also child elements.
|
|
|
|
|
* It is mainly used by `observeDeep`.
|
2019-04-03 03:08:10 +02:00
|
|
|
* @type {Map<AbstractType<YEvent>,Array<YEvent>>}
|
2018-03-23 04:35:52 +01:00
|
|
|
*/
|
2017-11-07 22:44:43 -08:00
|
|
|
this.changedParentTypes = new Map()
|
2019-03-29 01:02:44 +01:00
|
|
|
/**
|
|
|
|
|
* @type {encoding.Encoder|null}
|
|
|
|
|
*/
|
|
|
|
|
this._updateMessage = null
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @type {encoding.Encoder}
|
|
|
|
|
*/
|
|
|
|
|
get updateMessage () {
|
|
|
|
|
if (this._updateMessage === null) {
|
|
|
|
|
const encoder = encoding.createEncoder()
|
2019-04-02 23:08:58 +02:00
|
|
|
sortAndMergeDeleteSet(this.deleteSet)
|
2019-04-05 19:46:18 +02:00
|
|
|
writeStructsFromTransaction(encoder, this)
|
2019-04-02 23:08:58 +02:00
|
|
|
writeDeleteSet(encoder, this.deleteSet)
|
2019-03-29 01:02:44 +01:00
|
|
|
this._updateMessage = encoder
|
|
|
|
|
}
|
|
|
|
|
return this._updateMessage
|
2018-05-23 14:01:00 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-03-26 01:14:15 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param {Transaction} transaction
|
|
|
|
|
*/
|
|
|
|
|
export const nextID = transaction => {
|
|
|
|
|
const y = transaction.y
|
|
|
|
|
return createID(y.clientID, getState(y.store, y.clientID))
|
|
|
|
|
}
|