fw.collection = function createCollection (configParamsOrData) { var configParams = {}; var collectionData = []; if (_.isArray(configParamsOrData)) { collectionData = configParamsOrData; } else if (_.isObject(configParamsOrData)) { configParams = configParamsOrData; collectionData = configParams.data || []; } configParams = _.extend({}, defaultCollectionConfig, configParams); var collection = fw.observableArray(); _.extend(collection, require('./collection-methods'), { isReading: fw.observable(false) }); collection[getSymbol('isCollection')] = true; collection[privateDataSymbol] = { configParams: configParams }; collection.requestInProgress = fw.pureComputed(function () { return collection.isReading(); }); if (collectionData) { collection(collectionData); } return collection; };
/** * Bootstrap an instance with router capabilities (state management, outlet control, etc). * * @param {any} instance * @param {any} configParams * @returns {object} The instance that was passed in */ function routerBootstrap (instance, configParams) { if (!instance) { throw Error('Must supply the instance to boot()'); } var descriptor = entityDescriptors.getDescriptor('router'); // bootstrap/mixin viewModel functionality viewModelBootstrap(instance, configParams, descriptor); var hasBeenBootstrapped = !_.isUndefined(instance[descriptor.isEntityDuckTag]); if (!hasBeenBootstrapped) { var privateData = instance[privateDataSymbol]; instance[descriptor.isEntityDuckTag] = true; var previousRoute; _.extend(privateData, { registerOutlet: _.partial(registerOutlet, instance), unregisterOutlet: _.partial(unregisterOutlet, instance), outlets: {}, configParams: _.extend(privateData.configParams, descriptor.resource.defaultConfig, configParams || {}) }); _.extend(instance, require('./router-methods'), { currentState: fw.observable(), currentRoute: fw.observable(), activated: fw.observable(false), routes: fw.observableArray(privateData.configParams.routes), outlets: fw.observable({}) }); instance.disposeWithInstance( instance.activated.subscribe(function routerActivation (activated) { // activate/deactivate the router when the activated flag is set if (activated) { var currentState = instance.currentState(); if (currentState) { // user set the state explicitly prior to activation, lets execute it now instance.currentRoute(instance.getRouteForState(currentState)); } else { // get the current state/route as of activation from the browser url/location instance.currentState(getLocation()); } if (!fw.router.disableHistory) { (function setupPopStateListener (eventInfo) { window[eventInfo[0]](eventInfo[1] + 'popstate', privateData.historyPopstateHandler = function popstateEventHandler (event) { instance.currentState(event.state); }, false); })(window.addEventListener ? ['addEventListener', ''] : ['attachEvent', 'on']); } } else { if (privateData.historyPopstateHandler) { (function removePopStateListener (eventInfo) { window[eventInfo[0]](eventInfo[1] + 'popstate', privateData.historyPopstateHandler); })(window.removeEventListener ? ['removeEventListener', ''] : ['detachEvent', 'on']); } } }), instance.currentState.subscribe(function evalRoute (currentState) { instance.currentRoute(instance.getRouteForState(currentState)); }), instance.currentRoute.subscribe(function execRoute (currentRoute) { // Trigger the currentRoute controller whenever the currentRoute() updates if (currentRoute && instance.activated() && !_.isEqual(previousRoute, currentRoute)) { previousRoute = currentRoute; var state = instance.currentState(); var route = currentRoute.route; var params = currentRoute.params; // register the callback for any defined fragment identifier found in the currentState if needed (after the route loads we need to trigger scrolling to the fragment) privateData.scrollToFragment = _.noop; if (_.isString(state) && state.indexOf('#') !== -1) { var fragmentIdentifier = state.split('#')[1]; privateData.scrollToFragment = function () { var elementToScrollTo = document.getElementById(fragmentIdentifier); elementToScrollTo && _.isFunction(elementToScrollTo.scrollIntoView) && elementToScrollTo.scrollIntoView(); }; } if (currentRoute.title) { window.document.title = currentRoute.title; } if (privateData.alterStateMethod && !fw.router.disableHistory) { privateData.alterStateMethod.call(history, state, null, (currentRoute.url ? privateData.configParams.baseRoute + currentRoute.url : null)); privateData.alterStateMethod = null; } _.isFunction(currentRoute.controller) && currentRoute.controller.call(instance, params); } }) ); } else { throw Error('Cannot bootstrap a ' + descriptor.entityName + ' more than once.'); } return instance; }