git.fiddlerwoaroof.com
src/state_container.js
272a0697
 import * as R from 'ramda';
 import {
     Map,
     fromJS
 } from 'immutable';
ee0444ba
 import { makeLens, lensTransformer, fireListeners } from './lens';
272a0697
 
7524a4a6
 let common_state = {
     get(key) {
         return this.lensFor(key).get();
     },
 
     set(key, value) {
         this.lensFor(key).set(value);
     },
 
     getState() {
         return this._currentState.toJS();
     },
 
     lensFor(key) {
         return makeLens(key instanceof Array ? key : [key], this);
     },
 
     getRecorder() {
         return new RecordingStateContainer(this);
     },
 
     commit(recorder) {
         recorder.replay(this);
     },
 
     onUpdate(listener) {
         this.listeners.push(listener);
1abf40ca
         return () => {
             this.listeners.splice(this.listeners.indexOf(listener), 1);
7524a4a6
         };
     },
 
     [fireListeners](oldState, newState) {
         this.listeners.forEach((listener) => {
             listener(oldState, newState);
         });
     },
 };
 
272a0697
 function RecordingStateContainer(container) {
     this.localStore = Map();
     this.container = container;
     this.listeners = [];
     this.actions = [];
ee0444ba
 }
272a0697
 
7524a4a6
 RecordingStateContainer.prototype = Object.assign({
272a0697
     setState(newState) {
7524a4a6
         const oldState = this._currentState;
272a0697
         this.localStore = this.localStore.merge(newState);
7524a4a6
         this.actions = [[['setState', this.localStore]]];
         this[fireListeners](oldState, this._currentState);
272a0697
     },
 
7524a4a6
     get _currentState() {
272a0697
         const con = new StateContainer(this.container.getState());
         this._replay(con);
         return con._currentState;
     },
7524a4a6
     set _currentState(value) {
         this.setState(value);
272a0697
     },
 
     _replay(container) {
         R.forEach(
             R.reduce(
                 (cur, [key, ...args]) => cur[key](...args),
                 container,
                 R.__
             ),
             this.actions
         );
     },
     replay(container) {
         if (container !== this.container) {
             throw new Error("Trying to replay into wrong parent container");
         }
         this._replay(container);
         this.localStore = Map();
         this.actions = [];
     },
7524a4a6
 }, common_state);
272a0697
 
ee0444ba
 export { lensTransformer };
 
 export default function StateContainer(data = {}) {
7524a4a6
     var state = fromJS(data);
272a0697
 
7524a4a6
     return Object.assign({
         listeners: [],
272a0697
 
         get _currentState() {
7524a4a6
             return state;
272a0697
         },
         set _currentState(value) {
7524a4a6
             state = value;
272a0697
         },
 
         /**
          * setState merges state shallowly
          * */
         setState(newState) {
             const oldState = this._currentState;
             this._currentState = this._currentState.merge(newState);
ee0444ba
             this[fireListeners](oldState, this._currentState);
272a0697
         },
7524a4a6
     }, common_state);
272a0697
 }