UNPKG

kaiju

Version:

Virtual dom, observables and stateful components

178 lines (136 loc) 4.85 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Store = Store; var _observable = require('../observable'); var _message = require('../lib/message'); var _message2 = _interopRequireDefault(_message); var _log = require('../lib/log'); var _log2 = _interopRequireDefault(_log); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * A Store is an Observable that is guaranteed to have an initial value * and can be modified from the outside by messages. */ function Store(initialState, registerHandlers) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : empty; var store = {}; // Message handlers for the on(message) syntax var handlers = {}; // unsubscribe functions created by the on(observable) syntax var subscriptions = []; // List of the messages that are listened to in order to create observables var listened = {}; // Dispatching queue, when a message handler sends additional messages var queue = []; // Stack size while receiving a message var stack = 0; var receiving = false; var name = options.name; var shouldLog = options.log !== undefined ? options.log : _log2.default.message === true; var storeName = name || (registerHandlers.name ? registerHandlers.name + ' store' : 'Store'); var msg = { send: function send(m) { return store.send(m); }, // Late binding as store.send is not yet defined listen: function listen(message) { var observable = (0, _observable.Observable)(function () { var obss = listened[message._id]; if (!obss) obss = listened[message._id] = []; obss.push(observable); return function () { obss.splice(obss.indexOf(observable), 1); }; }).named(message._name); return observable; } }; function on(src, fn) { if (src._isMessage) { if (src.type === 'partiallyAppliedMessage') { console.error('You should not use on() with a partially applied message - Ignoring "' + src._name + '"'); return; } handlers[src._id] = fn; } else { var unsubscribe = src.subscribe(function (val, name) { receive(name, fn, [val]); }); subscriptions.push(unsubscribe); } } function receive(sourceName, handler, arg) { queue.push({ sourceName: sourceName, handler: handler, arg: arg }); if (stack >= 10) throw new Error('Infinite loop while handling ' + sourceName); if (receiving) return; receiving = true; var state = store.state(); try { // This loop is used in case a change in the store.state actually triggers more state changes while (queue.length) { var _queue$shift = queue.shift(), _sourceName = _queue$shift.sourceName, _handler = _queue$shift.handler, _arg = _queue$shift.arg; stack++; if (shouldLog) console.log('%c' + _sourceName + ' %creceived by %c' + storeName, 'color: #B31EA6', 'color: black', 'font-weight: bold', 'with', _arg); var result = _handler.apply(null, _arg); if (result !== undefined) state = result; if (state !== store.state() && state !== undefined) store.state(state); } } finally { receiving = false; queue.length = 0; stack = 0; } } store.state = (0, _observable.Observable)()(initialState).named(storeName + '.state'); // Eagerly activate so that any backing resource is involved now. store.state.subscribe(function (x) { return x; }); store.send = function (message) { var _id = message._id, _name = message._name, payload = message.payload; var handler = handlers[_id]; var handled = false; if (handler) { receive(_name, handler, payload); handled = true; } var obss = listened[_id]; if (obss) { obss.forEach(function (obs) { return obs(unpackPayload(payload)); }); handled = true; } if (handled) return; var unhandled = handlers[_message2.default.unhandled._id]; if (unhandled) { receive(_message2.default.unhandled._name, unhandled, [message]); return; } console.warn('Unhandled message "' + _name + '" at %c' + storeName, 'font-weight: bold'); }; store.destroy = function () { store.state._subscribers.length = 0; store.state.subscribe = noop; store.send = noop; subscriptions.forEach(function (fn) { return fn(); }); subscriptions.length = 0; }; registerHandlers({ on: on, msg: msg, state: store.state }); return store; } function unpackPayload(payload) { if (payload.length === 0) return undefined; if (payload.length === 1) return payload[0]; return payload; } var empty = {}; function noop() {}