sententiaregum-flux-container
Version:
The flux implementation of the sententiaregum project based on facebook/flux
205 lines (165 loc) • 7.43 kB
JavaScript
/*
* This file is part of the Sententiaregum project.
*
* (c) Maximilian Bosch <maximilian.bosch.27@gmail.com>
* (c) Ben Bieler <benjaminbieler2014@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createStoreRefreshStateHandler = require('./util/createStoreRefreshStateHandler');
var _createStoreRefreshStateHandler2 = _interopRequireDefault(_createStoreRefreshStateHandler);
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
var _connect = require('./util/connect');
var _connect2 = _interopRequireDefault(_connect);
var _connector = require('./connector');
var _connector2 = _interopRequireDefault(_connector);
var _invariant = require('invariant');
var _invariant2 = _interopRequireDefault(_invariant);
var _parseArrayBrackets = require('./util/parseArrayBrackets');
var _parseArrayBrackets2 = _interopRequireDefault(_parseArrayBrackets);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Creates a flux store.
*
* @param {Object} subscriptions The configured subscriptions.
* @param {*} initialState The initial state or callback handler.
*
* @returns {{getState:Function,getStateValue:Function,getToken:Function}}
*/
exports.default = function (subscriptions, initialState) {
var state = initialState;
var emitter = new _events2.default();
var tokens = connectSubscriptions(subscriptions, []);
/**
* Factory which creates a function that updates state if something changed.
*
* @returns {Function} The change handler.
*/
function getStateSaveHandler() {
return function (newState, emitter) {
// refresh store internals
state = newState;
tokens = connectSubscriptions(subscriptions, Object.values(tokens));
// emit change
emitter.emit('change');
};
}
/**
* Connects subscriptions.
*
* @param {Object} subscriptions The subscriptions to connect with the store.
* @param {Array} oldTokens The old event tokens.
*
* @returns {Object.<String>} The processed subscriptions represented as tokens.
*/
function connectSubscriptions(subscriptions, oldTokens) {
return (0, _connect2.default)(Object.keys(subscriptions).reduce(function (config, eventName) {
var subscription = subscriptions[eventName];
return Object.assign({}, config, _defineProperty({}, eventName, {
function: (0, _createStoreRefreshStateHandler2.default)(getStateSaveHandler(), emitter, subscription, evaluateState(state)),
dependencies: typeof subscription.dependencies === 'undefined' ? subscription.dependencies : []
}));
}, {}), oldTokens);
}
/**
* Evaluates a property path written as dot notation.
* So "foo.bar.baz" will be evaluated as o['foo']['bar']['baz'].
*
* @param {Array|Object} state The state to evaluate.
* @param {String} path The property path.
*
* @returns {*} The result of the path evaluation.
*/
function evaluatePropertyPath(state, path) {
(0, _invariant2.default)(Array.isArray(state) || (typeof state === 'undefined' ? 'undefined' : _typeof(state)) === 'object', 'To evaluate a property path, the value must be an object or an array!');
return (0, _parseArrayBrackets2.default)(path).split('.').reduce(function (o, i) {
if (typeof o === 'undefined' || typeof o[i] === 'undefined') {
return;
}
return o[i];
}, state);
}
/**
* Evaluates the state inline.
* The state might be a lazy callback, so it needs to be checked whether this is true or
* the state can be returned as-is.
*
* @param {*} state The state to evaluate.
*
* @returns {*} The evaluated state.
*/
function evaluateState(state) {
return typeof state === 'function' ? state() : state;
}
return new (function () {
/**
* Constructor.
* Instantiates the class and registers the store's instance at the store<>view connector.
*
* @returns {void}
*/
function _class() {
_classCallCheck(this, _class);
(0, _connector2.default)(this).register(emitter);
}
/**
* Getter for the store's internal state.
* The state built by an internal handler will be stored as local variable in the store's scope.
* A function might be returned which will be executed lazily when the state needs to be received.
*
* @returns {*}
*/
_createClass(_class, [{
key: 'getState',
value: function getState() {
return state = evaluateState(state);
}
/**
* In a lot of cases a single item of the state is needed, nothing more.
* To fulfill this use-case this provider returns a single value of the state and provides
* a default value if the item can't be received.
*
* @param {String} path The property path.
* @param {*} defaultValue The default value.
*
* @returns {*} The value of the state to be fetched.
*/
}, {
key: 'getStateValue',
value: function getStateValue(path) {
var defaultValue = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
var search = evaluatePropertyPath(this.getState(), path);
if (typeof search === 'undefined') {
return defaultValue;
}
return search;
}
/**
* Provider for a dispatch token.
* The store listens to certain actions published by the dispatcher. Every event handler has its own
* ID generated by the dispatcher. To declare proper callback dependencies, this token is needed.
*
* @param {String} eventName The event name to look for.
*
* @returns {String}
*/
}, {
key: 'getToken',
value: function getToken(eventName) {
(0, _invariant2.default)(eventName in tokens, 'A handler for event name "' + eventName + '" must be registered in this store!');
return tokens[eventName];
}
}]);
return _class;
}())();
};