/static/js/views/drawerviews.js
JavaScript | 257 lines | 154 code | 50 blank | 53 comment | 7 complexity | 4d8ab1a0ed904a06de1fb294ed08652e MD5 | raw file
Possible License(s): Apache-2.0
- define([
- 'underscore',
- 'backbone',
- 'views/singleview',
- 'views/listview',
- 'models/stackcollection',
- 'models/stackmodel',
- 'models/sitemodel',
- 'lib/template'
- ], function (
- util,
- Backbone,
- SingleView,
- ListView,
- StackCollection,
- StackModel,
- SiteModel,
- template
- ) {
- // Define shorthands for prototypes. This allows easy calls to `super` methods.
- var __SingleView = SingleView.prototype;
- var __ListView = ListView.prototype;
- // Place
- // ---------------------------------------------------------------------------
- var PlaceView = SingleView.extend({
- model: SiteModel,
- // Make `PlaceView` a list item. It lives in an EraView list view.
- tagName: 'li',
- className: 'accordion--item',
- template: template('<a class="place link {{selected}}" href="{place_url}"><span class="media media--ico"></span><span class="title">{place_title}</span></a>'),
- events: {
- 'click .link': 'onClick'
- },
- onClick: function (e) {
- e.preventDefault();
- e.stopPropagation();
- var model = this.model;
- // Capture the place collection from the model's collection reference.
- var prevPlaceCollection = model.collection;
- // Capture the stack reference from the placeCollection.
- var stack = prevPlaceCollection.stack();
- var nextPlaceCollection = stack.eras().at(0).places();
- // Update the accessed time so the model will be correctly sorted.
- model.set({
- accessed: Date.now()
- });
- // If the previous place collection is not the next one (in other words
- // if we're moving a place between a collection), we'll have to do some
- // hand-off work.
- if (prevPlaceCollection !== nextPlaceCollection) {
- prevPlaceCollection.remove(model);
- // Traverse back down the chain:
- //
- // 1. Grab the eras for the stack
- // 2. Get the first era (model)
- // 3. Get the places (collection) for that era
- // 4. Append the model to the places -- it will be put at the top because
- // of the comparitor on `PlaceCollection`.
- nextPlaceCollection.add(model);
- }
- // Otherwise, this is a simple move operation.
- else {
- prevPlaceCollection.move(model, { at: 0 });
- }
- nextPlaceCollection.selectPlace(model.id);
- },
- render: function () {
- var model = this.model;
- var html = this.template({
- place_title: model.get('place_title'),
- place_url: model.get('place_url'),
- selected: model.get('selected') ? 'activated' : ''
- });
- $(this.el).html(html);
- return this;
- }
- });
- // Shared static property.
- PlaceView.highestZIndex = 1;
- // Era
- // ---------------------------------------------------------------------------
- //
- // Handles rendering the styles for an "era" -- a time-span of places.
- // Era is a listview, but itself lives inside of a listview.
- var EraView = ListView.extend({
- view: PlaceView,
- tagName: 'li',
- className: 'era',
- attachPoints: {
- 'list': '.accordion--items'
- },
- template: template('<span class="era--title title">{era_title}</span><ul class="accordion--items"></ul>'),
- initialize: function (options) {
- // Requires a stackModel, or another model that implements `places`.
- this.collection = this.model.places();
- __ListView.initialize.call(this, options);
- },
- // Calculate the height of this element.
- // Does a reduce on the height of the `era` views inside, which in turn
- // does a reduce on the `height` of the individual places.
- // Returns the memoized height, unless recalculate is true.
- height: function (recalculate) {
- // If we have a memoized height, and we're not asked to recalculate,
- // return the memoized height.
- if (this._height !== undefined && !recalculate) return this._height;
- // Calculate the sum total height of all the places.
- var placesHeight = util.reduce(this.views(), function (memo, place) {
- return memo + $(place.render().el).height();
- }, 0);
- // Get the height of the era title.
- var titleHeight = this.$('.era--title').height();
- // Add them together, memoized the result and return it.
- return this._height = placesHeight + titleHeight;
- },
- _repositionViews: function () {
- // Do a reduce operation on the sub-views, recalulating where they should
- // be placed within this era. `memo` is the sum total height of the
- // views before the current view.
- util.reduce(this.views(), function (memo, place) {
- var $el = $(place.el);
- $el.css('top', memo + 'px');
- return memo + $el.height();
- }, 0);
- return this;
- },
- moveView: function (model, options) {
- var view = this.lookup(model);
- // Set this view as the highest index (one higher than all other places).
- // This will ensure it animates *over* other places.
- $(view.el).css('z-index', PlaceView.highestZIndex++);
- // Wait for move animation to finish and then move in DOM for reals.
- __ListView.moveView.call(this, model, options);
- },
- render: function () {
- // Recalculate the height of this element, and update the memoized
- // property.
- var height = this._height = this.height(true);
- $(this.el).css('height', (this.collection.length ? height : 0) + 'px');
- this._repositionViews();
- return this;
- }
- });
- // Stack
- // ---------------------------------------------------------------------------
- //
- // Handles rendering the styles for a stack containing eras.
- // StackView is a listview, but itself lives inside of a listview.
- var StackView = ListView.extend({
- view: EraView,
- tagName: 'li',
- className: 'accordion--group',
- attachPoints: {
- 'list': '.eras'
- },
- events: {
- 'click .link': 'onClick'
- },
- template: template('<a class="stack link"><span class="media media--ico"></span><span class="title">{stack_title}</span></a><ul class="eras"></ul>'),
- initialize: function (options) {
- // Requires a stackModel, or another model that implements `eras`.
- this.collection = this.model.eras();
- __ListView.initialize.call(this, options);
- this.model
- .bind('change', this.render, this)
- .bind('eras add', this.render, this)
- .bind('eras remove', this.render, this)
- .bind('places add', this.render, this)
- .bind('places remove', this.render, this);
- },
- onClick: function (e) {
- e.preventDefault();
- var stackModel = this.model;
- stackModel.collection.each(function (model) {
- if (model !== stackModel) model.set({ open: false });
- });
- stackModel.set({ open: !this.model.get('open') });
- },
- // Calculate the height of this element.
- // Does a reduce on the height of the `era` views inside, which in turn
- // does a reduce on the `height` of the individual places.
- height: function (recalculate) {
- // If we have a memoized height, and we're not asked to recalculate,
- // return the memoized height.
- if (this._height !== undefined && !recalculate) return this._height;
- return this._height = util.reduce(this.views(), function (memo, era) {
- return memo + era.render().height();
- }, 0);
- },
- render: function () {
- var model = this.model;
- var totalHeight = this.height(true);
- this.$('list').css('height', (model.get('open') ? totalHeight : 0) + 'px');
- return this;
- }
- });
- var StackListView = ListView.extend({
- view: StackView,
- tagName: 'ul',
- className: 'accordion'
- });
- return {
- PlaceView: PlaceView,
- EraView: EraView,
- StackView: StackView,
- StackListView: StackListView
- };
- });