/static/js/models/placecollection.js
JavaScript | 250 lines | 128 code | 32 blank | 90 comment | 4 complexity | 157df1631faeeacd28a8879a00e2492e MD5 | raw file
Possible License(s): Apache-2.0
- define([
- 'config',
- 'underscore',
- 'models/sitecollection',
- 'models/thumbnails',
- 'lib/template',
- 'lib/urlhelper',
- 'lib/selectmodel',
- 'lib/lazily',
- 'logger',
- 'lib/errors',
- 'lib/promise',
- 'lib/bridge'
- ], function(
- config,
- util,
- SiteCollection,
- thumbnails,
- template,
- URLHelper,
- selectModel,
- lazily,
- logger,
- errors,
- Promise,
- Bridge
- ){
- var flagError = function(msg){
- return function(err) {
- logger.error.apply(logger, [msg, err]);
- };
- };
- var bridge = new Bridge();
- var __SiteCollection = SiteCollection.prototype;
- var StackPlacesCollection = SiteCollection.extend({
- // override as we need different url behavior
- initialize: function (models, options) {
- // If a stack was passed in via options, use it.
- // Overshadow the standard `stack` accessor on the prototype
- // with a new one.
- if (options) this.stack = function () { return options.stack; };
- this.urlHelper = new URLHelper({
- template: config.latticeUrl,
- tokens: {
- latticeRoot: config.latticeRoot,
- username: config.username,
- service: 'stack'
- },
- query: { v: 2 }
- });
- __SiteCollection.initialize.apply(this, arguments);
- },
- url: function (tokens, query) {
- // Calculate stack ID at URL run-time. This is a deliberate decision. It
- // allows the parent stack to be changed during the duration of this
- // object's lifetime, and also allows you to construct PlaceCollections
- // without a stack.
- tokens = util.extend({ method: this.stack().id + '/nodes' }, tokens);
- return this.urlHelper.url(tokens, query);
- },
- // Return a reference to the parent stack.
- stack: function () {
- // `Era.EraCollection.Stack`
- return this.parent().parent().parent();
- },
- // Fetch an individual place by id. Will refetch places from server
- // if ID is not found in current collection. Returns a Promise or value.
- //
- // TODO: this method should return a memoized promise object if the promise
- // resolution is in-flight.
- fetchPlace: function (place_id) {
- var places = this;
- var placesWithPlace = places.get(place_id) ?
- places : this.fetch({ diff: true});
- var placePromise = new Promise();
- Promise.when(placesWithPlace, function (places) {
- var place = places.get(place_id);
- // Resolve the promise if we found the place. Reject it if the
- // place still isn't found.
- placePromise[place ? 'resolve' : 'reject'](place);
- }, flagError("PlaceCollection fetchPlace resulted in an error"));
- return placePromise;
- },
- // Set a particular place in this collection as "selected".
- // De-select any previously selected place (modal).
- //
- // By default, retrieves the place with `get`. You can override the
- // getter used by passing a function via `options.with`. `with` function
- // may return a promise or value.
- selectPlace: function (place_id, options) {
- var place = this.get(place_id);
- // This could be decoupled, I suppose. -GB
- this.move(place, { at: 0 });
- selectModel.select.call(this, place.id);
- // This could potentially move to a method on the stack, I suppose. -GB
- this.stack().set({
- place_id: place.id,
- // TODO: we should avoid storing this information on the stack.
- // I know it comes back from the server, but perhaps we should
- // throw it away and defer to the place in the place collection.
- place_title: place.get('place_title'),
- place_url: place.get('place_url')
- });
- return this;
- },
- // Looks at the collection instance, the `stack` property and config to
- // piece together:
- //
- // * place_id
- // * place_url
- // * stack_id
- // * session_id
- // * origin
- //
- // ...and send a Bridge `changePlace` function.
- changePlace: function (place_id, options) {
- var stack = this.stack();
- var stack_id = stack.get('stack_id');
- var session_id = stack.get('session_id');
- var place = this.get(place_id);
- // Send a notification of a place change while I'm at it.
- var msg = util.extend(place.toJSON(), {
- stack_id: stack_id,
- session_id: session_id,
- origin: config.appName
- });
- bridge.changePlace(msg);
- return this;
- },
- // Decorate `SiteModels` on the way in
- // with `session_id` and `stack_id` from stack.
- //
- // These are used to issue `PUT lattice/:username/link` requests
- // via `siteModel.save()`. These should probably never change, so
- // don't worry about data binding for now.
- decorateModel: function (model) {
- var stack = this.stack();
- var decoration = {
- stack_id: stack.get('stack_id'),
- session_id: stack.get('session_id')
- };
- var set = model.set;
- // If model has a `set` method, assume they are model instances rather
- // than vanilla objects.
- return (set && 'function' === typeof set) ?
- model.set(decoration) : util.extend(model, decoration);
- },
- // Customize the `add` method.
- add: function (models, options) {
- // Decorate `SiteModels` on the way in
- // with `session_id` and `stack_id` from stack.
- //
- // There is one case where stack is `undefined` -- when instantiating
- // a `PlaceCollection`, `Backbone.Collection` calls
- // `Backbone.collection._reset`, which in turn calls `add`.
- if (this.stack()) models = util.isArray(models) ?
- util.map(models, this.decorateModel, this) :
- this.decorateModel(models);
- // Hand off to default `add` method.
- return __SiteCollection.add.call(this, models, options);
- },
- // Define a comparator function, used by Backbone to keep the
- // collection in sorted order.
- comparator: function (model) {
- // Sort models by reverse chronological order (last-accessed timestamp).
- return -1 * model.get('accessed');
- },
- // Backbone.Collection's default parse method passes sync (xhr) results
- // directly to Collection.set. We're defining a custom parse
- // implementation that massages data from our JSON API into
- // a Backbone.Model-compatible format.
- //
- // Sample return data:
- //
- // {
- // "d": [
- // {
- // stack: {
- // "title": "Join.me",
- // "id": "..."
- // },
- // place: {
- // "title": "Join.me",
- // "url": "https://join.me/",
- // "thumbnail_key": "...",
- // "id": "..."
- // },
- // "session_id": "..."
- // },
- // ...
- // ],
- // "thumbnails_job": "..."
- // }
- parse: function (resp, xhr) {
- resp = thumbnails.parse.call(this, resp, xhr);
- var results = resp.d;
- // nothing to do here
- if(!results.length) return [];
- var model = this.model,
- stack = this.stack(),
- stackAttrs = {
- session_id: stack.get('session_id'),
- stack_id: stack.id
- };
- // Translate response array using curried translator function.
- return util.map(results, function (place) {
- // Decorate with `stack_id` and `session_id`, if not passed in.
- // These are used to issue `PUT lattice/:username/link` requests
- // via `siteModel.save()`. These should probably never change, so
- // don't worry about data binding for now.
- util.defaults(place, stackAttrs);
- place = model.prototype.parse.call(this, place);
- return place;
- });
- }
- });
- return StackPlacesCollection;
- });