123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- import {
- assign,
- blankObject,
- _differs,
- _differsImmutable,
- get,
- on,
- fire
- } from './shared.js';
- function Store(state, options) {
- this._handlers = {};
- this._dependents = [];
- this._computed = blankObject();
- this._sortedComputedProperties = [];
- this._state = assign({}, state);
- this._differs = options && options.immutable ? _differsImmutable : _differs;
- }
- assign(Store.prototype, {
- _add(component, props) {
- this._dependents.push({
- component: component,
- props: props
- });
- },
- _init(props) {
- const state = {};
- for (let i = 0; i < props.length; i += 1) {
- const prop = props[i];
- state['$' + prop] = this._state[prop];
- }
- return state;
- },
- _remove(component) {
- let i = this._dependents.length;
- while (i--) {
- if (this._dependents[i].component === component) {
- this._dependents.splice(i, 1);
- return;
- }
- }
- },
- _set(newState, changed) {
- const previous = this._state;
- this._state = assign(assign({}, previous), newState);
- for (let i = 0; i < this._sortedComputedProperties.length; i += 1) {
- this._sortedComputedProperties[i].update(this._state, changed);
- }
- this.fire('state', {
- changed,
- previous,
- current: this._state
- });
- this._dependents
- .filter(dependent => {
- const componentState = {};
- let dirty = false;
- for (let j = 0; j < dependent.props.length; j += 1) {
- const prop = dependent.props[j];
- if (prop in changed) {
- componentState['$' + prop] = this._state[prop];
- dirty = true;
- }
- }
- if (dirty) {
- dependent.component._stage(componentState);
- return true;
- }
- })
- .forEach(dependent => {
- dependent.component.set({});
- });
- this.fire('update', {
- changed,
- previous,
- current: this._state
- });
- },
- _sortComputedProperties() {
- const computed = this._computed;
- const sorted = this._sortedComputedProperties = [];
- const visited = blankObject();
- let currentKey;
- function visit(key) {
- const c = computed[key];
- if (c) {
- c.deps.forEach(dep => {
- if (dep === currentKey) {
- throw new Error(`Cyclical dependency detected between ${dep} <-> ${key}`);
- }
- visit(dep);
- });
- if (!visited[key]) {
- visited[key] = true;
- sorted.push(c);
- }
- }
- }
- for (const key in this._computed) {
- visit(currentKey = key);
- }
- },
- compute(key, deps, fn) {
- let value;
- const c = {
- deps,
- update: (state, changed, dirty) => {
- const values = deps.map(dep => {
- if (dep in changed) dirty = true;
- return state[dep];
- });
- if (dirty) {
- const newValue = fn.apply(null, values);
- if (this._differs(newValue, value)) {
- value = newValue;
- changed[key] = true;
- state[key] = value;
- }
- }
- }
- };
- this._computed[key] = c;
- this._sortComputedProperties();
- const state = assign({}, this._state);
- const changed = {};
- c.update(state, changed, true);
- this._set(state, changed);
- },
- fire,
- get,
- on,
- set(newState) {
- const oldState = this._state;
- const changed = this._changed = {};
- let dirty = false;
- for (const key in newState) {
- if (this._computed[key]) throw new Error(`'${key}' is a read-only computed property`);
- if (this._differs(newState[key], oldState[key])) changed[key] = dirty = true;
- }
- if (!dirty) return;
- this._set(newState, changed);
- }
- });
- export { Store };
|