diff --git a/LICENSE.txt b/LICENSE.txt index 0d1d6da..fa6051c 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -264,3 +264,15 @@ https://github.com/moment/moment/blob/develop/LICENSE rome.js is a customizable date (and time) picker. It is Copyright © 2014 Nicolas Bevacqua https://github.com/bevacqua/rome + +Backbone.Wreqr is a message passing system for Backbone.js. +It is (c) 2012 Derick Bailey, Muted Solutions, LLC and MIT licensed: +https://github.com/marionettejs/backbone.wreqr/blob/v1.3.1/LICENSE.md + +Backbone.Babysitter manages child views for Backbone.js. +It is (c) 2013 Derick Bailey, Muted Solutions, LLC and MIT licensed: +https://github.com/marionettejs/backbone.babysitter/blob/v0.1.6/LICENSE.md + +Backbone.Marionette is a composite application library for Backbone.js. +It is MIT licensed: +https://github.com/marionettejs/backbone.marionette/blob/v2.4.1/license.txt diff --git a/htrace-core/src/web/app/app.js b/htrace-core/src/web/app/app.js index aafad1f..0bc7100 100644 --- a/htrace-core/src/web/app/app.js +++ b/htrace-core/src/web/app/app.js @@ -16,5 +16,5 @@ * specific language governing permissions and limitations * under the License. */ - -window.App = {}; \ No newline at end of file + +window.app = new Marionette.Application(); diff --git a/htrace-core/src/web/app/models/span.js b/htrace-core/src/web/app/models/span.js index 8f6ef12..306533d 100644 --- a/htrace-core/src/web/app/models/span.js +++ b/htrace-core/src/web/app/models/span.js @@ -18,7 +18,7 @@ */ // Span model -App.Span = Backbone.Model.extend({ +app.Span = Backbone.Model.extend({ "defaults": { "spanId": null, "traceId": null, @@ -53,8 +53,8 @@ App.Span = Backbone.Model.extend({ } }); -App.Spans = Backbone.PageableCollection.extend({ - model: App.Span, +app.Spans = Backbone.PageableCollection.extend({ + model: app.Span, mode: "infinite", url: "/query", state: { diff --git a/htrace-core/src/web/app/setup.js b/htrace-core/src/web/app/setup.js index 106d959..ddeec5e 100644 --- a/htrace-core/src/web/app/setup.js +++ b/htrace-core/src/web/app/setup.js @@ -17,69 +17,81 @@ * under the License. */ -var Router = Backbone.Router.extend({ +var BaseView = Backbone.Marionette.LayoutView.extend({ + "el": "body", + "regions": { + "header": "#header", + "app": "#app" + } +}); - routes: { - "": "search", - "spans/:span": "span" +var Router = Backbone.Marionette.AppRouter.extend({ + "routes": { + "": "init", + "!/search(/:query)": "search", + "!/spans/:id": "span" }, - initialize: function() { - this.spansCollection = new App.Spans(); + "initialize": function() { + // Collection + this.spansCollection = new app.Spans(); this.spansCollection.fetch(); - - this.spanViews = {}; - - this.listSpansView = new App.ListSpansView({ - "collection": this.spansCollection - }).render(); - $("#list *[role='main']").append(this.listSpansView.$el); - - this.searchView = new App.SearchView({ - "collection": this.spansCollection, - "el": $("#list").find("[role='form']") - }).render(); }, - search: function() { - $("*[role='application']").css('display', 'none'); - $("#list").show(); + "init": function() { + Backbone.history.navigate("!/search", {"trigger": true}); }, - span: function(span) { - var root = $("#span"); - - // Cache views to avoid leaks - if (!(span in this.spanViews)) { - var model = this.spansCollection.findWhere({ - "spanId": span - }); + "search": function(query) { + var top = new app.SearchView(); + app.root.app.show(top); - if (!model) { - urlconf.navigate("/", true); - return; - } - - this.spanViews[span] = new App.SpanView({ - "model": model, - "id": "span-details" - }); - } - - var view = this.spanViews[span]; - - $("*[role='application']").css('display', 'none'); - - view.render(); - root.find("*[role='main']").empty(); - root.find("*[role='main']").append(view.$el); + top.controls.show(new app.SearchControlsView({ + "collection": this.spansCollection + })); + top.main.show(new Backgrid.Grid({ + "collection": this.spansCollection, + "columns": [{ + "name": "spanId", + "label": "ID", + "cell": "string", + "editable": false + }, { + "name": "description", + "label": "Description", + "cell": "string", + "editable": false + }], + "row": Backgrid.Row.extend({ + "events": { + "click": "details" + }, + "details": function() { + Backbone.history.navigate("!/spans/" + this.model.get("spanId"), {"trigger": true}); + } + }) + })); + top.pagination.show(new Backgrid.Extension.Paginator({ + collection: this.spansCollection, + })); + }, - root.show(); + "span": function(id) { + var top = new app.DetailsView(); + app.root.app.show(top); + top.span.show(new app.SpanDetailsView({ + "model": this.spansCollection.findWhere({ + "spanId": id + }) + })); } }); -window.urlconf = new Router(); +app.on("start", function(options) { + app.root = new BaseView(); + app.routes = new Router(); -$(function() { Backbone.history.start(); }); + +app.start(); diff --git a/htrace-core/src/web/app/views/details/details.js b/htrace-core/src/web/app/views/details/details.js new file mode 100644 index 0000000..2a2b9f4 --- /dev/null +++ b/htrace-core/src/web/app/views/details/details.js @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +app.DetailsView = Backbone.Marionette.LayoutView.extend({ + "template": "#details-layout-template", + "regions": { + "span": "div[role='complementary']", + "content": "div[role='main']" + } +}); + +app.SpanDetailsView = Backbone.Marionette.ItemView.extend({ + "className": "span", + "template": "#span-details-template", + + "serializeData": function() { + var context = { + "span": this.model.toJSON() + }; + context["span"]["duration"] = this.model.duration(); + return context; + } +}); diff --git a/htrace-core/src/web/app/views/search/field.js b/htrace-core/src/web/app/views/search/field.js index 6dea522..34b0110 100644 --- a/htrace-core/src/web/app/views/search/field.js +++ b/htrace-core/src/web/app/views/search/field.js @@ -17,7 +17,7 @@ * under the License. */ -App.SearchFieldView = Backbone.View.extend({ +app.SearchFieldView = Backbone.View.extend({ 'className': 'search-field', 'template': _.template($("#search-field-template").html()), diff --git a/htrace-core/src/web/app/views/search/search.js b/htrace-core/src/web/app/views/search/search.js index 27bdbf4..9d56bdd 100644 --- a/htrace-core/src/web/app/views/search/search.js +++ b/htrace-core/src/web/app/views/search/search.js @@ -17,16 +17,26 @@ * under the License. */ -App.SearchView = Backbone.View.extend({ +app.SearchView = Backbone.Marionette.LayoutView.extend({ + "template": "#search-layout-template", + "regions": { + "controls": "div[role='form']", + "main": "div[role='main']", + "pagination": "div[role='complementary']" + } +}); + +app.SearchControlsView = Backbone.Marionette.View.extend({ + "template": _.template($("#search-controls-template").html()), "events": { "click a.add-field": "addSearchField", "click button.search": "search", }, - 'initialize': function() { + "initialize": function() { this.predicates = []; this.searchFields = []; - this.searchFields.push(new App.SearchFieldView({ + this.searchFields.push(new app.SearchFieldView({ predicates: this.predicates, manager: this, field: 'description' @@ -34,24 +44,25 @@ App.SearchView = Backbone.View.extend({ this.on('removeSearchField', this.removeSearchField, this); }, - 'render': function() { - this.$('.search-fields').append(this.searchFields[0].render().$el); + "render": function() { + this.$el.html(this.template()); + $(this.$el).find('.search-fields').append(this.searchFields[0].render().$el); return this; }, - 'addSearchField': function(e) { + "addSearchField": function(e) { var target = $(e.target); $('button.field').text(target.text()); - var newSearchField = new App.SearchFieldView({ + var newSearchField = new app.SearchFieldView({ predicates: this.predicates, manager: this, field: target.data('field') }); - this.$('.search-fields').append(newSearchField.render().$el); + $(this.$el).find('.search-fields').append(newSearchField.render().$el); this.searchFields.push(newSearchField); }, - 'removeSearchField': function(cid) { + "removeSearchField": function(cid) { var removedFieldIndex = _(this.searchFields).indexOf(_(this.searchFields).findWhere({cid: cid})); this.searchFields.splice(removedFieldIndex, 1); }, @@ -67,6 +78,7 @@ App.SearchView = Backbone.View.extend({ fetch: false, resetState: true }); + this.collection.fullCollection.reset(); this.collection.setPredicates(this.predicates); this.collection.fetch(); diff --git a/htrace-core/src/web/app/views/span.js b/htrace-core/src/web/app/views/span.js deleted file mode 100644 index cbb694d..0000000 --- a/htrace-core/src/web/app/views/span.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -App.SpanView = Backbone.View.extend({ - "tagName": "div", - "className": "span", - "template": _.template($("#span-details-template").html()), - - initialize: function() { - _.bindAll(this, "render"); - this.model.bind('change', this.render); - - this.rendered = false; - }, - - "render": function() { - var context = { - "span": this.model.toJSON() - }; - context["span"]["duration"] = this.model.duration(); - - if (this.rendered) { - $(this.el).empty(); - } - - $(this.el).append(this.template(context)); - this.rendered = true; - - return this; - } -}); - -App.ListSpansView = Backbone.View.extend({ - "tagName": "div", - - "initialize": function() { - this.rendered = false; - - this.listSpansView = new Backgrid.Grid({ - collection: this.collection, - columns: [{ - name: "spanId", - label: "ID", - cell: "string", - editable: false - }, { - name: "description", - label: "Description", - cell: "string", - editable: false - }], - row: Backgrid.Row.extend({ - events: { - "click": "details" - }, - details: function() { - urlconf.navigate("/spans/" + this.model.get("spanId"), true); - } - }) - }); - - this.listSpansPaginator = new Backgrid.Extension.Paginator({ - collection: this.collection, - }); - }, - - "render": function() { - $(this.listSpansView.$el).detach(); - $(this.listSpansPaginator.$el).detach(); - - this.listSpansView.render(); - this.listSpansPaginator.render(); - - $(this.$el).append(this.listSpansView.$el); - $(this.$el).append(this.listSpansPaginator.$el); - - return this; - } -}); - diff --git a/htrace-core/src/web/index.html b/htrace-core/src/web/index.html index 4fbc3ac..c57bc4c 100644 --- a/htrace-core/src/web/index.html +++ b/htrace-core/src/web/index.html @@ -36,7 +36,7 @@ -
+ -
+
+ +
+ + -
-
-
-
-
-

Controls

+ + - - + @@ -192,9 +189,9 @@ - + diff --git a/htrace-core/src/web/lib/js/backbone.marionette-2.4.1.min.js b/htrace-core/src/web/lib/js/backbone.marionette-2.4.1.min.js new file mode 100644 index 0000000..994efee --- /dev/null +++ b/htrace-core/src/web/lib/js/backbone.marionette-2.4.1.min.js @@ -0,0 +1,23 @@ +// MarionetteJS (Backbone.Marionette) +// ---------------------------------- +// v2.4.1 +// +// Copyright (c)2015 Derick Bailey, Muted Solutions, LLC. +// Distributed under MIT license +// +// http://marionettejs.com + + +/*! + * Includes BabySitter + * https://github.com/marionettejs/backbone.babysitter/ + * + * Includes Wreqr + * https://github.com/marionettejs/backbone.wreqr/ + */ + + + +!function(a,b){if("function"==typeof define&&define.amd)define(["backbone","underscore"],function(c,d){return a.Marionette=a.Mn=b(a,c,d)});else if("undefined"!=typeof exports){var c=require("backbone"),d=require("underscore");module.exports=b(a,c,d)}else a.Marionette=a.Mn=b(a,a.Backbone,a._)}(this,function(a,b,c){"use strict";!function(a,b){var c=a.ChildViewContainer;return a.ChildViewContainer=function(a,b){var c=function(a){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),b.each(a,this.add,this)};b.extend(c.prototype,{add:function(a,b){var c=a.cid;return this._views[c]=a,a.model&&(this._indexByModel[a.model.cid]=c),b&&(this._indexByCustom[b]=c),this._updateLength(),this},findByModel:function(a){return this.findByModelCid(a.cid)},findByModelCid:function(a){var b=this._indexByModel[a];return this.findByCid(b)},findByCustom:function(a){var b=this._indexByCustom[a];return this.findByCid(b)},findByIndex:function(a){return b.values(this._views)[a]},findByCid:function(a){return this._views[a]},remove:function(a){var c=a.cid;return a.model&&delete this._indexByModel[a.model.cid],b.any(this._indexByCustom,function(a,b){return a===c?(delete this._indexByCustom[b],!0):void 0},this),delete this._views[c],this._updateLength(),this},call:function(a){this.apply(a,b.tail(arguments))},apply:function(a,c){b.each(this._views,function(d){b.isFunction(d[a])&&d[a].apply(d,c||[])})},_updateLength:function(){this.length=b.size(this._views)}});var d=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck","reduce"];return b.each(d,function(a){c.prototype[a]=function(){var c=b.values(this._views),d=[c].concat(b.toArray(arguments));return b[a].apply(b,d)}}),c}(a,b),a.ChildViewContainer.VERSION="0.1.6",a.ChildViewContainer.noConflict=function(){return a.ChildViewContainer=c,this},a.ChildViewContainer}(b,c),function(a,b){var c=a.Wreqr,d=a.Wreqr={};return a.Wreqr.VERSION="1.3.1",a.Wreqr.noConflict=function(){return a.Wreqr=c,this},d.Handlers=function(a,b){var c=function(a){this.options=a,this._wreqrHandlers={},b.isFunction(this.initialize)&&this.initialize(a)};return c.extend=a.Model.extend,b.extend(c.prototype,a.Events,{setHandlers:function(a){b.each(a,function(a,c){var d=null;b.isObject(a)&&!b.isFunction(a)&&(d=a.context,a=a.callback),this.setHandler(c,a,d)},this)},setHandler:function(a,b,c){var d={callback:b,context:c};this._wreqrHandlers[a]=d,this.trigger("handler:add",a,b,c)},hasHandler:function(a){return!!this._wreqrHandlers[a]},getHandler:function(a){var b=this._wreqrHandlers[a];if(b)return function(){var a=Array.prototype.slice.apply(arguments);return b.callback.apply(b.context,a)}},removeHandler:function(a){delete this._wreqrHandlers[a]},removeAllHandlers:function(){this._wreqrHandlers={}}}),c}(a,b),d.CommandStorage=function(){var c=function(a){this.options=a,this._commands={},b.isFunction(this.initialize)&&this.initialize(a)};return b.extend(c.prototype,a.Events,{getCommands:function(a){var b=this._commands[a];return b||(b={command:a,instances:[]},this._commands[a]=b),b},addCommand:function(a,b){var c=this.getCommands(a);c.instances.push(b)},clearCommands:function(a){var b=this.getCommands(a);b.instances=[]}}),c}(),d.Commands=function(a){return a.Handlers.extend({storageType:a.CommandStorage,constructor:function(b){this.options=b||{},this._initializeStorage(this.options),this.on("handler:add",this._executeCommands,this);var c=Array.prototype.slice.call(arguments);a.Handlers.prototype.constructor.apply(this,c)},execute:function(a,b){a=arguments[0],b=Array.prototype.slice.call(arguments,1),this.hasHandler(a)?this.getHandler(a).apply(this,b):this.storage.addCommand(a,b)},_executeCommands:function(a,c,d){var e=this.storage.getCommands(a);b.each(e.instances,function(a){c.apply(d,a)}),this.storage.clearCommands(a)},_initializeStorage:function(a){var c,d=a.storageType||this.storageType;c=b.isFunction(d)?new d:d,this.storage=c}})}(d),d.RequestResponse=function(a){return a.Handlers.extend({request:function(){var a=arguments[0],b=Array.prototype.slice.call(arguments,1);return this.hasHandler(a)?this.getHandler(a).apply(this,b):void 0}})}(d),d.EventAggregator=function(a,b){var c=function(){};return c.extend=a.Model.extend,b.extend(c.prototype,a.Events),c}(a,b),d.Channel=function(){var c=function(b){this.vent=new a.Wreqr.EventAggregator,this.reqres=new a.Wreqr.RequestResponse,this.commands=new a.Wreqr.Commands,this.channelName=b};return b.extend(c.prototype,{reset:function(){return this.vent.off(),this.vent.stopListening(),this.reqres.removeAllHandlers(),this.commands.removeAllHandlers(),this},connectEvents:function(a,b){return this._connect("vent",a,b),this},connectCommands:function(a,b){return this._connect("commands",a,b),this},connectRequests:function(a,b){return this._connect("reqres",a,b),this},_connect:function(a,c,d){if(c){d=d||this;var e="vent"===a?"on":"setHandler";b.each(c,function(c,f){this[a][e](f,b.bind(c,d))},this)}}}),c}(d),d.radio=function(a){var c=function(){this._channels={},this.vent={},this.commands={},this.reqres={},this._proxyMethods()};b.extend(c.prototype,{channel:function(a){if(!a)throw new Error("Channel must receive a name");return this._getChannel(a)},_getChannel:function(b){var c=this._channels[b];return c||(c=new a.Channel(b),this._channels[b]=c),c},_proxyMethods:function(){b.each(["vent","commands","reqres"],function(a){b.each(d[a],function(b){this[a][b]=e(this,a,b)},this)},this)}});var d={vent:["on","off","trigger","once","stopListening","listenTo","listenToOnce"],commands:["execute","setHandler","setHandlers","removeHandler","removeAllHandlers"],reqres:["request","setHandler","setHandlers","removeHandler","removeAllHandlers"]},e=function(a,b,c){return function(d){var e=a._getChannel(d)[b],f=Array.prototype.slice.call(arguments,1);return e[c].apply(e,f)}};return new c}(d),a.Wreqr}(b,c);var d=a.Marionette,e=a.Mn,f=b.Marionette={};f.VERSION="2.4.1",f.noConflict=function(){return a.Marionette=d,a.Mn=e,this},b.Marionette=f,f.Deferred=b.$.Deferred,f.extend=b.Model.extend,f.isNodeAttached=function(a){return b.$.contains(document.documentElement,a)},f.mergeOptions=function(a,b){a&&c.extend(this,c.pick(a,b))},f.getOption=function(a,b){return a&&b?a.options&&void 0!==a.options[b]?a.options[b]:a[b]:void 0},f.proxyGetOption=function(a){return f.getOption(this,a)},f._getValue=function(a,b,d){return c.isFunction(a)&&(a=d?a.apply(b,d):a.call(b)),a},f.normalizeMethods=function(a){return c.reduce(a,function(a,b,d){return c.isFunction(b)||(b=this[b]),b&&(a[d]=b),a},{},this)},f.normalizeUIString=function(a,b){return a.replace(/@ui\.[a-zA-Z_$0-9]*/g,function(a){return b[a.slice(4)]})},f.normalizeUIKeys=function(a,b){return c.reduce(a,function(a,c,d){var e=f.normalizeUIString(d,b);return a[e]=c,a},{})},f.normalizeUIValues=function(a,b,d){return c.each(a,function(e,g){c.isString(e)?a[g]=f.normalizeUIString(e,b):c.isObject(e)&&c.isArray(d)&&(c.extend(e,f.normalizeUIValues(c.pick(e,d),b)),c.each(d,function(a){var d=e[a];c.isString(d)&&(e[a]=f.normalizeUIString(d,b))}))}),a},f.actAsCollection=function(a,b){var d=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck"];c.each(d,function(d){a[d]=function(){var a=c.values(c.result(this,b)),e=[a].concat(c.toArray(arguments));return c[d].apply(c,e)}})};var g=f.deprecate=function(a,b){c.isObject(a)&&(a=a.prev+" is going to be removed in the future. Please use "+a.next+" instead."+(a.url?" See: "+a.url:"")),void 0!==b&&b||g._cache[a]||(g._warn("Deprecation warning: "+a),g._cache[a]=!0)};g._warn="undefined"!=typeof console&&(console.warn||console.log)||function(){},g._cache={},f._triggerMethod=function(){function a(a,b,c){return c.toUpperCase()}var b=/(^|:)(\w)/gi;return function(d,e,f){var g=arguments.length<3;g&&(f=e,e=f[0]);var h,i="on"+e.replace(b,a),j=d[i];return c.isFunction(j)&&(h=j.apply(d,g?c.rest(f):f)),c.isFunction(d.trigger)&&(g+f.length>1?d.trigger.apply(d,g?f:[e].concat(c.drop(f,0))):d.trigger(e)),h}}(),f.triggerMethod=function(){return f._triggerMethod(this,arguments)},f.triggerMethodOn=function(a){var b=c.isFunction(a.triggerMethod)?a.triggerMethod:f.triggerMethod;return b.apply(a,c.rest(arguments))},f.MonitorDOMRefresh=function(a){function b(){a._isShown=!0,e()}function d(){a._isRendered=!0,e()}function e(){a._isShown&&a._isRendered&&f.isNodeAttached(a.el)&&c.isFunction(a.triggerMethod)&&a.triggerMethod("dom:refresh")}a.on({show:b,render:d})},function(a){function b(b,d,e,f){var g=f.split(/\s+/);c.each(g,function(c){var f=b[c];if(!f)throw new a.Error('Method "'+c+'" was configured as an event handler, but does not exist.');b.listenTo(d,e,f)})}function d(a,b,c,d){a.listenTo(b,c,d)}function e(a,b,d,e){var f=e.split(/\s+/);c.each(f,function(c){var e=a[c];a.stopListening(b,d,e)})}function f(a,b,c,d){a.stopListening(b,c,d)}function g(b,d,e,f,g){if(d&&e){if(!c.isObject(e))throw new a.Error({message:"Bindings must be an object or function.",url:"marionette.functions.html#marionettebindentityevents"});e=a._getValue(e,b),c.each(e,function(a,e){c.isFunction(a)?f(b,d,e,a):g(b,d,e,a)})}}a.bindEntityEvents=function(a,c,e){g(a,c,e,d,b)},a.unbindEntityEvents=function(a,b,c){g(a,b,c,f,e)},a.proxyBindEntityEvents=function(b,c){return a.bindEntityEvents(this,b,c)},a.proxyUnbindEntityEvents=function(b,c){return a.unbindEntityEvents(this,b,c)}}(f);var h=["description","fileName","lineNumber","name","message","number"];return f.Error=f.extend.call(Error,{urlRoot:"http://marionettejs.com/docs/v"+f.VERSION+"/",constructor:function(a,b){c.isObject(a)?(b=a,a=b.message):b||(b={});var d=Error.call(this,a);c.extend(this,c.pick(d,h),c.pick(b,h)),this.captureStackTrace(),b.url&&(this.url=this.urlRoot+b.url)},captureStackTrace:function(){Error.captureStackTrace&&Error.captureStackTrace(this,f.Error)},toString:function(){return this.name+": "+this.message+(this.url?" See: "+this.url:"")}}),f.Error.extend=f.extend,f.Callbacks=function(){this._deferred=f.Deferred(),this._callbacks=[]},c.extend(f.Callbacks.prototype,{add:function(a,b){var d=c.result(this._deferred,"promise");this._callbacks.push({cb:a,ctx:b}),d.then(function(c){b&&(c.context=b),a.call(c.context,c.options)})},run:function(a,b){this._deferred.resolve({options:a,context:b})},reset:function(){var a=this._callbacks;this._deferred=f.Deferred(),this._callbacks=[],c.each(a,function(a){this.add(a.cb,a.ctx)},this)}}),f.Controller=function(a){this.options=a||{},c.isFunction(this.initialize)&&this.initialize(this.options)},f.Controller.extend=f.extend,c.extend(f.Controller.prototype,b.Events,{destroy:function(){return f._triggerMethod(this,"before:destroy",arguments),f._triggerMethod(this,"destroy",arguments),this.stopListening(),this.off(),this},triggerMethod:f.triggerMethod,mergeOptions:f.mergeOptions,getOption:f.proxyGetOption}),f.Object=function(a){this.options=c.extend({},c.result(this,"options"),a),this.initialize.apply(this,arguments)},f.Object.extend=f.extend,c.extend(f.Object.prototype,b.Events,{initialize:function(){},destroy:function(){return this.triggerMethod("before:destroy"),this.triggerMethod("destroy"),this.stopListening(),this},triggerMethod:f.triggerMethod,mergeOptions:f.mergeOptions,getOption:f.proxyGetOption,bindEntityEvents:f.proxyBindEntityEvents,unbindEntityEvents:f.proxyUnbindEntityEvents}),f.Region=f.Object.extend({constructor:function(a){if(this.options=a||{},this.el=this.getOption("el"),this.el=this.el instanceof b.$?this.el[0]:this.el,!this.el)throw new f.Error({name:"NoElError",message:'An "el" must be specified for a region.'});this.$el=this.getEl(this.el),f.Object.call(this,a)},show:function(a,b){if(this._ensureElement()){this._ensureViewIsIntact(a);var c=b||{},d=a!==this.currentView,e=!!c.preventDestroy,g=!!c.forceShow,h=!!this.currentView,i=d&&!e,j=d||g;if(h&&this.triggerMethod("before:swapOut",this.currentView,this,b),this.currentView&&delete this.currentView._parent,i?this.empty():h&&j&&this.currentView.off("destroy",this.empty,this),j){a.once("destroy",this.empty,this),a.render(),a._parent=this,h&&this.triggerMethod("before:swap",a,this,b),this.triggerMethod("before:show",a,this,b),f.triggerMethodOn(a,"before:show",a,this,b),h&&this.triggerMethod("swapOut",this.currentView,this,b);var k=f.isNodeAttached(this.el),l=[],m=c.triggerBeforeAttach||this.triggerBeforeAttach,n=c.triggerAttach||this.triggerAttach;return k&&m&&(l=this._displayedViews(a),this._triggerAttach(l,"before:")),this.attachHtml(a),this.currentView=a,k&&n&&(l=this._displayedViews(a),this._triggerAttach(l)),h&&this.triggerMethod("swap",a,this,b),this.triggerMethod("show",a,this,b),f.triggerMethodOn(a,"show",a,this,b),this}return this}},triggerBeforeAttach:!0,triggerAttach:!0,_triggerAttach:function(a,b){var d=(b||"")+"attach";c.each(a,function(a){f.triggerMethodOn(a,d,a,this)},this)},_displayedViews:function(a){return c.union([a],c.result(a,"_getNestedViews")||[])},_ensureElement:function(){if(c.isObject(this.el)||(this.$el=this.getEl(this.el),this.el=this.$el[0]),!this.$el||0===this.$el.length){if(this.getOption("allowMissingEl"))return!1;throw new f.Error('An "el" '+this.$el.selector+" must exist in DOM")}return!0},_ensureViewIsIntact:function(a){if(!a)throw new f.Error({name:"ViewNotValid",message:"The view passed is undefined and therefore invalid. You must pass a view instance to show."});if(a.isDestroyed)throw new f.Error({name:"ViewDestroyedError",message:'View (cid: "'+a.cid+'") has already been destroyed and cannot be used.'})},getEl:function(a){return b.$(a,f._getValue(this.options.parentEl,this))},attachHtml:function(a){this.$el.contents().detach(),this.el.appendChild(a.el)},empty:function(a){var b=this.currentView,c=f._getValue(a,"preventDestroy",this);return b?(b.off("destroy",this.empty,this),this.triggerMethod("before:empty",b),c||this._destroyView(),this.triggerMethod("empty",b),delete this.currentView,c&&this.$el.contents().detach(),this):void 0},_destroyView:function(){var a=this.currentView;a.destroy&&!a.isDestroyed?a.destroy():a.remove&&(a.remove(),a.isDestroyed=!0)},attachView:function(a){return this.currentView=a,this},hasView:function(){return!!this.currentView},reset:function(){return this.empty(),this.$el&&(this.el=this.$el.selector),delete this.$el,this}},{buildRegion:function(a,b){if(c.isString(a))return this._buildRegionFromSelector(a,b);if(a.selector||a.el||a.regionClass)return this._buildRegionFromObject(a,b);if(c.isFunction(a))return this._buildRegionFromRegionClass(a);throw new f.Error({message:"Improper region configuration type.",url:"marionette.region.html#region-configuration-types"})},_buildRegionFromSelector:function(a,b){return new b({el:a})},_buildRegionFromObject:function(a,b){var d=a.regionClass||b,e=c.omit(a,"selector","regionClass");return a.selector&&!e.el&&(e.el=a.selector),new d(e)},_buildRegionFromRegionClass:function(a){return new a}}),f.RegionManager=f.Controller.extend({constructor:function(a){this._regions={},this.length=0,f.Controller.call(this,a),this.addRegions(this.getOption("regions"))},addRegions:function(a,b){return a=f._getValue(a,this,arguments),c.reduce(a,function(a,d,e){return c.isString(d)&&(d={selector:d}),d.selector&&(d=c.defaults({},d,b)),a[e]=this.addRegion(e,d),a},{},this)},addRegion:function(a,b){var c;return c=b instanceof f.Region?b:f.Region.buildRegion(b,f.Region),this.triggerMethod("before:add:region",a,c),c._parent=this,this._store(a,c),this.triggerMethod("add:region",a,c),c},get:function(a){return this._regions[a]},getRegions:function(){return c.clone(this._regions)},removeRegion:function(a){var b=this._regions[a];return this._remove(a,b),b},removeRegions:function(){var a=this.getRegions();return c.each(this._regions,function(a,b){this._remove(b,a)},this),a},emptyRegions:function(){var a=this.getRegions();return c.invoke(a,"empty"),a},destroy:function(){return this.removeRegions(),f.Controller.prototype.destroy.apply(this,arguments)},_store:function(a,b){this._regions[a]||this.length++,this._regions[a]=b},_remove:function(a,b){this.triggerMethod("before:remove:region",a,b),b.empty(),b.stopListening(),delete b._parent,delete this._regions[a],this.length--,this.triggerMethod("remove:region",a,b)}}),f.actAsCollection(f.RegionManager.prototype,"_regions"),f.TemplateCache=function(a){this.templateId=a},c.extend(f.TemplateCache,{templateCaches:{},get:function(a,b){var c=this.templateCaches[a];return c||(c=new f.TemplateCache(a),this.templateCaches[a]=c),c.load(b)},clear:function(){var a,b=c.toArray(arguments),d=b.length;if(d>0)for(a=0;d>a;a++)delete this.templateCaches[b[a]];else this.templateCaches={}}}),c.extend(f.TemplateCache.prototype,{load:function(a){if(this.compiledTemplate)return this.compiledTemplate;var b=this.loadTemplate(this.templateId,a);return this.compiledTemplate=this.compileTemplate(b,a),this.compiledTemplate},loadTemplate:function(a){var c=b.$(a).html();if(!c||0===c.length)throw new f.Error({name:"NoTemplateError",message:'Could not find template: "'+a+'"'});return c},compileTemplate:function(a,b){return c.template(a,b)}}),f.Renderer={render:function(a,b){if(!a)throw new f.Error({name:"TemplateNotFoundError",message:"Cannot render the template since its false, null or undefined."});var d=c.isFunction(a)?a:f.TemplateCache.get(a);return d(b)}},f.View=b.View.extend({isDestroyed:!1,constructor:function(a){c.bindAll(this,"render"),a=f._getValue(a,this),this.options=c.extend({},c.result(this,"options"),a),this._behaviors=f.Behaviors(this),b.View.call(this,this.options),f.MonitorDOMRefresh(this)},getTemplate:function(){return this.getOption("template")},serializeModel:function(a){return a.toJSON.apply(a,c.rest(arguments))},mixinTemplateHelpers:function(a){a=a||{};var b=this.getOption("templateHelpers");return b=f._getValue(b,this),c.extend(a,b)},normalizeUIKeys:function(a){var b=c.result(this,"_uiBindings");return f.normalizeUIKeys(a,b||c.result(this,"ui"))},normalizeUIValues:function(a,b){var d=c.result(this,"ui"),e=c.result(this,"_uiBindings");return f.normalizeUIValues(a,e||d,b)},configureTriggers:function(){if(this.triggers){var a=this.normalizeUIKeys(c.result(this,"triggers"));return c.reduce(a,function(a,b,c){return a[c]=this._buildViewTrigger(b),a},{},this)}},delegateEvents:function(a){return this._delegateDOMEvents(a),this.bindEntityEvents(this.model,this.getOption("modelEvents")),this.bindEntityEvents(this.collection,this.getOption("collectionEvents")),c.each(this._behaviors,function(a){a.bindEntityEvents(this.model,a.getOption("modelEvents")),a.bindEntityEvents(this.collection,a.getOption("collectionEvents"))},this),this},_delegateDOMEvents:function(a){var d=f._getValue(a||this.events,this);d=this.normalizeUIKeys(d),c.isUndefined(a)&&(this.events=d);var e={},g=c.result(this,"behaviorEvents")||{},h=this.configureTriggers(),i=c.result(this,"behaviorTriggers")||{};c.extend(e,g,d,h,i),b.View.prototype.delegateEvents.call(this,e)},undelegateEvents:function(){return b.View.prototype.undelegateEvents.apply(this,arguments),this.unbindEntityEvents(this.model,this.getOption("modelEvents")),this.unbindEntityEvents(this.collection,this.getOption("collectionEvents")),c.each(this._behaviors,function(a){a.unbindEntityEvents(this.model,a.getOption("modelEvents")),a.unbindEntityEvents(this.collection,a.getOption("collectionEvents"))},this),this},_ensureViewIsIntact:function(){if(this.isDestroyed)throw new f.Error({name:"ViewDestroyedError",message:'View (cid: "'+this.cid+'") has already been destroyed and cannot be used.'})},destroy:function(){if(this.isDestroyed)return this;var a=c.toArray(arguments);return this.triggerMethod.apply(this,["before:destroy"].concat(a)),this.isDestroyed=!0,this.triggerMethod.apply(this,["destroy"].concat(a)),this.unbindUIElements(),this.isRendered=!1,this.remove(),c.invoke(this._behaviors,"destroy",a),this},bindUIElements:function(){this._bindUIElements(),c.invoke(this._behaviors,this._bindUIElements)},_bindUIElements:function(){if(this.ui){this._uiBindings||(this._uiBindings=this.ui);var a=c.result(this,"_uiBindings");this.ui={},c.each(a,function(a,b){this.ui[b]=this.$(a)},this)}},unbindUIElements:function(){this._unbindUIElements(),c.invoke(this._behaviors,this._unbindUIElements)},_unbindUIElements:function(){this.ui&&this._uiBindings&&(c.each(this.ui,function(a,b){delete this.ui[b]},this),this.ui=this._uiBindings,delete this._uiBindings)},_buildViewTrigger:function(a){var b=c.isObject(a),d=c.defaults({},b?a:{},{preventDefault:!0,stopPropagation:!0}),e=b?d.event:a;return function(a){a&&(a.preventDefault&&d.preventDefault&&a.preventDefault(),a.stopPropagation&&d.stopPropagation&&a.stopPropagation());var b={view:this,model:this.model,collection:this.collection};this.triggerMethod(e,b)}},setElement:function(){var a=b.View.prototype.setElement.apply(this,arguments);return c.invoke(this._behaviors,"proxyViewProperties",this),a},triggerMethod:function(){var a=f._triggerMethod(this,arguments);return this._triggerEventOnBehaviors(arguments),this._triggerEventOnParentLayout(arguments[0],c.rest(arguments)),a},_triggerEventOnBehaviors:function(a){for(var b=f._triggerMethod,c=this._behaviors,d=0,e=c&&c.length;e>d;d++)b(c[d],a)},_triggerEventOnParentLayout:function(a,b){var d=this._parentLayoutView();if(d){var e=f.getOption(d,"childViewEventPrefix"),g=e+":"+a;f._triggerMethod(d,[g,this].concat(b));var h=f.getOption(d,"childEvents"),i=d.normalizeMethods(h);i&&c.isFunction(i[a])&&i[a].apply(d,[this].concat(b))}},_getImmediateChildren:function(){return[]},_getNestedViews:function(){var a=this._getImmediateChildren();return a.length?c.reduce(a,function(a,b){return b._getNestedViews?a.concat(b._getNestedViews()):a},a):a},_getAncestors:function(){for(var a=[],b=this._parent;b;)a.push(b),b=b._parent;return a},_parentLayoutView:function(){var a=this._getAncestors();return c.find(a,function(a){return a instanceof f.LayoutView})},normalizeMethods:f.normalizeMethods,mergeOptions:f.mergeOptions,getOption:f.proxyGetOption,bindEntityEvents:f.proxyBindEntityEvents,unbindEntityEvents:f.proxyUnbindEntityEvents}),f.ItemView=f.View.extend({constructor:function(){f.View.apply(this,arguments)},serializeData:function(){if(!this.model&&!this.collection)return{};var a=[this.model||this.collection];return arguments.length&&a.push.apply(a,arguments),this.model?this.serializeModel.apply(this,a):{items:this.serializeCollection.apply(this,a)}},serializeCollection:function(a){return a.toJSON.apply(a,c.rest(arguments))},render:function(){return this._ensureViewIsIntact(),this.triggerMethod("before:render",this),this._renderTemplate(),this.isRendered=!0,this.bindUIElements(),this.triggerMethod("render",this),this},_renderTemplate:function(){var a=this.getTemplate();if(a!==!1){if(!a)throw new f.Error({name:"UndefinedTemplateError",message:"Cannot render the template since it is null or undefined."});var b=this.mixinTemplateHelpers(this.serializeData()),c=f.Renderer.render(a,b,this);return this.attachElContent(c),this}},attachElContent:function(a){return this.$el.html(a),this}}),f.CollectionView=f.View.extend({childViewEventPrefix:"childview",sort:!0,constructor:function(){this.once("render",this._initialEvents),this._initChildViewStorage(),f.View.apply(this,arguments),this.on("show",this._onShowCalled),this.initRenderBuffer()},initRenderBuffer:function(){this._bufferedChildren=[]},startBuffering:function(){this.initRenderBuffer(),this.isBuffering=!0},endBuffering:function(){this.isBuffering=!1,this._triggerBeforeShowBufferedChildren(),this.attachBuffer(this),this._triggerShowBufferedChildren(),this.initRenderBuffer()},_triggerBeforeShowBufferedChildren:function(){this._isShown&&c.each(this._bufferedChildren,c.partial(this._triggerMethodOnChild,"before:show"))},_triggerShowBufferedChildren:function(){this._isShown&&(c.each(this._bufferedChildren,c.partial(this._triggerMethodOnChild,"show")),this._bufferedChildren=[])},_triggerMethodOnChild:function(a,b){f.triggerMethodOn(b,a)},_initialEvents:function(){this.collection&&(this.listenTo(this.collection,"add",this._onCollectionAdd),this.listenTo(this.collection,"remove",this._onCollectionRemove),this.listenTo(this.collection,"reset",this.render),this.getOption("sort")&&this.listenTo(this.collection,"sort",this._sortViews))},_onCollectionAdd:function(a,b,d){var e;if(e=void 0!==d.at?d.at:c.indexOf(this._filteredSortedModels(),a),this._shouldAddChild(a,e)){this.destroyEmptyView();var f=this.getChildView(a);this.addChild(a,f,e)}},_onCollectionRemove:function(a){var b=this.children.findByModel(a);this.removeChildView(b),this.checkEmpty()},_onShowCalled:function(){this.children.each(c.partial(this._triggerMethodOnChild,"show"))},render:function(){return this._ensureViewIsIntact(),this.triggerMethod("before:render",this),this._renderChildren(),this.isRendered=!0,this.triggerMethod("render",this),this},reorder:function(){var a=this.children,b=this._filteredSortedModels(),d=c.find(b,function(b){return!a.findByModel(b)});if(d)this.render();else{var e=c.map(b,function(b){return a.findByModel(b).el});this.triggerMethod("before:reorder"),this._appendReorderedChildren(e),this.triggerMethod("reorder")}},resortView:function(){f.getOption(this,"reorderOnSort")?this.reorder():this.render()},_sortViews:function(){var a=this._filteredSortedModels(),b=c.find(a,function(a,b){var c=this.children.findByModel(a);return!c||c._index!==b},this);b&&this.resortView()},_emptyViewIndex:-1,_appendReorderedChildren:function(a){this.$el.append(a)},_renderChildren:function(){this.destroyEmptyView(),this.destroyChildren(),this.isEmpty(this.collection)?this.showEmptyView():(this.triggerMethod("before:render:collection",this),this.startBuffering(),this.showCollection(),this.endBuffering(),this.triggerMethod("render:collection",this),this.children.isEmpty()&&this.showEmptyView())},showCollection:function(){var a,b=this._filteredSortedModels();c.each(b,function(b,c){a=this.getChildView(b),this.addChild(b,a,c)},this)},_filteredSortedModels:function(){var a,b=this.getViewComparator();return a=b?c.isString(b)||1===b.length?this.collection.sortBy(b,this):c.clone(this.collection.models).sort(c.bind(b,this)):this.collection.models,this.getOption("filter")&&(a=c.filter(a,function(a,b){return this._shouldAddChild(a,b)},this)),a},showEmptyView:function(){var a=this.getEmptyView();if(a&&!this._showingEmptyView){this.triggerMethod("before:render:empty"),this._showingEmptyView=!0;var c=new b.Model;this.addEmptyView(c,a),this.triggerMethod("render:empty")}},destroyEmptyView:function(){this._showingEmptyView&&(this.triggerMethod("before:remove:empty"),this.destroyChildren(),delete this._showingEmptyView,this.triggerMethod("remove:empty"))},getEmptyView:function(){return this.getOption("emptyView")},addEmptyView:function(a,b){var d=this.getOption("emptyViewOptions")||this.getOption("childViewOptions");c.isFunction(d)&&(d=d.call(this,a,this._emptyViewIndex));var e=this.buildChildView(a,b,d);e._parent=this,this.proxyChildEvents(e),this._isShown&&f.triggerMethodOn(e,"before:show"),this.children.add(e),this.renderChildView(e,this._emptyViewIndex),this._isShown&&f.triggerMethodOn(e,"show")},getChildView:function(){var a=this.getOption("childView");if(!a)throw new f.Error({name:"NoChildViewError",message:'A "childView" must be specified'});return a},addChild:function(a,b,c){var d=this.getOption("childViewOptions");d=f._getValue(d,this,[a,c]);var e=this.buildChildView(a,b,d);return this._updateIndices(e,!0,c),this._addChildView(e,c),e._parent=this,e},_updateIndices:function(a,b,c){this.getOption("sort")&&(b&&(a._index=c),this.children.each(function(c){c._index>=a._index&&(c._index+=b?1:-1)}))},_addChildView:function(a,b){this.proxyChildEvents(a),this.triggerMethod("before:add:child",a),this._isShown&&!this.isBuffering&&f.triggerMethodOn(a,"before:show"),this.children.add(a),this.renderChildView(a,b),this._isShown&&!this.isBuffering&&f.triggerMethodOn(a,"show"),this.triggerMethod("add:child",a)},renderChildView:function(a,b){return a.render(),this.attachHtml(this,a,b),a},buildChildView:function(a,b,d){var e=c.extend({model:a},d);return new b(e)},removeChildView:function(a){return a&&(this.triggerMethod("before:remove:child",a),a.destroy?a.destroy():a.remove&&a.remove(),delete a._parent,this.stopListening(a),this.children.remove(a),this.triggerMethod("remove:child",a),this._updateIndices(a,!1)),a},isEmpty:function(){return!this.collection||0===this.collection.length},checkEmpty:function(){this.isEmpty(this.collection)&&this.showEmptyView()},attachBuffer:function(a){a.$el.append(this._createBuffer(a))},_createBuffer:function(a){var b=document.createDocumentFragment();return c.each(a._bufferedChildren,function(a){b.appendChild(a.el)}),b},attachHtml:function(a,b,c){a.isBuffering?a._bufferedChildren.splice(c,0,b):a._insertBefore(b,c)||a._insertAfter(b)},_insertBefore:function(a,b){var c,d=this.getOption("sort")&&b - - - -HTRACE -Nested world.

- -