UNPKG

corporate-frontend-mithril

Version:

Corporate frontend MithrilJS modules

169 lines (152 loc) 4.42 kB
const Strings = require('./helpers/strings'); const ObservableSlim = require('observable-slim'); /** * DataService handles shared data and methods between components * It observers shared data changes and notify changes to other components */ module.exports = function({data}) { /** * @type {Object} * @private */ let _data = data || {}; /** * Observers * @type {Set} * @private */ let _observers = new Map(); /** * Subscribers * @type {Array} * @private */ let _subscribers = new Set(); /*-------------------------- private functions -------------------------*/ /** * Create subscriber proxy * @param keyPath {String} * @param handler * @returns {*} * @private */ let _createObservableProxy = function(keyPath , handler=_handleObservingDataChanges) { if(!_observers.has(keyPath)) { _observers.set(keyPath, ObservableSlim.create( _data[keyPath], true, (changes)=> { handler(changes, keyPath); } )); } return _observers.get(keyPath); }; /** * Subscriber proxy set handler * @param changes * @returns {boolean} - default true * @private * @override */ let _handleObservingDataChanges = function (changes, keyPath) { broadcastDataChanges(keyPath); return true; }; /** * Helper to exclude functions from view handlers * @param property * @returns {boolean} * @private */ let _validateHandlerProperty = function(property) { let excludedNames = ['on', 'off']; return !(property.startsWith('_') || (typeof this[property] !== 'function') || !Object.is(excludedNames.find((name)=>{return name === property;}), undefined)); }; /*---------------------------- public functions -------------------------*/ /** * Subscribe changes * @param keyPath * @param handler * @param instance * @returns {{id: *, key: *, proxy: *, fn: *}} */ let subscribe = function(keyPath, handler, instance) { if ( Object.is(keyPath, undefined) ) { throw new Error('keyPath is required to subscribe data service'); } if( Object.is(handler, undefined)) { throw new Error('fn is required to subscribe data service'); } const subscriber = { instance: instance, id: Strings.random(6), keyPath: keyPath, handler: handler, proxy: _createObservableProxy(keyPath), }; _subscribers.add(subscriber); return subscriber; }; /** * Unsubscribe a subscriber * @param subscriber */ let unsubscribe = function(subscriber) { _subscribers.delete(subscriber); }; /** * Unsubscribe all subscribers */ let unsubscribeAll = function() { _subscribers.clear(); }; /** * Notify all subscribers data object changes * Use it after loading the data from the server. * @param {String} keyPath - key path of the _data * @param {Object} excluded - subscriber, excluded subscriber * @example * ``` * _data.currentSite = {name: "corporate"}; * //subscribers listen to the currentSite changes * * broadcastDataChanges("currentSite"); * //tell all subscribers "currentSite" which has changed * * ``` * * An example `/src/components/style-guide/style-guide-service.js` * * @private */ let broadcastDataChanges = function(keyPath, excluded) { let data = _data[keyPath]; for (let subscriber of _subscribers) { if(Object.is(subscriber, undefined)) { return; } if(Object.is(subscriber.keyPath, keyPath) && !Object.is(excluded, subscriber)) { subscriber.handler(keyPath, data); } } }; /** * Destroy this service */ let destroy = function() { unsubscribeAll(); for (const prop in this) { if(hasOwnProperty(prop)){ delete this[prop]; } } }; return { subscribe, unsubscribe, unsubscribeAll, broadcastDataChanges, destroy, }; };