Created
December 25, 2016 11:05
-
-
Save mattiamanzati/34f82da45b2caa28784cabb407c76e6c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {computed, observable, IObservableArray, extras, BaseAtom, _, intercept, IArrayWillChange, IArrayWillSplice, observe, asFlat} from 'mobx' | |
import {NodeType, NodeFactory, NodePatch} from '../core/interfaces' | |
import {Node, getNode} from '../core/node' | |
import {addHiddenFinalProp, createPatcher} from '../core/utils' | |
interface ObservableArrayAdministration<T>{ | |
values: T[] | |
atom: BaseAtom | |
updateArrayLength(oldLength: number, delta: number) | |
} | |
const patchArray = <T>(array: T[], patches: NodePatch[]) => | |
patches | |
.reduce( | |
(value: T[], patch: NodePatch) => { | |
// get a copy and if array is observable, get rid of it | |
const source = value.slice() | |
// handle the relative patching method | |
switch(patch.type){ | |
case 'update': | |
source[patch.index] = patch.newValue | |
return source | |
case 'splice': | |
source.splice(patch.index, patch.removedCount, ...patch.added) | |
return source | |
} | |
}, | |
array | |
) | |
export class ArrayNode<T> extends Node<T[]>{ | |
public readonly subType: NodeFactory<T> | |
private adm: ObservableArrayAdministration<T> | |
@observable private _patches: NodePatch[] = [] | |
constructor(subType: NodeFactory<T>){ | |
super(observable(asFlat([]))) | |
// store the default values | |
this.value = [] | |
this.subType = subType | |
// make the array reactive | |
this.adm = _.getAdministration(this.instance) | |
intercept(this.instance as IObservableArray<T>, change => { | |
this._patches.push(change) | |
return change | |
}) | |
// update the instance whenever necessary | |
observe(this.instance as IObservableArray<T>, change => { | |
this.updateInstanceArray() | |
}) | |
} | |
// update the instance | |
protected updateInstanceArray() { | |
const patchedArray = patchArray(this.value, this._patches) | |
// update the observable array and report it has changed. | |
this.adm.updateArrayLength(this.instance.length, patchedArray.length - this.instance.length) | |
this.adm.values = patchedArray | |
this.adm.atom.reportChanged() | |
} | |
acceptChanges(){ | |
// TODO: instead of applying all patches at once, perform then one by one awaiting async listeners | |
let patchedArray = patchArray(this.value, this._patches) | |
this.value = patchedArray | |
this.adm.atom.reportChanged() | |
} | |
} | |
// array | |
export function arrayOf<T>(type: NodeFactory<T>): NodeFactory<T[]>{ | |
return (state?: T[]) => | |
(new ArrayNode<T>(type)).instance | |
} | |
let rows = [] | |
let rowsBinding = arrayOf(() => ({a: 1})) | |
const doc = rowsBinding() | |
// make a change | |
doc.push({a:2}) | |
console.log(getNode(doc).instance[0], getNode(doc).value[0]) // ==> {a: 2} undefined | |
// accept changes | |
console.log('accepting changes...') | |
getNode(doc).acceptChanges() | |
console.log(getNode(doc).instance[0], getNode(doc).value[0]) // ==> {a: 2} {a: 2} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment