UNPKG

todomvc

Version:

> Helping you select an MV\* framework

115 lines (106 loc) 3.3 kB
(function (define) { define(function () { "use strict"; /** * Creates a strategy to push all data from a source into the consumers * in the network directly (rather than as a sequence of 'add' events * in the network) when a sync event happens. * * @description This strategy helps eliminate loops and complexities * when data providers and consumers are added at unpredictable times. * During a sync, all 'add' events are squelched while providers push * all items to all consumers. * * @param [options.providersAreConsumers] {Boolean} if truthy, providers * are also treated as consumers and receive items from other providers. * @return {Function} a network strategy function */ return function (options) { var synced, providers, consumers, undef; if (!options) options = {}; // TODO: consider putting these on the api object so they can be shared across strategies // a list of all known providers and consumers // these lists tend to be very small providers = []; consumers = []; // the adapter currently being synced synced = undef; return function syncDataDirectly (source, dest, provide, type, api) { // this strategy stops sync events before going on the network if ('sync' == type && api.isBefore()) { synced = source; try { if (provide) { // provide data onto consumers in network if (typeof source.forEach != 'function') { throw new Error('syncDataDirectly: provider doesn\'t have `forEach()`.'); } // keep track of providers add(providers, synced); // also add to consumers list, if specified if (options.providersAreConsumers) { add(consumers, synced); } // push data to all consumers forEach(consumers, function (consumer) { source.forEach(function (item) { consumer.add(item); }); }); } else { // keep track of consumers add(consumers, synced); // provide data onto consumers in network if (typeof source.add == 'function') { // consume data from all providers forEach(providers, function (provider) { provider.forEach(function (item) { synced.add(item); }); }); } } // the sync event never gets onto the network: api.cancel(); } finally { synced = undef; } } // stop 'add' events between adapters while sync'ing, but allow // strategies interested in the event to see it before else if ('add' == type && synced && !api.isBefore()) { api.cancel(); } // keep track of adapters that leave else if ('leave' == type && api.isAfter()) { // these just end up being noops if the source isn't in the list remove(providers, source); remove(consumers, source); } }; function add (list, adapter) { list.push(adapter); } function remove (list, adapter) { forEach(list, function (provider, i , providers) { if (provider == adapter) { providers.splice(i, 1); } }); } function forEach (list, lambda) { var i, obj; i = list.length; while ((obj = list[--i])) { lambda(obj, i, list); } } }; }); }( typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } ));