From: Stas Vilchik Date: Tue, 9 Jun 2015 10:13:56 +0000 (+0200) Subject: upgrade backbone.marionette X-Git-Tag: 5.2-RC1~1560 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e9ac473ec7dc0433cadf3f64f5d7980e38e0b93c;p=sonarqube.git upgrade backbone.marionette --- diff --git a/server/sonar-web/src/main/js/apps/api-documentation/actions-view.js b/server/sonar-web/src/main/js/apps/api-documentation/actions-view.js index 099e1ea73d0..683485c101b 100644 --- a/server/sonar-web/src/main/js/apps/api-documentation/actions-view.js +++ b/server/sonar-web/src/main/js/apps/api-documentation/actions-view.js @@ -24,7 +24,7 @@ define([ var $ = jQuery; return Marionette.CollectionView.extend({ - itemView: ActionView, + childView: ActionView, scrollToTop: function () { var parent = this.$el.scrollParent(); diff --git a/server/sonar-web/src/main/js/apps/api-documentation/layout.js b/server/sonar-web/src/main/js/apps/api-documentation/layout.js index 64f17b220ed..ae4ce851798 100644 --- a/server/sonar-web/src/main/js/apps/api-documentation/layout.js +++ b/server/sonar-web/src/main/js/apps/api-documentation/layout.js @@ -23,7 +23,7 @@ define([ var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['api-documentation-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/api-documentation/list-view.js b/server/sonar-web/src/main/js/apps/api-documentation/list-view.js index a833cf7b48b..b90ba7f725a 100644 --- a/server/sonar-web/src/main/js/apps/api-documentation/list-view.js +++ b/server/sonar-web/src/main/js/apps/api-documentation/list-view.js @@ -23,9 +23,9 @@ define([ return Marionette.CollectionView.extend({ className: 'list-group', - itemView: ItemView, + childView: ItemView, - itemViewOptions: function (model) { + childViewOptions: function (model) { return { collectionView: this, highlighted: model.get('path') === this.highlighted, diff --git a/server/sonar-web/src/main/js/apps/coding-rules/facets-view.js b/server/sonar-web/src/main/js/apps/coding-rules/facets-view.js index b9c2a7f4921..cf9e8d92bc5 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/facets-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/facets-view.js @@ -68,7 +68,7 @@ define([ return FacetsView.extend({ - getItemView: function (model) { + getChildView: function (model) { var view = viewsMapping[model.get('property')]; return view ? view : BaseFacet; } diff --git a/server/sonar-web/src/main/js/apps/coding-rules/layout.js b/server/sonar-web/src/main/js/apps/coding-rules/layout.js index 87ec56e9694..238db774707 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/layout.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/layout.js @@ -23,7 +23,7 @@ define([ var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['coding-rules-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js index 941cfc42912..05856342aa4 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js @@ -41,7 +41,7 @@ define([ var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ className: 'coding-rule-details', template: Templates['coding-rules-rule-details'], @@ -99,7 +99,7 @@ define([ this.$el.scrollParent().scrollTop(0); }, - onClose: function () { + onDestroy: function () { this.unbindShortcuts(); }, diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-creation-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-creation-view.js index 5c3829854a6..e15a1149e69 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-creation-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-creation-view.js @@ -51,7 +51,7 @@ define([ 'keydown @ui.customRuleCreationKey': 'flagKey', 'keyup @ui.customRuleCreationKey': 'flagKey', - 'click #coding-rules-custom-rule-creation-cancel': 'close', + 'click #coding-rules-custom-rule-creation-cancel': 'destroy', 'click @ui.customRuleCreationCreate': 'create', 'click @ui.customRuleCreationReactivate': 'reactivate' }); @@ -168,7 +168,7 @@ define([ } else { that.options.app.controller.showDetails(that.model); } - that.close(); + that.destroy(); }).fail(function (jqXHR) { if (jqXHR.status === 409) { that.existingRule = jqXHR.responseJSON.rule; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js index 98d9634516e..e50b7c11005 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js @@ -45,7 +45,7 @@ define([ options = { key: that.model.id }; $.post(url, options).done(function () { that.model.collection.remove(that.model); - that.close(); + that.destroy(); }); } }); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js index 3785b8ed6b6..56ae2a95833 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js @@ -25,10 +25,10 @@ define([ return Marionette.CompositeView.extend({ template: Templates['coding-rules-custom-rules'], - itemView: CustomRuleView, - itemViewContainer: '#coding-rules-detail-custom-rules', + childView: CustomRuleView, + childViewContainer: '#coding-rules-detail-custom-rules', - itemViewOptions: function () { + childViewOptions: function () { return { app: this.options.app, templateRule: this.model diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/manual-rule-creation-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/manual-rule-creation-view.js index 6417beb3c8a..66617fc33ed 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/manual-rule-creation-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/manual-rule-creation-view.js @@ -115,7 +115,7 @@ define([ r = JSON.parse(r); } that.options.app.controller.showDetails(r.rule.key); - that.close(); + that.destroy(); }).fail(function (jqXHR) { if (jqXHR.status === 409) { that.existingRule = jqXHR.responseJSON.rule; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/profile-activation-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/profile-activation-view.js index e12c4730469..a310ce97674 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/profile-activation-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/profile-activation-view.js @@ -111,7 +111,7 @@ define([ 400: null } }).done(function () { - that.close(); + that.destroy(); that.trigger('profileActivated', severity, params); }).fail(function (jqXHR) { that.enableForm(); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-filter-mixin.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-filter-mixin.js index 839e1743af0..5bbe6a2d3cd 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-filter-mixin.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-filter-mixin.js @@ -38,7 +38,7 @@ define([ var obj = {}; obj[property] = '' + value; that.options.app.state.updateFilter(obj); - popup.close(); + popup.destroy(); }); popup.render(); } diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js index 1a4cb4c3f7e..d8565818c52 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js @@ -51,7 +51,7 @@ define([ }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profiles-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profiles-view.js index 7c3dc3df275..fc7662e5073 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profiles-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profiles-view.js @@ -25,10 +25,10 @@ define([ return Marionette.CompositeView.extend({ template: Templates['coding-rules-rule-profiles'], - itemView: ProfileView, - itemViewContainer: '#coding-rules-detail-quality-profiles', + childView: ProfileView, + childViewContainer: '#coding-rules-detail-quality-profiles', - itemViewOptions: function () { + childViewOptions: function () { return { app: this.options.app, rule: this.model diff --git a/server/sonar-web/src/main/js/apps/coding-rules/workspace-list-view.js b/server/sonar-web/src/main/js/apps/coding-rules/workspace-list-view.js index e5f1ac02eb2..e77a504fa7f 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/workspace-list-view.js +++ b/server/sonar-web/src/main/js/apps/coding-rules/workspace-list-view.js @@ -26,8 +26,8 @@ define([ return WorkspaceListView.extend({ template: Templates['coding-rules-workspace-list'], - itemView: WorkspaceListItemView, - itemViewContainer: '.js-list', + childView: WorkspaceListItemView, + childViewContainer: '.js-list', emptyView: WorkspaceListEmptyView, bindShortcuts: function () { diff --git a/server/sonar-web/src/main/js/apps/computation/layout.js b/server/sonar-web/src/main/js/apps/computation/layout.js index f747efea06c..2e7edcd22bf 100644 --- a/server/sonar-web/src/main/js/apps/computation/layout.js +++ b/server/sonar-web/src/main/js/apps/computation/layout.js @@ -2,7 +2,7 @@ define([ './templates' ], function () { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['computation-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/computation/list-item-view.js b/server/sonar-web/src/main/js/apps/computation/list-item-view.js index e457b39c2f3..afcf2f15d3f 100644 --- a/server/sonar-web/src/main/js/apps/computation/list-item-view.js +++ b/server/sonar-web/src/main/js/apps/computation/list-item-view.js @@ -13,7 +13,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/computation/list-view.js b/server/sonar-web/src/main/js/apps/computation/list-view.js index 138c36b7619..24878864d30 100644 --- a/server/sonar-web/src/main/js/apps/computation/list-view.js +++ b/server/sonar-web/src/main/js/apps/computation/list-view.js @@ -5,7 +5,7 @@ define([ return Marionette.CollectionView.extend({ tagName: 'ul', - itemView: ListItemView + childView: ListItemView }); }); diff --git a/server/sonar-web/src/main/js/apps/groups/create-view.js b/server/sonar-web/src/main/js/apps/groups/create-view.js index 8d5cfce55aa..cddde867a99 100644 --- a/server/sonar-web/src/main/js/apps/groups/create-view.js +++ b/server/sonar-web/src/main/js/apps/groups/create-view.js @@ -19,7 +19,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/groups/delete-view.js b/server/sonar-web/src/main/js/apps/groups/delete-view.js index 05e07c0d032..85b33a632b5 100644 --- a/server/sonar-web/src/main/js/apps/groups/delete-view.js +++ b/server/sonar-web/src/main/js/apps/groups/delete-view.js @@ -22,7 +22,7 @@ define([ } }).done(function () { collection.total--; - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); }); diff --git a/server/sonar-web/src/main/js/apps/groups/form-view.js b/server/sonar-web/src/main/js/apps/groups/form-view.js index e79ea6eec65..7e3c26b98ee 100644 --- a/server/sonar-web/src/main/js/apps/groups/form-view.js +++ b/server/sonar-web/src/main/js/apps/groups/form-view.js @@ -11,7 +11,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this._super(); this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/groups/layout.js b/server/sonar-web/src/main/js/apps/groups/layout.js index a60fb06f35f..18f6c7738d1 100644 --- a/server/sonar-web/src/main/js/apps/groups/layout.js +++ b/server/sonar-web/src/main/js/apps/groups/layout.js @@ -2,7 +2,7 @@ define([ './templates' ], function () { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['groups-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/groups/list-item-view.js b/server/sonar-web/src/main/js/apps/groups/list-item-view.js index 43eaa5b0d24..c09af127003 100644 --- a/server/sonar-web/src/main/js/apps/groups/list-item-view.js +++ b/server/sonar-web/src/main/js/apps/groups/list-item-view.js @@ -21,7 +21,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/groups/list-view.js b/server/sonar-web/src/main/js/apps/groups/list-view.js index 138c36b7619..24878864d30 100644 --- a/server/sonar-web/src/main/js/apps/groups/list-view.js +++ b/server/sonar-web/src/main/js/apps/groups/list-view.js @@ -5,7 +5,7 @@ define([ return Marionette.CollectionView.extend({ tagName: 'ul', - itemView: ListItemView + childView: ListItemView }); }); diff --git a/server/sonar-web/src/main/js/apps/groups/update-view.js b/server/sonar-web/src/main/js/apps/groups/update-view.js index 71383a1793d..850ddb7510f 100644 --- a/server/sonar-web/src/main/js/apps/groups/update-view.js +++ b/server/sonar-web/src/main/js/apps/groups/update-view.js @@ -18,7 +18,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/groups/users-view.js b/server/sonar-web/src/main/js/apps/groups/users-view.js index 25db7e80158..de5901fc5f1 100644 --- a/server/sonar-web/src/main/js/apps/groups/users-view.js +++ b/server/sonar-web/src/main/js/apps/groups/users-view.js @@ -33,7 +33,7 @@ define([ }); }, - onClose: function () { + onDestroy: function () { this.model.collection.refresh(); this._super(); } diff --git a/server/sonar-web/src/main/js/apps/issues/component-viewer/main.js b/server/sonar-web/src/main/js/apps/issues/component-viewer/main.js index f138a860d30..1e79d92e45d 100644 --- a/server/sonar-web/src/main/js/apps/issues/component-viewer/main.js +++ b/server/sonar-web/src/main/js/apps/issues/component-viewer/main.js @@ -73,8 +73,8 @@ define([ return key.deleteScope('componentViewer'); }, - onClose: function () { - SourceViewer.prototype.onClose.apply(this, arguments); + onDestroy: function () { + SourceViewer.prototype.onDestroy.apply(this, arguments); this.unbindScrollEvents(); return this.unbindShortcuts(); }, diff --git a/server/sonar-web/src/main/js/apps/issues/facets-view.js b/server/sonar-web/src/main/js/apps/issues/facets-view.js index eb5b4e127fa..26477d4788c 100644 --- a/server/sonar-web/src/main/js/apps/issues/facets-view.js +++ b/server/sonar-web/src/main/js/apps/issues/facets-view.js @@ -41,7 +41,7 @@ define([ }; return FacetsView.extend({ - getItemView: function (model) { + getChildView: function (model) { var view = viewsMapping[model.get('property')]; return view ? view : BaseFacet; } diff --git a/server/sonar-web/src/main/js/apps/issues/facets/base-facet.js b/server/sonar-web/src/main/js/apps/issues/facets/base-facet.js index 1376e8b6611..4f7d9d8ea55 100644 --- a/server/sonar-web/src/main/js/apps/issues/facets/base-facet.js +++ b/server/sonar-web/src/main/js/apps/issues/facets/base-facet.js @@ -11,7 +11,7 @@ define([ return this.$('[data-toggle="tooltip"]').tooltip({ container: 'body' }); }, - onClose: function () { + onDestroy: function () { return this.$('[data-toggle="tooltip"]').tooltip('destroy'); } }); diff --git a/server/sonar-web/src/main/js/apps/issues/layout.js b/server/sonar-web/src/main/js/apps/issues/layout.js index 06b2f893af6..13a71301a24 100644 --- a/server/sonar-web/src/main/js/apps/issues/layout.js +++ b/server/sonar-web/src/main/js/apps/issues/layout.js @@ -3,7 +3,7 @@ define([ ], function () { var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['issues-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js index c301c40e872..928b4b42c5f 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js @@ -23,7 +23,7 @@ define([ window.onBulkIssues = _.bind(this.afterBulkChange, this); }, - onClose: function () { + onDestroy: function () { this._super(); window.onBulkIssues = this._onBulkIssues; }, diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js index 510f26c63ea..28a6eb7e433 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js @@ -68,7 +68,7 @@ define([ }); } that.options.app.state.updateFilter(obj); - that.popup.close(); + that.popup.destroy(); }); this.popup.render(); }, diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js index d4bdad5f65b..5734479fc36 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js @@ -12,10 +12,18 @@ define([ return WorkspaceListView.extend({ template: Templates['issues-workspace-list'], componentTemplate: Templates['issues-workspace-list-component'], - itemView: IssueView, - itemViewContainer: '.js-list', + childView: IssueView, + childViewContainer: '.js-list', emptyView: EmptyView, + collectionEvents: { + 'all': 'log' + }, + + log: function () { + console.log(arguments); + }, + bindShortcuts: function () { var that = this; var doAction = function (action) { @@ -82,8 +90,8 @@ define([ } }, - appendHtml: function (compositeView, itemView, index) { - var $container = this.getItemViewContainer(compositeView), + attachHtml: function (compositeView, childView, index) { + var $container = this.getChildViewContainer(compositeView), model = this.collection.at(index); if (model != null) { var prev = this.collection.at(index - 1), @@ -99,11 +107,11 @@ define([ $container.append(this.componentTemplate(model.toJSON())); } } - $container.append(itemView.el); + $container.append(childView.el); }, - closeChildren: function () { - WorkspaceListView.prototype.closeChildren.apply(this, arguments); + destroyChildren: function () { + WorkspaceListView.prototype.destroyChildren.apply(this, arguments); this.$('.issues-workspace-list-component').remove(); } }); diff --git a/server/sonar-web/src/main/js/apps/metrics/create-view.js b/server/sonar-web/src/main/js/apps/metrics/create-view.js index 0db9fa70f11..5be34dac1ec 100644 --- a/server/sonar-web/src/main/js/apps/metrics/create-view.js +++ b/server/sonar-web/src/main/js/apps/metrics/create-view.js @@ -22,7 +22,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors([{ msg: jqXHR.responseJSON.err_msg }]); diff --git a/server/sonar-web/src/main/js/apps/metrics/delete-view.js b/server/sonar-web/src/main/js/apps/metrics/delete-view.js index 0acc3c055a9..8719b9fdb3a 100644 --- a/server/sonar-web/src/main/js/apps/metrics/delete-view.js +++ b/server/sonar-web/src/main/js/apps/metrics/delete-view.js @@ -22,7 +22,7 @@ define([ } }).done(function () { collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); }); diff --git a/server/sonar-web/src/main/js/apps/metrics/form-view.js b/server/sonar-web/src/main/js/apps/metrics/form-view.js index 77b5f2a54a5..03e66f715b6 100644 --- a/server/sonar-web/src/main/js/apps/metrics/form-view.js +++ b/server/sonar-web/src/main/js/apps/metrics/form-view.js @@ -35,7 +35,7 @@ define([ this.$('#create-metric-type').select2({ width: '250px' }); }, - onClose: function () { + onDestroy: function () { this._super(); this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/metrics/layout.js b/server/sonar-web/src/main/js/apps/metrics/layout.js index 812212a42fa..9575307d96f 100644 --- a/server/sonar-web/src/main/js/apps/metrics/layout.js +++ b/server/sonar-web/src/main/js/apps/metrics/layout.js @@ -2,7 +2,7 @@ define([ './templates' ], function () { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['metrics-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/metrics/list-item-view.js b/server/sonar-web/src/main/js/apps/metrics/list-item-view.js index 6328aea11d5..c6989e3b7b3 100644 --- a/server/sonar-web/src/main/js/apps/metrics/list-item-view.js +++ b/server/sonar-web/src/main/js/apps/metrics/list-item-view.js @@ -21,7 +21,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/metrics/list-view.js b/server/sonar-web/src/main/js/apps/metrics/list-view.js index 27060bbe7d4..b015c65d966 100644 --- a/server/sonar-web/src/main/js/apps/metrics/list-view.js +++ b/server/sonar-web/src/main/js/apps/metrics/list-view.js @@ -5,9 +5,9 @@ define([ return Marionette.CollectionView.extend({ tagName: 'ul', - itemView: ListItemView, + childView: ListItemView, - itemViewOptions: function () { + childViewOptions: function () { return { types: this.options.types, domains: this.options.domains diff --git a/server/sonar-web/src/main/js/apps/metrics/update-view.js b/server/sonar-web/src/main/js/apps/metrics/update-view.js index c4edec81a8d..3dfea4a584e 100644 --- a/server/sonar-web/src/main/js/apps/metrics/update-view.js +++ b/server/sonar-web/src/main/js/apps/metrics/update-view.js @@ -21,7 +21,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/nav/context-navbar-view.js b/server/sonar-web/src/main/js/apps/nav/context-navbar-view.js index 07eb0cd159a..2ff9d41d518 100644 --- a/server/sonar-web/src/main/js/apps/nav/context-navbar-view.js +++ b/server/sonar-web/src/main/js/apps/nav/context-navbar-view.js @@ -68,7 +68,7 @@ define([ return href.indexOf(url) !== -1; }), isOverviewActive = !isMoreActive && href.indexOf('/dashboard') !== -1 && search.indexOf('did=') === -1; - return _.extend(Marionette.Layout.prototype.serializeData.apply(this, arguments), { + return _.extend(Marionette.LayoutView.prototype.serializeData.apply(this, arguments), { canManageContextDashboards: !!window.SS.user, contextKeyEncoded: encodeURIComponent(this.model.get('componentKey')), diff --git a/server/sonar-web/src/main/js/apps/nav/global-navbar-view.js b/server/sonar-web/src/main/js/apps/nav/global-navbar-view.js index 5a0915e7b20..b4d8dd76f95 100644 --- a/server/sonar-web/src/main/js/apps/nav/global-navbar-view.js +++ b/server/sonar-web/src/main/js/apps/nav/global-navbar-view.js @@ -23,7 +23,7 @@ define([ './templates' ], function (SearchView, ShortcutsHelpView) { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['nav-global-navbar'], modelEvents: { @@ -82,7 +82,7 @@ define([ }, serializeData: function () { - return _.extend(Marionette.Layout.prototype.serializeData.apply(this, arguments), { + return _.extend(Marionette.LayoutView.prototype.serializeData.apply(this, arguments), { user: window.SS.user, userName: window.SS.userName, userEmail: window.SS.userEmail, diff --git a/server/sonar-web/src/main/js/apps/nav/search-view.js b/server/sonar-web/src/main/js/apps/nav/search-view.js index 09c7468851e..da26004aa57 100644 --- a/server/sonar-web/src/main/js/apps/nav/search-view.js +++ b/server/sonar-web/src/main/js/apps/nav/search-view.js @@ -55,11 +55,11 @@ define([ SearchResultsView = SelectableCollectionView.extend({ className: 'menu', tagName: 'ul', - itemView: SearchItemView, + childView: SearchItemView, emptyView: SearchEmptyView }); - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ className: 'navbar-search', tagName: 'form', template: Templates['nav-search'], diff --git a/server/sonar-web/src/main/js/apps/provisioning/bulk-delete-view.js b/server/sonar-web/src/main/js/apps/provisioning/bulk-delete-view.js index 91d09a12ee7..731e3e163d2 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/bulk-delete-view.js +++ b/server/sonar-web/src/main/js/apps/provisioning/bulk-delete-view.js @@ -21,7 +21,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); }); diff --git a/server/sonar-web/src/main/js/apps/provisioning/create-view.js b/server/sonar-web/src/main/js/apps/provisioning/create-view.js index 2f7d3b3965c..2aba2786c3c 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/create-view.js +++ b/server/sonar-web/src/main/js/apps/provisioning/create-view.js @@ -20,7 +20,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors([{ msg: jqXHR.responseJSON.err_msg }]); diff --git a/server/sonar-web/src/main/js/apps/provisioning/delete-view.js b/server/sonar-web/src/main/js/apps/provisioning/delete-view.js index 7797227aa40..dd503c4b1a4 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/delete-view.js +++ b/server/sonar-web/src/main/js/apps/provisioning/delete-view.js @@ -22,7 +22,7 @@ define([ } }).done(function () { collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); }); diff --git a/server/sonar-web/src/main/js/apps/provisioning/form-view.js b/server/sonar-web/src/main/js/apps/provisioning/form-view.js index ce359c6fa07..bb0fc0bcef5 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/form-view.js +++ b/server/sonar-web/src/main/js/apps/provisioning/form-view.js @@ -11,7 +11,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this._super(); this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/provisioning/layout.js b/server/sonar-web/src/main/js/apps/provisioning/layout.js index d0627a1e5b8..31b67e8b774 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/layout.js +++ b/server/sonar-web/src/main/js/apps/provisioning/layout.js @@ -2,7 +2,7 @@ define([ './templates' ], function () { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['provisioning-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/provisioning/list-item-view.js b/server/sonar-web/src/main/js/apps/provisioning/list-item-view.js index 2b03660b698..ead9b009ca3 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/list-item-view.js +++ b/server/sonar-web/src/main/js/apps/provisioning/list-item-view.js @@ -22,7 +22,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/provisioning/list-view.js b/server/sonar-web/src/main/js/apps/provisioning/list-view.js index 138c36b7619..24878864d30 100644 --- a/server/sonar-web/src/main/js/apps/provisioning/list-view.js +++ b/server/sonar-web/src/main/js/apps/provisioning/list-view.js @@ -5,7 +5,7 @@ define([ return Marionette.CollectionView.extend({ tagName: 'ul', - itemView: ListItemView + childView: ListItemView }); }); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/delete-view.js b/server/sonar-web/src/main/js/apps/quality-gates/delete-view.js index 793934460ca..d142b883c84 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/delete-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/delete-view.js @@ -22,7 +22,7 @@ define([ }; return this.model.destroy(options) .done(function () { - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/details-view.js b/server/sonar-web/src/main/js/apps/quality-gates/details-view.js index df054717447..9af1b38e65e 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/details-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/details-view.js @@ -5,7 +5,7 @@ define([ './templates' ], function (Conditions, DetailConditionsView, ProjectsView) { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['quality-gate-detail'], regions: { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/form-view.js b/server/sonar-web/src/main/js/apps/quality-gates/form-view.js index 5da9dfd05a2..9b61f400bf3 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/form-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/form-view.js @@ -24,7 +24,7 @@ define([ }); return Backbone.ajax(opts) .done(function () { - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/gate-condition-view.js b/server/sonar-web/src/main/js/apps/quality-gates/gate-condition-view.js index 49797716adf..0dfbea0ab17 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/gate-condition-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/gate-condition-view.js @@ -68,7 +68,7 @@ define([ }, cancelAddCondition: function () { - this.close(); + this.destroy(); }, enableUpdate: function () { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-delete-view.js b/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-delete-view.js index 83e32ee2455..c8ed23a2883 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-delete-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-delete-view.js @@ -22,7 +22,7 @@ define([ }; return this.model.destroy(options) .done(function () { - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-view.js b/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-view.js index 5ec13c6734a..b0c0857cc95 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/gate-conditions-view.js @@ -7,9 +7,9 @@ define([ return Marionette.CompositeView.extend({ template: Templates['quality-gate-detail-conditions'], - itemView: ConditionView, + childView: ConditionView, emptyView: ConditionsEmptyView, - itemViewContainer: '.js-conditions', + childViewContainer: '.js-conditions', ui: { metricSelect: '#quality-gate-new-condition-metric' @@ -20,7 +20,7 @@ define([ 'change @ui.metricSelect': 'addCondition' }, - itemViewOptions: function () { + childViewOptions: function () { return { canEdit: this.options.canEdit, gate: this.model, diff --git a/server/sonar-web/src/main/js/apps/quality-gates/gates-view.js b/server/sonar-web/src/main/js/apps/quality-gates/gates-view.js index 6c05b728d55..cd36c381a39 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/gates-view.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/gates-view.js @@ -6,10 +6,10 @@ define([ return Marionette.CompositeView.extend({ className: 'list-group', template: Templates['quality-gates-gates'], - itemView: ItemView, - itemViewContainer: '.js-list', + childView: ItemView, + childViewContainer: '.js-list', - itemViewOptions: function (model) { + childViewOptions: function (model) { return { collectionView: this, highlighted: model.id === this.highlighted diff --git a/server/sonar-web/src/main/js/apps/quality-gates/layout.js b/server/sonar-web/src/main/js/apps/quality-gates/layout.js index e9ae08550c4..791ba30ae83 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/layout.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/layout.js @@ -5,7 +5,7 @@ define([ var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['quality-gates-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js index e3c30699fe7..a0813a661c9 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js @@ -60,7 +60,7 @@ define([ }).done(function () { that.model.collection.fetch(); that.model.trigger('select', that.model); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); that.enableForm(); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js index 446254c1c4c..307a904e192 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js @@ -52,7 +52,7 @@ define([ } }).done(function (r) { that.addProfile(r); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js index ec5a0923d4b..531edc0f342 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js @@ -74,7 +74,7 @@ define([ that.showErrors(r.errors, r.warnings); } else { that.addProfile(r.profile); - that.close(); + that.destroy(); } }); }, diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js index 3b2ccee277a..e58f870c672 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js @@ -28,7 +28,7 @@ define([ template: Templates['quality-profiles-delete-profile'], modelEvents: { - 'destroy': 'close' + 'destroy': 'destroy' }, onFormSubmit: function () { diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/layout.js b/server/sonar-web/src/main/js/apps/quality-profiles/layout.js index 9099a11fa78..7ec62799470 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/layout.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/layout.js @@ -24,7 +24,7 @@ define([ var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['quality-profiles-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/profile-details-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/profile-details-view.js index ede00f14d73..3f9d16f7ea2 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/profile-details-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/profile-details-view.js @@ -28,7 +28,7 @@ define([ var $ = jQuery; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['quality-profiles-profile-details'], regions: { diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/profile-view.js index 03e5352e2d0..34de0a2d0c0 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/profile-view.js @@ -41,7 +41,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/profiles-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/profiles-view.js index 2a433476dcd..ae40ab623a5 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/profiles-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/profiles-view.js @@ -26,14 +26,14 @@ define([ className: 'list-group', template: Templates['quality-profiles-profiles'], languageTemplate: Templates['quality-profiles-profiles-language'], - itemView: ProfileView, - itemViewContainer: '.js-list', + childView: ProfileView, + childViewContainer: '.js-list', collectionEvents: { 'filter': 'filterByLanguage' }, - itemViewOptions: function (model) { + childViewOptions: function (model) { return { collectionView: this, highlighted: model.get('key') === this.highlighted @@ -45,8 +45,8 @@ define([ this.render(); }, - appendHtml: function (compositeView, itemView, index) { - var $container = this.getItemViewContainer(compositeView), + attachHtml: function (compositeView, childView, index) { + var $container = this.getChildViewContainer(compositeView), model = this.collection.at(index); if (model != null) { var prev = this.collection.at(index - 1), @@ -62,7 +62,7 @@ define([ $container.append(this.languageTemplate(model.toJSON())); } } - return $container.append(itemView.el); + compositeView._insertAfter(childView); }, closeChildren: function () { diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js index b61d9d8a794..1091198d747 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js @@ -50,7 +50,7 @@ define([ } }).done(function () { that.model.set({ name: name }); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); }); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/restore-built-in-profiles-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/restore-built-in-profiles-view.js index 645197f7b55..bd223c261f3 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/restore-built-in-profiles-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/restore-built-in-profiles-view.js @@ -58,7 +58,7 @@ define([ }).done(function () { that.collection.fetch({ reset: true }); that.collection.trigger('destroy'); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); that.enableForm(); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js index fca5b66476f..09b8feeb812 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js @@ -37,7 +37,7 @@ define([ that.showErrors(r.errors, r.warnings); } else { that.addProfile(r.profile); - that.close(); + that.destroy(); } }); }, diff --git a/server/sonar-web/src/main/js/apps/users/change-password-view.js b/server/sonar-web/src/main/js/apps/users/change-password-view.js index 6187333c9e6..659d3012a79 100644 --- a/server/sonar-web/src/main/js/apps/users/change-password-view.js +++ b/server/sonar-web/src/main/js/apps/users/change-password-view.js @@ -26,7 +26,7 @@ define([ 400: null } }).done(function () { - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/users/create-view.js b/server/sonar-web/src/main/js/apps/users/create-view.js index 026f8095056..562e41e8d5d 100644 --- a/server/sonar-web/src/main/js/apps/users/create-view.js +++ b/server/sonar-web/src/main/js/apps/users/create-view.js @@ -22,7 +22,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/apps/users/deactivate-view.js b/server/sonar-web/src/main/js/apps/users/deactivate-view.js index 37c71d4a94b..000a350ea57 100644 --- a/server/sonar-web/src/main/js/apps/users/deactivate-view.js +++ b/server/sonar-web/src/main/js/apps/users/deactivate-view.js @@ -22,7 +22,7 @@ define([ } }).done(function () { collection.total--; - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); }); diff --git a/server/sonar-web/src/main/js/apps/users/form-view.js b/server/sonar-web/src/main/js/apps/users/form-view.js index f1c7f602d14..50b18c1d237 100644 --- a/server/sonar-web/src/main/js/apps/users/form-view.js +++ b/server/sonar-web/src/main/js/apps/users/form-view.js @@ -19,7 +19,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this._super(); this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/users/groups-view.js b/server/sonar-web/src/main/js/apps/users/groups-view.js index 8fb864add9d..09a127fc6fd 100644 --- a/server/sonar-web/src/main/js/apps/users/groups-view.js +++ b/server/sonar-web/src/main/js/apps/users/groups-view.js @@ -34,9 +34,9 @@ define([ }); }, - onClose: function () { + onDestroy: function () { this.model.collection.refresh(); - Modal.prototype.onClose.apply(this, arguments); + Modal.prototype.onDestroy.apply(this, arguments); } }); diff --git a/server/sonar-web/src/main/js/apps/users/layout.js b/server/sonar-web/src/main/js/apps/users/layout.js index d2b625162e0..9acb054bdad 100644 --- a/server/sonar-web/src/main/js/apps/users/layout.js +++ b/server/sonar-web/src/main/js/apps/users/layout.js @@ -2,7 +2,7 @@ define([ './templates' ], function () { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ template: Templates['users-layout'], regions: { diff --git a/server/sonar-web/src/main/js/apps/users/list-item-view.js b/server/sonar-web/src/main/js/apps/users/list-item-view.js index 99aa973579b..b11e39e2766 100644 --- a/server/sonar-web/src/main/js/apps/users/list-item-view.js +++ b/server/sonar-web/src/main/js/apps/users/list-item-view.js @@ -30,7 +30,7 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/apps/users/list-view.js b/server/sonar-web/src/main/js/apps/users/list-view.js index 138c36b7619..24878864d30 100644 --- a/server/sonar-web/src/main/js/apps/users/list-view.js +++ b/server/sonar-web/src/main/js/apps/users/list-view.js @@ -5,7 +5,7 @@ define([ return Marionette.CollectionView.extend({ tagName: 'ul', - itemView: ListItemView + childView: ListItemView }); }); diff --git a/server/sonar-web/src/main/js/apps/users/update-view.js b/server/sonar-web/src/main/js/apps/users/update-view.js index 81497a3a75d..b276b79ba42 100644 --- a/server/sonar-web/src/main/js/apps/users/update-view.js +++ b/server/sonar-web/src/main/js/apps/users/update-view.js @@ -19,7 +19,7 @@ define([ } }).done(function () { that.collection.refresh(); - that.close(); + that.destroy(); }).fail(function (jqXHR) { that.enableForm(); that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); diff --git a/server/sonar-web/src/main/js/components/common/modals.js b/server/sonar-web/src/main/js/components/common/modals.js index 243ddb04948..b4812096177 100644 --- a/server/sonar-web/src/main/js/components/common/modals.js +++ b/server/sonar-web/src/main/js/components/common/modals.js @@ -41,7 +41,7 @@ define(function () { this.keyScope = key.getScope(); key.setScope('modal'); key('escape', 'modal', function () { - that.close(); + that.destroy(); return false; }); this.show(); @@ -58,7 +58,7 @@ define(function () { }, 0); }, - onClose: function () { + onDestroy: function () { $('html').removeClass(this.htmlClassName); this.removeOverlay(); key.deleteScope('modal'); @@ -67,7 +67,7 @@ define(function () { onCloseClick: function (e) { e.preventDefault(); - this.close(); + this.destroy(); }, renderOverlay: function () { @@ -85,7 +85,7 @@ define(function () { var that = this; $('body').on('click.' + EVENT_SCOPE, function () { $('body').off('click.' + EVENT_SCOPE); - that.close(); + that.destroy(); }); } }); diff --git a/server/sonar-web/src/main/js/components/common/popup.js b/server/sonar-web/src/main/js/components/common/popup.js index f978b7ab380..a3d15c1bbb8 100644 --- a/server/sonar-web/src/main/js/components/common/popup.js +++ b/server/sonar-web/src/main/js/components/common/popup.js @@ -31,20 +31,20 @@ define(function () { attachCloseEvents: function () { var that = this; key('escape', function () { - that.close(); + that.destroy(); }); $('body').on('click.bubble-popup', function () { $('body').off('click.bubble-popup'); - that.close(); + that.destroy(); }); this.options.triggerEl.on('click.bubble-popup', function (e) { that.options.triggerEl.off('click.bubble-popup'); e.stopPropagation(); - that.close(); + that.destroy(); }); }, - onClose: function () { + onDestroy: function () { $('body').off('click.bubble-popup'); this.options.triggerEl.off('click.bubble-popup'); } diff --git a/server/sonar-web/src/main/js/components/common/selectable-collection-view.js b/server/sonar-web/src/main/js/components/common/selectable-collection-view.js index b025ba925a5..c7250855946 100644 --- a/server/sonar-web/src/main/js/components/common/selectable-collection-view.js +++ b/server/sonar-web/src/main/js/components/common/selectable-collection-view.js @@ -26,7 +26,7 @@ define(function () { this.listenTo(this.collection, 'reset', this.resetSelectedIndex); }, - itemViewOptions: function (model, index) { + childViewOptions: function (model, index) { return { index: index }; }, diff --git a/server/sonar-web/src/main/js/components/issue/issue-view.js b/server/sonar-web/src/main/js/components/issue/issue-view.js index d7c90ddb777..d211ab65eda 100644 --- a/server/sonar-web/src/main/js/components/issue/issue-view.js +++ b/server/sonar-web/src/main/js/components/issue/issue-view.js @@ -72,7 +72,7 @@ define([ data: { issue: this.model.get('key') } }).done(function () { if (that.popup) { - that.popup.close(); + that.popup.destroy(); } that.popup = new ChangeLogView({ triggerEl: t, @@ -86,7 +86,7 @@ define([ updateAfterAction: function (fetch) { if (this.popup) { - this.popup.close(); + this.popup.destroy(); } if (fetch) { this.resetIssue(); @@ -176,7 +176,7 @@ define([ triggerEl: $('body') }); view.submit(window.SS.user, window.SS.userName); - view.close(); + view.destroy(); }, plan: function (e) { diff --git a/server/sonar-web/src/main/js/components/issue/manual-issue-view.js b/server/sonar-web/src/main/js/components/issue/manual-issue-view.js index 1b043544a44..2f819f62f2b 100644 --- a/server/sonar-web/src/main/js/components/issue/manual-issue-view.js +++ b/server/sonar-web/src/main/js/components/issue/manual-issue-view.js @@ -37,7 +37,7 @@ define([ } }, - onClose: function () { + onDestroy: function () { if (key != null && this.key != null) { key.setScope(this.key); } @@ -61,13 +61,13 @@ define([ var that = this; return issue.fetch().done(function () { that.trigger('add', issue); - that.close(); + that.destroy(); }); }, cancel: function (e) { e.preventDefault(); - this.close(); + this.destroy(); }, serializeData: function () { diff --git a/server/sonar-web/src/main/js/components/issue/views/action-options-view.js b/server/sonar-web/src/main/js/components/issue/views/action-options-view.js index 402a0cc6ec6..57b5c95d0a9 100644 --- a/server/sonar-web/src/main/js/components/issue/views/action-options-view.js +++ b/server/sonar-web/src/main/js/components/issue/views/action-options-view.js @@ -75,7 +75,7 @@ define([ return that.selectActiveOption(); }); key('escape', this.keyScope, function () { - return that.close(); + return that.destroy(); }); key('backspace', this.keyScope, function () { return false; @@ -96,8 +96,8 @@ define([ key.setScope(this.currentKeyScope); }, - onClose: function () { - PopupView.prototype.onClose.apply(this, arguments); + onDestroy: function () { + PopupView.prototype.onDestroy.apply(this, arguments); this.unbindShortcuts(); this.$('[data-toggle="tooltip"]').tooltip('destroy'); $('.tooltip').remove(); @@ -105,7 +105,7 @@ define([ selectOption: function (e) { e.preventDefault(); - this.close(); + this.destroy(); }, selectActiveOption: function () { diff --git a/server/sonar-web/src/main/js/components/issue/views/assign-form-view.js b/server/sonar-web/src/main/js/components/issue/views/assign-form-view.js index f2894e865af..bca6a296365 100644 --- a/server/sonar-web/src/main/js/components/issue/views/assign-form-view.js +++ b/server/sonar-web/src/main/js/components/issue/views/assign-form-view.js @@ -98,7 +98,7 @@ define([ this.selectActiveOption(); } if (e.keyCode === 27) { - this.close(); + this.destroy(); } if ([9, 13, 27, 38, 40].indexOf(e.keyCode) !== -1) { return false; diff --git a/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js b/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js index 10e9c713e09..52cd3917a2c 100644 --- a/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js +++ b/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js @@ -41,7 +41,7 @@ define([ onKeydown: function (e) { if (e.keyCode === 27) { - this.close(); + this.destroy(); } }, diff --git a/server/sonar-web/src/main/js/components/issue/views/issue-popup.js b/server/sonar-web/src/main/js/components/issue/views/issue-popup.js index 575fb50a52a..9c36ad104b5 100644 --- a/server/sonar-web/src/main/js/components/issue/views/issue-popup.js +++ b/server/sonar-web/src/main/js/components/issue/views/issue-popup.js @@ -11,7 +11,7 @@ define([ events: function () { return { - 'click .js-issue-form-cancel': 'close' + 'click .js-issue-form-cancel': 'destroy' }; }, @@ -21,8 +21,8 @@ define([ this.options.view.render(); }, - onClose: function () { - this.options.view.close(); + onDestroy: function () { + this.options.view.destroy(); }, attachCloseEvents: function () { diff --git a/server/sonar-web/src/main/js/components/issue/views/tags-form-view.js b/server/sonar-web/src/main/js/components/issue/views/tags-form-view.js index ee04d7103c9..868230ccd88 100644 --- a/server/sonar-web/src/main/js/components/issue/views/tags-form-view.js +++ b/server/sonar-web/src/main/js/components/issue/views/tags-form-view.js @@ -142,7 +142,7 @@ define([ this.selectActiveOption(); } if (e.keyCode === 27) { - this.close(); + this.destroy(); } if ([9, 13, 27, 38, 40].indexOf(e.keyCode) !== -1) { return false; diff --git a/server/sonar-web/src/main/js/components/navigator/facets-view.js b/server/sonar-web/src/main/js/components/navigator/facets-view.js index b137c39e81c..bf881e018fa 100644 --- a/server/sonar-web/src/main/js/components/navigator/facets-view.js +++ b/server/sonar-web/src/main/js/components/navigator/facets-view.js @@ -24,13 +24,13 @@ define([ return Marionette.CollectionView.extend({ className: 'search-navigator-facets-list', - itemViewOptions: function () { + childViewOptions: function () { return { app: this.options.app }; }, - getItemView: function () { + getChildView: function () { return BaseFacet; }, diff --git a/server/sonar-web/src/main/js/components/navigator/filters/filter-bar.js b/server/sonar-web/src/main/js/components/navigator/filters/filter-bar.js index b87da53c1d6..28ee2ceb836 100644 --- a/server/sonar-web/src/main/js/components/navigator/filters/filter-bar.js +++ b/server/sonar-web/src/main/js/components/navigator/filters/filter-bar.js @@ -26,7 +26,7 @@ define( function (BaseFilters, MoreCriteriaFilters) { return Marionette.CompositeView.extend({ - itemViewContainer: '.navigator-filters-list', + childViewContainer: '.navigator-filters-list', collectionEvents: { @@ -34,12 +34,12 @@ define( }, - getItemView: function (item) { + getChildView: function (item) { return item.get('type') || BaseFilters.BaseFilterView; }, - itemViewOptions: function () { + childViewOptions: function () { return { filterBarView: this, app: this.options.app @@ -94,7 +94,7 @@ define( getEnabledFilters: function() { - return this.$(this.itemViewContainer).children() + return this.$(this.childViewContainer).children() .not('.navigator-filter-disabled') .not('.navigator-filter-inactive') .not('.navigator-filter-favorite'); @@ -146,8 +146,8 @@ define( }, - onAfterItemAdded: function (itemView) { - if (itemView.model.get('type') === MoreCriteriaFilters.FavoriteFilterView) { + onAddChild: function (childView) { + if (childView.model.get('type') === MoreCriteriaFilters.FavoriteFilterView) { jQuery('.navigator-header').addClass('navigator-header-favorite'); } }, diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js index 524346fa080..75e34798616 100644 --- a/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js +++ b/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js @@ -48,7 +48,7 @@ define(function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js index 0296b1589aa..a9c1831c835 100644 --- a/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js +++ b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js @@ -27,7 +27,7 @@ define(function () { loadMore: '.js-more' }, - itemViewOptions: function () { + childViewOptions: function () { return { app: this.options.app }; @@ -44,7 +44,7 @@ define(function () { this.bindShortcuts(); }, - onClose: function () { + onDestroy: function () { this.unbindScrollEvents(); this.unbindShortcuts(); }, diff --git a/server/sonar-web/src/main/js/components/source-viewer/main.js b/server/sonar-web/src/main/js/components/source-viewer/main.js index a007145f354..947d6582af0 100644 --- a/server/sonar-web/src/main/js/components/source-viewer/main.js +++ b/server/sonar-web/src/main/js/components/source-viewer/main.js @@ -42,7 +42,7 @@ define([ var $ = jQuery, HIGHLIGHTED_ROW_CLASS = 'source-line-highlighted'; - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ className: 'source-viewer', template: Templates['source-viewer'], @@ -106,9 +106,9 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body' }); }, - onClose: function () { + onDestroy: function () { this.issueViews.forEach(function (view) { - return view.close(); + return view.destroy(); }); this.issueViews = []; this.clearTooltips(); diff --git a/server/sonar-web/src/main/js/components/source-viewer/more-actions.js b/server/sonar-web/src/main/js/components/source-viewer/more-actions.js index c3e7698b8f9..a1b5ff87f99 100644 --- a/server/sonar-web/src/main/js/components/source-viewer/more-actions.js +++ b/server/sonar-web/src/main/js/components/source-viewer/more-actions.js @@ -39,7 +39,7 @@ define([ var that = this; $('body').on('click.component-viewer-more-actions', function () { $('body').off('click.component-viewer-more-actions'); - that.close(); + that.destroy(); }); }, diff --git a/server/sonar-web/src/main/js/components/workspace/main.js b/server/sonar-web/src/main/js/components/workspace/main.js index 5f766ce00fa..7aa7f901aa6 100644 --- a/server/sonar-web/src/main/js/components/workspace/main.js +++ b/server/sonar-web/src/main/js/components/workspace/main.js @@ -89,7 +89,7 @@ define([ var that = this; if (this.viewerView != null) { this.viewerView.model.trigger('hideViewer'); - this.viewerView.close(); + this.viewerView.destroy(); } $('html').addClass('with-workspace'); model.trigger('showViewer'); @@ -112,7 +112,7 @@ define([ closeComponentViewer: function () { if (this.viewerView != null) { - this.viewerView.close(); + this.viewerView.destroy(); $('.with-workspace').removeClass('with-workspace'); } }, diff --git a/server/sonar-web/src/main/js/components/workspace/views/base-viewer-view.js b/server/sonar-web/src/main/js/components/workspace/views/base-viewer-view.js index 761b9887184..c917fbc9f65 100644 --- a/server/sonar-web/src/main/js/components/workspace/views/base-viewer-view.js +++ b/server/sonar-web/src/main/js/components/workspace/views/base-viewer-view.js @@ -21,11 +21,11 @@ define([ './viewer-header-view' ], function (HeaderView) { - return Marionette.Layout.extend({ + return Marionette.LayoutView.extend({ className: 'workspace-viewer', modelEvents: { - 'destroy': 'close' + 'destroy': 'destroy' }, regions: { diff --git a/server/sonar-web/src/main/js/components/workspace/views/items-view.js b/server/sonar-web/src/main/js/components/workspace/views/items-view.js index a83eeb0f3e8..36aa5679097 100644 --- a/server/sonar-web/src/main/js/components/workspace/views/items-view.js +++ b/server/sonar-web/src/main/js/components/workspace/views/items-view.js @@ -25,10 +25,10 @@ define([ return Marionette.CompositeView.extend({ className: 'workspace-nav', template: Templates['workspace-items'], - itemViewContainer: '.workspace-nav-list', - itemView: ItemView, + childViewContainer: '.workspace-nav-list', + childView: ItemView, - itemViewOptions: function () { + childViewOptions: function () { return { collectionView: this }; } }); diff --git a/server/sonar-web/src/main/js/components/workspace/views/rule-view.js b/server/sonar-web/src/main/js/components/workspace/views/rule-view.js index 4b4a498244b..b6ca04fee6f 100644 --- a/server/sonar-web/src/main/js/components/workspace/views/rule-view.js +++ b/server/sonar-web/src/main/js/components/workspace/views/rule-view.js @@ -26,7 +26,7 @@ define([ template: Templates['workspace-rule'], modelEvents: { - 'destroy': 'close', + 'destroy': 'destroy', 'change': 'render' }, @@ -35,12 +35,12 @@ define([ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body' }); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, serializeData: function () { - return _.extend(Marionette.Layout.prototype.serializeData.apply(this, arguments), { + return _.extend(Marionette.LayoutView.prototype.serializeData.apply(this, arguments), { allTags: _.union(this.model.get('sysTags'), this.model.get('tags')) }); } diff --git a/server/sonar-web/src/main/js/components/workspace/views/viewer-header-view.js b/server/sonar-web/src/main/js/components/workspace/views/viewer-header-view.js index b0705fb724a..6ef5b47f375 100644 --- a/server/sonar-web/src/main/js/components/workspace/views/viewer-header-view.js +++ b/server/sonar-web/src/main/js/components/workspace/views/viewer-header-view.js @@ -44,7 +44,7 @@ define([ this.$('.js-normal-size').addClass('hidden'); }, - onClose: function () { + onDestroy: function () { this.$('[data-toggle="tooltip"]').tooltip('destroy'); $('.tooltip').remove(); }, diff --git a/server/sonar-web/src/main/js/libs/third-party/backbone.marionette.js b/server/sonar-web/src/main/js/libs/third-party/backbone.marionette.js index a7dfbc340fc..d0e801ddcfa 100644 --- a/server/sonar-web/src/main/js/libs/third-party/backbone.marionette.js +++ b/server/sonar-web/src/main/js/libs/third-party/backbone.marionette.js @@ -1,14 +1,13 @@ // MarionetteJS (Backbone.Marionette) // ---------------------------------- -// v1.6.3 +// v2.4.1 // -// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC. +// Copyright (c)2015 Derick Bailey, Muted Solutions, LLC. // Distributed under MIT license // // http://marionettejs.com - /*! * Includes BabySitter * https://github.com/marionettejs/backbone.babysitter/ @@ -17,2537 +16,3804 @@ * https://github.com/marionettejs/backbone.wreqr/ */ -// Backbone.BabySitter -// ------------------- -// v0.1.0 -// -// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC. -// Distributed under MIT license -// -// http://github.com/marionettejs/backbone.babysitter - -// Backbone.ChildViewContainer -// --------------------------- -// -// Provide a container to store, retrieve and -// shut down child views. - -Backbone.ChildViewContainer = (function(Backbone, _){ - - // Container Constructor - // --------------------- - - var Container = function(views){ - this._views = {}; - this._indexByModel = {}; - this._indexByCustom = {}; - this._updateLength(); - - _.each(views, this.add, this); - }; - - // Container Methods - // ----------------- - - _.extend(Container.prototype, { - - // Add a view to this container. Stores the view - // by `cid` and makes it searchable by the model - // cid (and model itself). Optionally specify - // a custom key to store an retrieve the view. - add: function(view, customIndex){ - var viewCid = view.cid; - - // store the view - this._views[viewCid] = view; - // index it by model - if (view.model){ - this._indexByModel[view.model.cid] = viewCid; - } - - // index by custom - if (customIndex){ - this._indexByCustom[customIndex] = viewCid; - } - - this._updateLength(); - return this; - }, - - // Find a view by the model that was attached to - // it. Uses the model's `cid` to find it. - findByModel: function(model){ - return this.findByModelCid(model.cid); - }, - - // Find a view by the `cid` of the model that was attached to - // it. Uses the model's `cid` to find the view `cid` and - // retrieve the view using it. - findByModelCid: function(modelCid){ - var viewCid = this._indexByModel[modelCid]; - return this.findByCid(viewCid); - }, - - // Find a view by a custom indexer. - findByCustom: function(index){ - var viewCid = this._indexByCustom[index]; - return this.findByCid(viewCid); - }, - - // Find by index. This is not guaranteed to be a - // stable index. - findByIndex: function(index){ - return _.values(this._views)[index]; - }, - - // retrieve a view by its `cid` directly - findByCid: function(cid){ - return this._views[cid]; - }, +(function(root, factory) { - // Remove a view - remove: function(view){ - var viewCid = view.cid; + /* istanbul ignore next */ + if (typeof define === 'function' && define.amd) { + define(['backbone', 'underscore'], function(Backbone, _) { + return (root.Marionette = root.Mn = factory(root, Backbone, _)); + }); + } else if (typeof exports !== 'undefined') { + var Backbone = require('backbone'); + var _ = require('underscore'); + module.exports = factory(root, Backbone, _); + } else { + root.Marionette = root.Mn = factory(root, root.Backbone, root._); + } - // delete model index - if (view.model){ - delete this._indexByModel[view.model.cid]; - } +}(this, function(root, Backbone, _) { + 'use strict'; - // delete custom index - _.any(this._indexByCustom, function(cid, key) { - if (cid === viewCid) { - delete this._indexByCustom[key]; - return true; + /* istanbul ignore next */ + // Backbone.BabySitter + // ------------------- + // v0.1.6 + // + // Copyright (c)2015 Derick Bailey, Muted Solutions, LLC. + // Distributed under MIT license + // + // http://github.com/marionettejs/backbone.babysitter + (function(Backbone, _) { + "use strict"; + var previousChildViewContainer = Backbone.ChildViewContainer; + // BabySitter.ChildViewContainer + // ----------------------------- + // + // Provide a container to store, retrieve and + // shut down child views. + Backbone.ChildViewContainer = function(Backbone, _) { + // Container Constructor + // --------------------- + var Container = function(views) { + this._views = {}; + this._indexByModel = {}; + this._indexByCustom = {}; + this._updateLength(); + _.each(views, this.add, this); + }; + // Container Methods + // ----------------- + _.extend(Container.prototype, { + // Add a view to this container. Stores the view + // by `cid` and makes it searchable by the model + // cid (and model itself). Optionally specify + // a custom key to store an retrieve the view. + add: function(view, customIndex) { + var viewCid = view.cid; + // store the view + this._views[viewCid] = view; + // index it by model + if (view.model) { + this._indexByModel[view.model.cid] = viewCid; + } + // index by custom + if (customIndex) { + this._indexByCustom[customIndex] = viewCid; + } + this._updateLength(); + return this; + }, + // Find a view by the model that was attached to + // it. Uses the model's `cid` to find it. + findByModel: function(model) { + return this.findByModelCid(model.cid); + }, + // Find a view by the `cid` of the model that was attached to + // it. Uses the model's `cid` to find the view `cid` and + // retrieve the view using it. + findByModelCid: function(modelCid) { + var viewCid = this._indexByModel[modelCid]; + return this.findByCid(viewCid); + }, + // Find a view by a custom indexer. + findByCustom: function(index) { + var viewCid = this._indexByCustom[index]; + return this.findByCid(viewCid); + }, + // Find by index. This is not guaranteed to be a + // stable index. + findByIndex: function(index) { + return _.values(this._views)[index]; + }, + // retrieve a view by its `cid` directly + findByCid: function(cid) { + return this._views[cid]; + }, + // Remove a view + remove: function(view) { + var viewCid = view.cid; + // delete model index + if (view.model) { + delete this._indexByModel[view.model.cid]; + } + // delete custom index + _.any(this._indexByCustom, function(cid, key) { + if (cid === viewCid) { + delete this._indexByCustom[key]; + return true; + } + }, this); + // remove the view from the container + delete this._views[viewCid]; + // update the length + this._updateLength(); + return this; + }, + // Call a method on every view in the container, + // passing parameters to the call method one at a + // time, like `function.call`. + call: function(method) { + this.apply(method, _.tail(arguments)); + }, + // Apply a method on every view in the container, + // passing parameters to the call method one at a + // time, like `function.apply`. + apply: function(method, args) { + _.each(this._views, function(view) { + if (_.isFunction(view[method])) { + view[method].apply(view, args || []); + } + }); + }, + // Update the `.length` attribute on this container + _updateLength: function() { + this.length = _.size(this._views); } - }, this); - - // remove the view from the container - delete this._views[viewCid]; - - // update the length - this._updateLength(); + }); + // Borrowing this code from Backbone.Collection: + // http://backbonejs.org/docs/backbone.html#section-106 + // + // Mix in methods from Underscore, for iteration, and other + // collection related features. + var methods = [ "forEach", "each", "map", "find", "detect", "filter", "select", "reject", "every", "all", "some", "any", "include", "contains", "invoke", "toArray", "first", "initial", "rest", "last", "without", "isEmpty", "pluck", "reduce" ]; + _.each(methods, function(method) { + Container.prototype[method] = function() { + var views = _.values(this._views); + var args = [ views ].concat(_.toArray(arguments)); + return _[method].apply(_, args); + }; + }); + // return the public API + return Container; + }(Backbone, _); + Backbone.ChildViewContainer.VERSION = "0.1.6"; + Backbone.ChildViewContainer.noConflict = function() { + Backbone.ChildViewContainer = previousChildViewContainer; return this; - }, - - // Call a method on every view in the container, - // passing parameters to the call method one at a - // time, like `function.call`. - call: function(method){ - this.apply(method, _.tail(arguments)); - }, + }; + return Backbone.ChildViewContainer; + })(Backbone, _); - // Apply a method on every view in the container, - // passing parameters to the call method one at a - // time, like `function.apply`. - apply: function(method, args){ - _.each(this._views, function(view){ - if (_.isFunction(view[method])){ - view[method].apply(view, args || []); + /* istanbul ignore next */ + // Backbone.Wreqr (Backbone.Marionette) + // ---------------------------------- + // v1.3.1 + // + // Copyright (c)2014 Derick Bailey, Muted Solutions, LLC. + // Distributed under MIT license + // + // http://github.com/marionettejs/backbone.wreqr + (function(Backbone, _) { + "use strict"; + var previousWreqr = Backbone.Wreqr; + var Wreqr = Backbone.Wreqr = {}; + Backbone.Wreqr.VERSION = "1.3.1"; + Backbone.Wreqr.noConflict = function() { + Backbone.Wreqr = previousWreqr; + return this; + }; + // Handlers + // -------- + // A registry of functions to call, given a name + Wreqr.Handlers = function(Backbone, _) { + "use strict"; + // Constructor + // ----------- + var Handlers = function(options) { + this.options = options; + this._wreqrHandlers = {}; + if (_.isFunction(this.initialize)) { + this.initialize(options); + } + }; + Handlers.extend = Backbone.Model.extend; + // Instance Members + // ---------------- + _.extend(Handlers.prototype, Backbone.Events, { + // Add multiple handlers using an object literal configuration + setHandlers: function(handlers) { + _.each(handlers, function(handler, name) { + var context = null; + if (_.isObject(handler) && !_.isFunction(handler)) { + context = handler.context; + handler = handler.callback; + } + this.setHandler(name, handler, context); + }, this); + }, + // Add a handler for the given name, with an + // optional context to run the handler within + setHandler: function(name, handler, context) { + var config = { + callback: handler, + context: context + }; + this._wreqrHandlers[name] = config; + this.trigger("handler:add", name, handler, context); + }, + // Determine whether or not a handler is registered + hasHandler: function(name) { + return !!this._wreqrHandlers[name]; + }, + // Get the currently registered handler for + // the specified name. Throws an exception if + // no handler is found. + getHandler: function(name) { + var config = this._wreqrHandlers[name]; + if (!config) { + return; + } + return function() { + var args = Array.prototype.slice.apply(arguments); + return config.callback.apply(config.context, args); + }; + }, + // Remove a handler for the specified name + removeHandler: function(name) { + delete this._wreqrHandlers[name]; + }, + // Remove all handlers from this registry + removeAllHandlers: function() { + this._wreqrHandlers = {}; } }); - }, - - // Update the `.length` attribute on this container - _updateLength: function(){ - this.length = _.size(this._views); - } - }); - - // Borrowing this code from Backbone.Collection: - // http://backbonejs.org/docs/backbone.html#section-106 - // - // Mix in methods from Underscore, for iteration, and other - // collection related features. - var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', - 'select', 'reject', 'every', 'all', 'some', 'any', 'include', - 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', - 'last', 'without', 'isEmpty', 'pluck']; + return Handlers; + }(Backbone, _); + // Wreqr.CommandStorage + // -------------------- + // + // Store and retrieve commands for execution. + Wreqr.CommandStorage = function() { + "use strict"; + // Constructor function + var CommandStorage = function(options) { + this.options = options; + this._commands = {}; + if (_.isFunction(this.initialize)) { + this.initialize(options); + } + }; + // Instance methods + _.extend(CommandStorage.prototype, Backbone.Events, { + // Get an object literal by command name, that contains + // the `commandName` and the `instances` of all commands + // represented as an array of arguments to process + getCommands: function(commandName) { + var commands = this._commands[commandName]; + // we don't have it, so add it + if (!commands) { + // build the configuration + commands = { + command: commandName, + instances: [] + }; + // store it + this._commands[commandName] = commands; + } + return commands; + }, + // Add a command by name, to the storage and store the + // args for the command + addCommand: function(commandName, args) { + var command = this.getCommands(commandName); + command.instances.push(args); + }, + // Clear all commands for the given `commandName` + clearCommands: function(commandName) { + var command = this.getCommands(commandName); + command.instances = []; + } + }); + return CommandStorage; + }(); + // Wreqr.Commands + // -------------- + // + // A simple command pattern implementation. Register a command + // handler and execute it. + Wreqr.Commands = function(Wreqr) { + "use strict"; + return Wreqr.Handlers.extend({ + // default storage type + storageType: Wreqr.CommandStorage, + constructor: function(options) { + this.options = options || {}; + this._initializeStorage(this.options); + this.on("handler:add", this._executeCommands, this); + var args = Array.prototype.slice.call(arguments); + Wreqr.Handlers.prototype.constructor.apply(this, args); + }, + // Execute a named command with the supplied args + execute: function(name, args) { + name = arguments[0]; + args = Array.prototype.slice.call(arguments, 1); + if (this.hasHandler(name)) { + this.getHandler(name).apply(this, args); + } else { + this.storage.addCommand(name, args); + } + }, + // Internal method to handle bulk execution of stored commands + _executeCommands: function(name, handler, context) { + var command = this.storage.getCommands(name); + // loop through and execute all the stored command instances + _.each(command.instances, function(args) { + handler.apply(context, args); + }); + this.storage.clearCommands(name); + }, + // Internal method to initialize storage either from the type's + // `storageType` or the instance `options.storageType`. + _initializeStorage: function(options) { + var storage; + var StorageType = options.storageType || this.storageType; + if (_.isFunction(StorageType)) { + storage = new StorageType(); + } else { + storage = StorageType; + } + this.storage = storage; + } + }); + }(Wreqr); + // Wreqr.RequestResponse + // --------------------- + // + // A simple request/response implementation. Register a + // request handler, and return a response from it + Wreqr.RequestResponse = function(Wreqr) { + "use strict"; + return Wreqr.Handlers.extend({ + request: function() { + var name = arguments[0]; + var args = Array.prototype.slice.call(arguments, 1); + if (this.hasHandler(name)) { + return this.getHandler(name).apply(this, args); + } + } + }); + }(Wreqr); + // Event Aggregator + // ---------------- + // A pub-sub object that can be used to decouple various parts + // of an application through event-driven architecture. + Wreqr.EventAggregator = function(Backbone, _) { + "use strict"; + var EA = function() {}; + // Copy the `extend` function used by Backbone's classes + EA.extend = Backbone.Model.extend; + // Copy the basic Backbone.Events on to the event aggregator + _.extend(EA.prototype, Backbone.Events); + return EA; + }(Backbone, _); + // Wreqr.Channel + // -------------- + // + // An object that wraps the three messaging systems: + // EventAggregator, RequestResponse, Commands + Wreqr.Channel = function(Wreqr) { + "use strict"; + var Channel = function(channelName) { + this.vent = new Backbone.Wreqr.EventAggregator(); + this.reqres = new Backbone.Wreqr.RequestResponse(); + this.commands = new Backbone.Wreqr.Commands(); + this.channelName = channelName; + }; + _.extend(Channel.prototype, { + // Remove all handlers from the messaging systems of this channel + reset: function() { + this.vent.off(); + this.vent.stopListening(); + this.reqres.removeAllHandlers(); + this.commands.removeAllHandlers(); + return this; + }, + // Connect a hash of events; one for each messaging system + connectEvents: function(hash, context) { + this._connect("vent", hash, context); + return this; + }, + connectCommands: function(hash, context) { + this._connect("commands", hash, context); + return this; + }, + connectRequests: function(hash, context) { + this._connect("reqres", hash, context); + return this; + }, + // Attach the handlers to a given message system `type` + _connect: function(type, hash, context) { + if (!hash) { + return; + } + context = context || this; + var method = type === "vent" ? "on" : "setHandler"; + _.each(hash, function(fn, eventName) { + this[type][method](eventName, _.bind(fn, context)); + }, this); + } + }); + return Channel; + }(Wreqr); + // Wreqr.Radio + // -------------- + // + // An object that lets you communicate with many channels. + Wreqr.radio = function(Wreqr) { + "use strict"; + var Radio = function() { + this._channels = {}; + this.vent = {}; + this.commands = {}; + this.reqres = {}; + this._proxyMethods(); + }; + _.extend(Radio.prototype, { + channel: function(channelName) { + if (!channelName) { + throw new Error("Channel must receive a name"); + } + return this._getChannel(channelName); + }, + _getChannel: function(channelName) { + var channel = this._channels[channelName]; + if (!channel) { + channel = new Wreqr.Channel(channelName); + this._channels[channelName] = channel; + } + return channel; + }, + _proxyMethods: function() { + _.each([ "vent", "commands", "reqres" ], function(system) { + _.each(messageSystems[system], function(method) { + this[system][method] = proxyMethod(this, system, method); + }, this); + }, this); + } + }); + var messageSystems = { + vent: [ "on", "off", "trigger", "once", "stopListening", "listenTo", "listenToOnce" ], + commands: [ "execute", "setHandler", "setHandlers", "removeHandler", "removeAllHandlers" ], + reqres: [ "request", "setHandler", "setHandlers", "removeHandler", "removeAllHandlers" ] + }; + var proxyMethod = function(radio, system, method) { + return function(channelName) { + var messageSystem = radio._getChannel(channelName)[system]; + var args = Array.prototype.slice.call(arguments, 1); + return messageSystem[method].apply(messageSystem, args); + }; + }; + return new Radio(); + }(Wreqr); + return Backbone.Wreqr; + })(Backbone, _); - _.each(methods, function(method) { - Container.prototype[method] = function() { - var views = _.values(this._views); - var args = [views].concat(_.toArray(arguments)); - return _[method].apply(_, args); - }; - }); + var previousMarionette = root.Marionette; + var previousMn = root.Mn; - // return the public API - return Container; -})(Backbone, _); + var Marionette = Backbone.Marionette = {}; -// Backbone.Wreqr (Backbone.Marionette) -// ---------------------------------- -// v1.0.0 -// -// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC. -// Distributed under MIT license -// -// http://github.com/marionettejs/backbone.wreqr + Marionette.VERSION = '2.4.1'; + Marionette.noConflict = function() { + root.Marionette = previousMarionette; + root.Mn = previousMn; + return this; + }; -Backbone.Wreqr = (function(Backbone, Marionette, _){ - "use strict"; - var Wreqr = {}; + Backbone.Marionette = Marionette; - // Handlers -// -------- -// A registry of functions to call, given a name + // Get the Deferred creator for later use + Marionette.Deferred = Backbone.$.Deferred; -Wreqr.Handlers = (function(Backbone, _){ - "use strict"; + /* jshint unused: false *//* global console */ - // Constructor - // ----------- - - var Handlers = function(options){ - this.options = options; - this._wreqrHandlers = {}; - - if (_.isFunction(this.initialize)){ - this.initialize(options); + // Helpers + // ------- + + // Marionette.extend + // ----------------- + + // Borrow the Backbone `extend` method so we can use it as needed + Marionette.extend = Backbone.Model.extend; + + // Marionette.isNodeAttached + // ------------------------- + + // Determine if `el` is a child of the document + Marionette.isNodeAttached = function(el) { + return Backbone.$.contains(document.documentElement, el); + }; + + // Merge `keys` from `options` onto `this` + Marionette.mergeOptions = function(options, keys) { + if (!options) { return; } + _.extend(this, _.pick(options, keys)); + }; + + // Marionette.getOption + // -------------------- + + // Retrieve an object, function or other value from a target + // object or its `options`, with `options` taking precedence. + Marionette.getOption = function(target, optionName) { + if (!target || !optionName) { return; } + if (target.options && (target.options[optionName] !== undefined)) { + return target.options[optionName]; + } else { + return target[optionName]; } }; - - Handlers.extend = Backbone.Model.extend; - - // Instance Members - // ---------------- - - _.extend(Handlers.prototype, Backbone.Events, { - - // Add multiple handlers using an object literal configuration - setHandlers: function(handlers){ - _.each(handlers, function(handler, name){ - var context = null; - - if (_.isObject(handler) && !_.isFunction(handler)){ - context = handler.context; - handler = handler.callback; - } - - this.setHandler(name, handler, context); - }, this); - }, - - // Add a handler for the given name, with an - // optional context to run the handler within - setHandler: function(name, handler, context){ - var config = { - callback: handler, - context: context - }; - - this._wreqrHandlers[name] = config; - - this.trigger("handler:add", name, handler, context); - }, - - // Determine whether or not a handler is registered - hasHandler: function(name){ - return !! this._wreqrHandlers[name]; - }, - - // Get the currently registered handler for - // the specified name. Throws an exception if - // no handler is found. - getHandler: function(name){ - var config = this._wreqrHandlers[name]; - - if (!config){ - throw new Error("Handler not found for '" + name + "'"); + + // Proxy `Marionette.getOption` + Marionette.proxyGetOption = function(optionName) { + return Marionette.getOption(this, optionName); + }; + + // Similar to `_.result`, this is a simple helper + // If a function is provided we call it with context + // otherwise just return the value. If the value is + // undefined return a default value + Marionette._getValue = function(value, context, params) { + if (_.isFunction(value)) { + value = params ? value.apply(context, params) : value.call(context); + } + return value; + }; + + // Marionette.normalizeMethods + // ---------------------- + + // Pass in a mapping of events => functions or function names + // and return a mapping of events => functions + Marionette.normalizeMethods = function(hash) { + return _.reduce(hash, function(normalizedHash, method, name) { + if (!_.isFunction(method)) { + method = this[method]; } - - return function(){ - var args = Array.prototype.slice.apply(arguments); - return config.callback.apply(config.context, args); + if (method) { + normalizedHash[name] = method; + } + return normalizedHash; + }, {}, this); + }; + + // utility method for parsing @ui. syntax strings + // into associated selector + Marionette.normalizeUIString = function(uiString, ui) { + return uiString.replace(/@ui\.[a-zA-Z_$0-9]*/g, function(r) { + return ui[r.slice(4)]; + }); + }; + + // allows for the use of the @ui. syntax within + // a given key for triggers and events + // swaps the @ui with the associated selector. + // Returns a new, non-mutated, parsed events hash. + Marionette.normalizeUIKeys = function(hash, ui) { + return _.reduce(hash, function(memo, val, key) { + var normalizedKey = Marionette.normalizeUIString(key, ui); + memo[normalizedKey] = val; + return memo; + }, {}); + }; + + // allows for the use of the @ui. syntax within + // a given value for regions + // swaps the @ui with the associated selector + Marionette.normalizeUIValues = function(hash, ui, properties) { + _.each(hash, function(val, key) { + if (_.isString(val)) { + hash[key] = Marionette.normalizeUIString(val, ui); + } else if (_.isObject(val) && _.isArray(properties)) { + _.extend(val, Marionette.normalizeUIValues(_.pick(val, properties), ui)); + /* Value is an object, and we got an array of embedded property names to normalize. */ + _.each(properties, function(property) { + var propertyVal = val[property]; + if (_.isString(propertyVal)) { + val[property] = Marionette.normalizeUIString(propertyVal, ui); + } + }); + } + }); + return hash; + }; + + // Mix in methods from Underscore, for iteration, and other + // collection related features. + // Borrowing this code from Backbone.Collection: + // http://backbonejs.org/docs/backbone.html#section-121 + Marionette.actAsCollection = function(object, listProperty) { + var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', + 'select', 'reject', 'every', 'all', 'some', 'any', 'include', + 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', + 'last', 'without', 'isEmpty', 'pluck']; + + _.each(methods, function(method) { + object[method] = function() { + var list = _.values(_.result(this, listProperty)); + var args = [list].concat(_.toArray(arguments)); + return _[method].apply(_, args); }; - }, - - // Remove a handler for the specified name - removeHandler: function(name){ - delete this._wreqrHandlers[name]; - }, - - // Remove all handlers from this registry - removeAllHandlers: function(){ - this._wreqrHandlers = {}; + }); + }; + + var deprecate = Marionette.deprecate = function(message, test) { + if (_.isObject(message)) { + message = ( + message.prev + ' is going to be removed in the future. ' + + 'Please use ' + message.next + ' instead.' + + (message.url ? ' See: ' + message.url : '') + ); } - }); - - return Handlers; -})(Backbone, _); - - // Wreqr.CommandStorage -// -------------------- -// -// Store and retrieve commands for execution. -Wreqr.CommandStorage = (function(){ - "use strict"; - - // Constructor function - var CommandStorage = function(options){ - this.options = options; - this._commands = {}; - - if (_.isFunction(this.initialize)){ - this.initialize(options); + + if ((test === undefined || !test) && !deprecate._cache[message]) { + deprecate._warn('Deprecation warning: ' + message); + deprecate._cache[message] = true; } }; - - // Instance methods - _.extend(CommandStorage.prototype, Backbone.Events, { - - // Get an object literal by command name, that contains - // the `commandName` and the `instances` of all commands - // represented as an array of arguments to process - getCommands: function(commandName){ - var commands = this._commands[commandName]; - - // we don't have it, so add it - if (!commands){ - - // build the configuration - commands = { - command: commandName, - instances: [] - }; - - // store it - this._commands[commandName] = commands; + + deprecate._warn = typeof console !== 'undefined' && (console.warn || console.log) || function() {}; + deprecate._cache = {}; + + /* jshint maxstatements: 14, maxcomplexity: 7 */ + + // Trigger Method + // -------------- + + Marionette._triggerMethod = (function() { + // split the event name on the ":" + var splitter = /(^|:)(\w)/gi; + + // take the event section ("section1:section2:section3") + // and turn it in to uppercase name + function getEventName(match, prefix, eventName) { + return eventName.toUpperCase(); + } + + return function(context, event, args) { + var noEventArg = arguments.length < 3; + if (noEventArg) { + args = event; + event = args[0]; } - - return commands; - }, - - // Add a command by name, to the storage and store the - // args for the command - addCommand: function(commandName, args){ - var command = this.getCommands(commandName); - command.instances.push(args); - }, - - // Clear all commands for the given `commandName` - clearCommands: function(commandName){ - var command = this.getCommands(commandName); - command.instances = []; + + // get the method name from the event name + var methodName = 'on' + event.replace(splitter, getEventName); + var method = context[methodName]; + var result; + + // call the onMethodName if it exists + if (_.isFunction(method)) { + // pass all args, except the event name + result = method.apply(context, noEventArg ? _.rest(args) : args); + } + + // trigger the event, if a trigger method exists + if (_.isFunction(context.trigger)) { + if (noEventArg + args.length > 1) { + context.trigger.apply(context, noEventArg ? args : [event].concat(_.drop(args, 0))); + } else { + context.trigger(event); + } + } + + return result; + }; + })(); + + // Trigger an event and/or a corresponding method name. Examples: + // + // `this.triggerMethod("foo")` will trigger the "foo" event and + // call the "onFoo" method. + // + // `this.triggerMethod("foo:bar")` will trigger the "foo:bar" event and + // call the "onFooBar" method. + Marionette.triggerMethod = function(event) { + return Marionette._triggerMethod(this, arguments); + }; + + // triggerMethodOn invokes triggerMethod on a specific context + // + // e.g. `Marionette.triggerMethodOn(view, 'show')` + // will trigger a "show" event or invoke onShow the view. + Marionette.triggerMethodOn = function(context) { + var fnc = _.isFunction(context.triggerMethod) ? + context.triggerMethod : + Marionette.triggerMethod; + + return fnc.apply(context, _.rest(arguments)); + }; + + // DOM Refresh + // ----------- + + // Monitor a view's state, and after it has been rendered and shown + // in the DOM, trigger a "dom:refresh" event every time it is + // re-rendered. + + Marionette.MonitorDOMRefresh = function(view) { + + // track when the view has been shown in the DOM, + // using a Marionette.Region (or by other means of triggering "show") + function handleShow() { + view._isShown = true; + triggerDOMRefresh(); } - }); - - return CommandStorage; -})(); - - // Wreqr.Commands -// -------------- -// -// A simple command pattern implementation. Register a command -// handler and execute it. -Wreqr.Commands = (function(Wreqr){ - "use strict"; - - return Wreqr.Handlers.extend({ - // default storage type - storageType: Wreqr.CommandStorage, - - constructor: function(options){ - this.options = options || {}; - - this._initializeStorage(this.options); - this.on("handler:add", this._executeCommands, this); - - var args = Array.prototype.slice.call(arguments); - Wreqr.Handlers.prototype.constructor.apply(this, args); - }, - - // Execute a named command with the supplied args - execute: function(name, args){ - name = arguments[0]; - args = Array.prototype.slice.call(arguments, 1); - - if (this.hasHandler(name)){ - this.getHandler(name).apply(this, args); - } else { - this.storage.addCommand(name, args); + + // track when the view has been rendered + function handleRender() { + view._isRendered = true; + triggerDOMRefresh(); + } + + // Trigger the "dom:refresh" event and corresponding "onDomRefresh" method + function triggerDOMRefresh() { + if (view._isShown && view._isRendered && Marionette.isNodeAttached(view.el)) { + if (_.isFunction(view.triggerMethod)) { + view.triggerMethod('dom:refresh'); + } } - - }, - - // Internal method to handle bulk execution of stored commands - _executeCommands: function(name, handler, context){ - var command = this.storage.getCommands(name); - - // loop through and execute all the stored command instances - _.each(command.instances, function(args){ - handler.apply(context, args); + } + + view.on({ + show: handleShow, + render: handleRender + }); + }; + + /* jshint maxparams: 5 */ + + // Bind Entity Events & Unbind Entity Events + // ----------------------------------------- + // + // These methods are used to bind/unbind a backbone "entity" (e.g. collection/model) + // to methods on a target object. + // + // The first parameter, `target`, must have the Backbone.Events module mixed in. + // + // The second parameter is the `entity` (Backbone.Model, Backbone.Collection or + // any object that has Backbone.Events mixed in) to bind the events from. + // + // The third parameter is a hash of { "event:name": "eventHandler" } + // configuration. Multiple handlers can be separated by a space. A + // function can be supplied instead of a string handler name. + + (function(Marionette) { + 'use strict'; + + // Bind the event to handlers specified as a string of + // handler names on the target object + function bindFromStrings(target, entity, evt, methods) { + var methodNames = methods.split(/\s+/); + + _.each(methodNames, function(methodName) { + + var method = target[methodName]; + if (!method) { + throw new Marionette.Error('Method "' + methodName + + '" was configured as an event handler, but does not exist.'); + } + + target.listenTo(entity, evt, method); }); - - this.storage.clearCommands(name); - }, - - // Internal method to initialize storage either from the type's - // `storageType` or the instance `options.storageType`. - _initializeStorage: function(options){ - var storage; - - var StorageType = options.storageType || this.storageType; - if (_.isFunction(StorageType)){ - storage = new StorageType(); - } else { - storage = StorageType; - } - - this.storage = storage; } - }); - -})(Wreqr); - - // Wreqr.RequestResponse -// --------------------- -// -// A simple request/response implementation. Register a -// request handler, and return a response from it -Wreqr.RequestResponse = (function(Wreqr){ - "use strict"; - - return Wreqr.Handlers.extend({ - request: function(){ - var name = arguments[0]; - var args = Array.prototype.slice.call(arguments, 1); - - return this.getHandler(name).apply(this, args); + + // Bind the event to a supplied callback function + function bindToFunction(target, entity, evt, method) { + target.listenTo(entity, evt, method); } - }); - -})(Wreqr); - - // Event Aggregator -// ---------------- -// A pub-sub object that can be used to decouple various parts -// of an application through event-driven architecture. - -Wreqr.EventAggregator = (function(Backbone, _){ - "use strict"; - var EA = function(){}; - - // Copy the `extend` function used by Backbone's classes - EA.extend = Backbone.Model.extend; - - // Copy the basic Backbone.Events on to the event aggregator - _.extend(EA.prototype, Backbone.Events); - - return EA; -})(Backbone, _); - - - return Wreqr; -})(Backbone, Backbone.Marionette, _); - -var Marionette = (function(global, Backbone, _){ - "use strict"; - - // Define and export the Marionette namespace - var Marionette = {}; - Backbone.Marionette = Marionette; - - // Get the DOM manipulator for later use - Marionette.$ = Backbone.$; - -// Helpers -// ------- - -// For slicing `arguments` in functions -var slice = Array.prototype.slice; - -function throwError(message, name) { - var error = new Error(message); - error.name = name || 'Error'; - throw error; -} - -// Marionette.extend -// ----------------- - -// Borrow the Backbone `extend` method so we can use it as needed -Marionette.extend = Backbone.Model.extend; - -// Marionette.getOption -// -------------------- - -// Retrieve an object, function or other value from a target -// object or its `options`, with `options` taking precedence. -Marionette.getOption = function(target, optionName){ - if (!target || !optionName){ return; } - var value; - - if (target.options && (optionName in target.options) && (target.options[optionName] !== undefined)){ - value = target.options[optionName]; - } else { - value = target[optionName]; - } - - return value; -}; - -// Marionette.normalizeMethods -// ---------------------- - -// Pass in a mapping of events => functions or function names -// and return a mapping of events => functions -Marionette.normalizeMethods = function(hash) { - var normalizedHash = {}, method; - _.each(hash, function(fn, name) { - method = fn; - if (!_.isFunction(method)) { - method = this[method]; - } - if (!method) { - return; - } - normalizedHash[name] = method; - }, this); - return normalizedHash; -}; - -// Trigger an event and/or a corresponding method name. Examples: -// -// `this.triggerMethod("foo")` will trigger the "foo" event and -// call the "onFoo" method. -// -// `this.triggerMethod("foo:bar")` will trigger the "foo:bar" event and -// call the "onFooBar" method. -Marionette.triggerMethod = (function(){ - - // split the event name on the ":" - var splitter = /(^|:)(\w)/gi; - - // take the event section ("section1:section2:section3") - // and turn it in to uppercase name - function getEventName(match, prefix, eventName) { - return eventName.toUpperCase(); - } - - // actual triggerMethod implementation - var triggerMethod = function(event) { - // get the method name from the event name - var methodName = 'on' + event.replace(splitter, getEventName); - var method = this[methodName]; - - // trigger the event, if a trigger method exists - if(_.isFunction(this.trigger)) { - this.trigger.apply(this, arguments); - } - - // call the onMethodName if it exists - if (_.isFunction(method)) { - // pass all arguments, except the event name - return method.apply(this, _.tail(arguments)); - } - }; - - return triggerMethod; -})(); - -// DOMRefresh -// ---------- -// -// Monitor a view's state, and after it has been rendered and shown -// in the DOM, trigger a "dom:refresh" event every time it is -// re-rendered. - -Marionette.MonitorDOMRefresh = (function(documentElement){ - // track when the view has been shown in the DOM, - // using a Marionette.Region (or by other means of triggering "show") - function handleShow(view){ - view._isShown = true; - triggerDOMRefresh(view); - } - - // track when the view has been rendered - function handleRender(view){ - view._isRendered = true; - triggerDOMRefresh(view); - } - - // Trigger the "dom:refresh" event and corresponding "onDomRefresh" method - function triggerDOMRefresh(view){ - if (view._isShown && view._isRendered && isInDOM(view)){ - if (_.isFunction(view.triggerMethod)){ - view.triggerMethod("dom:refresh"); - } + + // Bind the event to handlers specified as a string of + // handler names on the target object + function unbindFromStrings(target, entity, evt, methods) { + var methodNames = methods.split(/\s+/); + + _.each(methodNames, function(methodName) { + var method = target[methodName]; + target.stopListening(entity, evt, method); + }); } - } - - function isInDOM(view) { - return documentElement.contains(view.el); - } - - // Export public API - return function(view){ - view.listenTo(view, "show", function(){ - handleShow(view); - }); - - view.listenTo(view, "render", function(){ - handleRender(view); - }); - }; -})(document.documentElement); - - -// Marionette.bindEntityEvents & unbindEntityEvents -// --------------------------- -// -// These methods are used to bind/unbind a backbone "entity" (collection/model) -// to methods on a target object. -// -// The first parameter, `target`, must have a `listenTo` method from the -// EventBinder object. -// -// The second parameter is the entity (Backbone.Model or Backbone.Collection) -// to bind the events from. -// -// The third parameter is a hash of { "event:name": "eventHandler" } -// configuration. Multiple handlers can be separated by a space. A -// function can be supplied instead of a string handler name. - -(function(Marionette){ - "use strict"; - - // Bind the event to handlers specified as a string of - // handler names on the target object - function bindFromStrings(target, entity, evt, methods){ - var methodNames = methods.split(/\s+/); - - _.each(methodNames,function(methodName) { - - var method = target[methodName]; - if(!method) { - throwError("Method '"+ methodName +"' was configured as an event handler, but does not exist."); - } - - target.listenTo(entity, evt, method); - }); - } - - // Bind the event to a supplied callback function - function bindToFunction(target, entity, evt, method){ - target.listenTo(entity, evt, method); - } - - // Bind the event to handlers specified as a string of - // handler names on the target object - function unbindFromStrings(target, entity, evt, methods){ - var methodNames = methods.split(/\s+/); - - _.each(methodNames,function(methodName) { - var method = target[methodName]; - target.stopListening(entity, evt, method); - }); - } - - // Bind the event to a supplied callback function - function unbindToFunction(target, entity, evt, method){ + + // Bind the event to a supplied callback function + function unbindToFunction(target, entity, evt, method) { target.stopListening(entity, evt, method); - } - - - // generic looping function - function iterateEvents(target, entity, bindings, functionCallback, stringCallback){ - if (!entity || !bindings) { return; } - - // allow the bindings to be a function - if (_.isFunction(bindings)){ - bindings = bindings.call(target); } - - // iterate the bindings and bind them - _.each(bindings, function(methods, evt){ - - // allow for a function as the handler, - // or a list of event names as a string - if (_.isFunction(methods)){ - functionCallback(target, entity, evt, methods); - } else { - stringCallback(target, entity, evt, methods); + + // generic looping function + function iterateEvents(target, entity, bindings, functionCallback, stringCallback) { + if (!entity || !bindings) { return; } + + // type-check bindings + if (!_.isObject(bindings)) { + throw new Marionette.Error({ + message: 'Bindings must be an object or function.', + url: 'marionette.functions.html#marionettebindentityevents' + }); } - - }); - } - - // Export Public API - Marionette.bindEntityEvents = function(target, entity, bindings){ - iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings); - }; - - Marionette.unbindEntityEvents = function(target, entity, bindings){ - iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings); - }; - -})(Marionette); - - -// Callbacks -// --------- - -// A simple way of managing a collection of callbacks -// and executing them at a later point in time, using jQuery's -// `Deferred` object. -Marionette.Callbacks = function(){ - this._deferred = Marionette.$.Deferred(); - this._callbacks = []; -}; - -_.extend(Marionette.Callbacks.prototype, { - - // Add a callback to be executed. Callbacks added here are - // guaranteed to execute, even if they are added after the - // `run` method is called. - add: function(callback, contextOverride){ - this._callbacks.push({cb: callback, ctx: contextOverride}); - - this._deferred.done(function(context, options){ - if (contextOverride){ context = contextOverride; } - callback.call(context, options); - }); - }, - - // Run all registered callbacks with the context specified. - // Additional callbacks can be added after this has been run - // and they will still be executed. - run: function(options, context){ - this._deferred.resolve(context, options); - }, - - // Resets the list of callbacks to be run, allowing the same list - // to be run multiple times - whenever the `run` method is called. - reset: function(){ - var callbacks = this._callbacks; - this._deferred = Marionette.$.Deferred(); - this._callbacks = []; - - _.each(callbacks, function(cb){ - this.add(cb.cb, cb.ctx); - }, this); - } -}); - - -// Marionette Controller -// --------------------- -// -// A multi-purpose object to use as a controller for -// modules and routers, and as a mediator for workflow -// and coordination of other objects, views, and more. -Marionette.Controller = function(options){ - this.triggerMethod = Marionette.triggerMethod; - this.options = options || {}; - - if (_.isFunction(this.initialize)){ - this.initialize(this.options); - } -}; - -Marionette.Controller.extend = Marionette.extend; - -// Controller Methods -// -------------- - -// Ensure it can trigger events with Backbone.Events -_.extend(Marionette.Controller.prototype, Backbone.Events, { - close: function(){ - this.stopListening(); - this.triggerMethod("close"); - this.unbind(); - } -}); - -// Region -// ------ -// -// Manage the visual regions of your composite application. See -// http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/ - -Marionette.Region = function(options){ - this.options = options || {}; - this.el = Marionette.getOption(this, "el"); - - if (!this.el){ - throwError("An 'el' must be specified for a region.", "NoElError"); - } - - if (this.initialize){ - var args = Array.prototype.slice.apply(arguments); - this.initialize.apply(this, args); - } -}; - - -// Region Type methods -// ------------------- - -_.extend(Marionette.Region, { - - // Build an instance of a region by passing in a configuration object - // and a default region type to use if none is specified in the config. - // - // The config object should either be a string as a jQuery DOM selector, - // a Region type directly, or an object literal that specifies both - // a selector and regionType: - // - // ```js - // { - // selector: "#foo", - // regionType: MyCustomRegion - // } - // ``` - // - buildRegion: function(regionConfig, defaultRegionType){ - var regionIsString = _.isString(regionConfig); - var regionSelectorIsString = _.isString(regionConfig.selector); - var regionTypeIsUndefined = _.isUndefined(regionConfig.regionType); - var regionIsType = _.isFunction(regionConfig); - - if (!regionIsType && !regionIsString && !regionSelectorIsString) { - throwError("Region must be specified as a Region type, a selector string or an object with selector property"); - } - - var selector, RegionType; - - // get the selector for the region - - if (regionIsString) { - selector = regionConfig; - } - - if (regionConfig.selector) { - selector = regionConfig.selector; - delete regionConfig.selector; - } - - // get the type for the region - - if (regionIsType){ - RegionType = regionConfig; - } - - if (!regionIsType && regionTypeIsUndefined) { - RegionType = defaultRegionType; - } - - if (regionConfig.regionType) { - RegionType = regionConfig.regionType; - delete regionConfig.regionType; - } - - if (regionIsString || regionIsType) { - regionConfig = {}; - } - - regionConfig.el = selector; - - // build the region instance - var region = new RegionType(regionConfig); - - // override the `getEl` function if we have a parentEl - // this must be overridden to ensure the selector is found - // on the first use of the region. if we try to assign the - // region's `el` to `parentEl.find(selector)` in the object - // literal to build the region, the element will not be - // guaranteed to be in the DOM already, and will cause problems - if (regionConfig.parentEl){ - region.getEl = function(selector) { - var parentEl = regionConfig.parentEl; - if (_.isFunction(parentEl)){ - parentEl = parentEl(); + + // allow the bindings to be a function + bindings = Marionette._getValue(bindings, target); + + // iterate the bindings and bind them + _.each(bindings, function(methods, evt) { + + // allow for a function as the handler, + // or a list of event names as a string + if (_.isFunction(methods)) { + functionCallback(target, entity, evt, methods); + } else { + stringCallback(target, entity, evt, methods); } - return parentEl.find(selector); - }; + + }); } + + // Export Public API + Marionette.bindEntityEvents = function(target, entity, bindings) { + iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings); + }; + + Marionette.unbindEntityEvents = function(target, entity, bindings) { + iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings); + }; + + // Proxy `bindEntityEvents` + Marionette.proxyBindEntityEvents = function(entity, bindings) { + return Marionette.bindEntityEvents(this, entity, bindings); + }; + + // Proxy `unbindEntityEvents` + Marionette.proxyUnbindEntityEvents = function(entity, bindings) { + return Marionette.unbindEntityEvents(this, entity, bindings); + }; + })(Marionette); + - return region; - } - -}); - -// Region Instance Methods -// ----------------------- - -_.extend(Marionette.Region.prototype, Backbone.Events, { - - // Displays a backbone view instance inside of the region. - // Handles calling the `render` method for you. Reads content - // directly from the `el` attribute. Also calls an optional - // `onShow` and `close` method on your view, just after showing - // or just before closing the view, respectively. - show: function(view){ - this.ensureEl(); - - var isViewClosed = view.isClosed || _.isUndefined(view.$el); - var isDifferentView = view !== this.currentView; - - if (isDifferentView) { - this.close(); + // Error + // ----- + + var errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number']; + + Marionette.Error = Marionette.extend.call(Error, { + urlRoot: 'http://marionettejs.com/docs/v' + Marionette.VERSION + '/', + + constructor: function(message, options) { + if (_.isObject(message)) { + options = message; + message = options.message; + } else if (!options) { + options = {}; + } + + var error = Error.call(this, message); + _.extend(this, _.pick(error, errorProps), _.pick(options, errorProps)); + + this.captureStackTrace(); + + if (options.url) { + this.url = this.urlRoot + options.url; + } + }, + + captureStackTrace: function() { + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Marionette.Error); + } + }, + + toString: function() { + return this.name + ': ' + this.message + (this.url ? ' See: ' + this.url : ''); } - - view.render(); - - if (isDifferentView || isViewClosed) { - this.open(view); + }); + + Marionette.Error.extend = Marionette.extend; + + // Callbacks + // --------- + + // A simple way of managing a collection of callbacks + // and executing them at a later point in time, using jQuery's + // `Deferred` object. + Marionette.Callbacks = function() { + this._deferred = Marionette.Deferred(); + this._callbacks = []; + }; + + _.extend(Marionette.Callbacks.prototype, { + + // Add a callback to be executed. Callbacks added here are + // guaranteed to execute, even if they are added after the + // `run` method is called. + add: function(callback, contextOverride) { + var promise = _.result(this._deferred, 'promise'); + + this._callbacks.push({cb: callback, ctx: contextOverride}); + + promise.then(function(args) { + if (contextOverride) { args.context = contextOverride; } + callback.call(args.context, args.options); + }); + }, + + // Run all registered callbacks with the context specified. + // Additional callbacks can be added after this has been run + // and they will still be executed. + run: function(options, context) { + this._deferred.resolve({ + options: options, + context: context + }); + }, + + // Resets the list of callbacks to be run, allowing the same list + // to be run multiple times - whenever the `run` method is called. + reset: function() { + var callbacks = this._callbacks; + this._deferred = Marionette.Deferred(); + this._callbacks = []; + + _.each(callbacks, function(cb) { + this.add(cb.cb, cb.ctx); + }, this); } - - this.currentView = view; - - Marionette.triggerMethod.call(this, "show", view); - Marionette.triggerMethod.call(view, "show"); - }, - - ensureEl: function(){ - if (!this.$el || this.$el.length === 0){ - this.$el = this.getEl(this.el); + }); + + // Controller + // ---------- + + // A multi-purpose object to use as a controller for + // modules and routers, and as a mediator for workflow + // and coordination of other objects, views, and more. + Marionette.Controller = function(options) { + this.options = options || {}; + + if (_.isFunction(this.initialize)) { + this.initialize(this.options); } - }, - - // Override this method to change how the region finds the - // DOM element that it manages. Return a jQuery selector object. - getEl: function(selector){ - return Marionette.$(selector); - }, - - // Override this method to change how the new view is - // appended to the `$el` that the region is managing - open: function(view){ - this.$el.empty().append(view.el); - }, - - // Close the current view, if there is one. If there is no - // current view, it does nothing and returns immediately. - close: function(){ - var view = this.currentView; - if (!view || view.isClosed){ return; } - - // call 'close' or 'remove', depending on which is found - if (view.close) { view.close(); } - else if (view.remove) { view.remove(); } - - Marionette.triggerMethod.call(this, "close", view); - - delete this.currentView; - }, - - // Attach an existing view to the region. This - // will not call `render` or `onShow` for the new view, - // and will not replace the current HTML for the `el` - // of the region. - attachView: function(view){ - this.currentView = view; - }, - - // Reset the region by closing any existing view and - // clearing out the cached `$el`. The next time a view - // is shown via this region, the region will re-query the - // DOM for the region's `el`. - reset: function(){ - this.close(); - delete this.$el; - } -}); - -// Copy the `extend` function used by Backbone's classes -Marionette.Region.extend = Marionette.extend; - -// Marionette.RegionManager -// ------------------------ -// -// Manage one or more related `Marionette.Region` objects. -Marionette.RegionManager = (function(Marionette){ - - var RegionManager = Marionette.Controller.extend({ - constructor: function(options){ - this._regions = {}; - Marionette.Controller.prototype.constructor.call(this, options); + }; + + Marionette.Controller.extend = Marionette.extend; + + // Controller Methods + // -------------- + + // Ensure it can trigger events with Backbone.Events + _.extend(Marionette.Controller.prototype, Backbone.Events, { + destroy: function() { + Marionette._triggerMethod(this, 'before:destroy', arguments); + Marionette._triggerMethod(this, 'destroy', arguments); + + this.stopListening(); + this.off(); + return this; }, - - // Add multiple regions using an object literal, where - // each key becomes the region name, and each value is - // the region definition. - addRegions: function(regionDefinitions, defaults){ - var regions = {}; - - _.each(regionDefinitions, function(definition, name){ - if (_.isString(definition)){ - definition = { selector: definition }; - } - - if (definition.selector){ - definition = _.defaults({}, definition, defaults); + + // import the `triggerMethod` to trigger events with corresponding + // methods if the method exists + triggerMethod: Marionette.triggerMethod, + + // A handy way to merge options onto the instance + mergeOptions: Marionette.mergeOptions, + + // Proxy `getOption` to enable getting options from this or this.options by name. + getOption: Marionette.proxyGetOption + + }); + + // Object + // ------ + + // A Base Class that other Classes should descend from. + // Object borrows many conventions and utilities from Backbone. + Marionette.Object = function(options) { + this.options = _.extend({}, _.result(this, 'options'), options); + + this.initialize.apply(this, arguments); + }; + + Marionette.Object.extend = Marionette.extend; + + // Object Methods + // -------------- + + // Ensure it can trigger events with Backbone.Events + _.extend(Marionette.Object.prototype, Backbone.Events, { + + //this is a noop method intended to be overridden by classes that extend from this base + initialize: function() {}, + + destroy: function() { + this.triggerMethod('before:destroy'); + this.triggerMethod('destroy'); + this.stopListening(); + + return this; + }, + + // Import the `triggerMethod` to trigger events with corresponding + // methods if the method exists + triggerMethod: Marionette.triggerMethod, + + // A handy way to merge options onto the instance + mergeOptions: Marionette.mergeOptions, + + // Proxy `getOption` to enable getting options from this or this.options by name. + getOption: Marionette.proxyGetOption, + + // Proxy `bindEntityEvents` to enable binding view's events from another entity. + bindEntityEvents: Marionette.proxyBindEntityEvents, + + // Proxy `unbindEntityEvents` to enable unbinding view's events from another entity. + unbindEntityEvents: Marionette.proxyUnbindEntityEvents + }); + + /* jshint maxcomplexity: 16, maxstatements: 45, maxlen: 120 */ + + // Region + // ------ + + // Manage the visual regions of your composite application. See + // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/ + + Marionette.Region = Marionette.Object.extend({ + constructor: function(options) { + + // set options temporarily so that we can get `el`. + // options will be overriden by Object.constructor + this.options = options || {}; + this.el = this.getOption('el'); + + // Handle when this.el is passed in as a $ wrapped element. + this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el; + + if (!this.el) { + throw new Marionette.Error({ + name: 'NoElError', + message: 'An "el" must be specified for a region.' + }); + } + + this.$el = this.getEl(this.el); + Marionette.Object.call(this, options); + }, + + // Displays a backbone view instance inside of the region. + // Handles calling the `render` method for you. Reads content + // directly from the `el` attribute. Also calls an optional + // `onShow` and `onDestroy` method on your view, just after showing + // or just before destroying the view, respectively. + // The `preventDestroy` option can be used to prevent a view from + // the old view being destroyed on show. + // The `forceShow` option can be used to force a view to be + // re-rendered if it's already shown in the region. + show: function(view, options) { + if (!this._ensureElement()) { + return; + } + + this._ensureViewIsIntact(view); + + var showOptions = options || {}; + var isDifferentView = view !== this.currentView; + var preventDestroy = !!showOptions.preventDestroy; + var forceShow = !!showOptions.forceShow; + + // We are only changing the view if there is a current view to change to begin with + var isChangingView = !!this.currentView; + + // Only destroy the current view if we don't want to `preventDestroy` and if + // the view given in the first argument is different than `currentView` + var _shouldDestroyView = isDifferentView && !preventDestroy; + + // Only show the view given in the first argument if it is different than + // the current view or if we want to re-show the view. Note that if + // `_shouldDestroyView` is true, then `_shouldShowView` is also necessarily true. + var _shouldShowView = isDifferentView || forceShow; + + if (isChangingView) { + this.triggerMethod('before:swapOut', this.currentView, this, options); + } + + if (this.currentView) { + delete this.currentView._parent; + } + + if (_shouldDestroyView) { + this.empty(); + + // A `destroy` event is attached to the clean up manually removed views. + // We need to detach this event when a new view is going to be shown as it + // is no longer relevant. + } else if (isChangingView && _shouldShowView) { + this.currentView.off('destroy', this.empty, this); + } + + if (_shouldShowView) { + + // We need to listen for if a view is destroyed + // in a way other than through the region. + // If this happens we need to remove the reference + // to the currentView since once a view has been destroyed + // we can not reuse it. + view.once('destroy', this.empty, this); + view.render(); + + view._parent = this; + + if (isChangingView) { + this.triggerMethod('before:swap', view, this, options); } - - var region = this.addRegion(name, definition); - regions[name] = region; + + this.triggerMethod('before:show', view, this, options); + Marionette.triggerMethodOn(view, 'before:show', view, this, options); + + if (isChangingView) { + this.triggerMethod('swapOut', this.currentView, this, options); + } + + // An array of views that we're about to display + var attachedRegion = Marionette.isNodeAttached(this.el); + + // The views that we're about to attach to the document + // It's important that we prevent _getNestedViews from being executed unnecessarily + // as it's a potentially-slow method + var displayedViews = []; + + var triggerBeforeAttach = showOptions.triggerBeforeAttach || this.triggerBeforeAttach; + var triggerAttach = showOptions.triggerAttach || this.triggerAttach; + + if (attachedRegion && triggerBeforeAttach) { + displayedViews = this._displayedViews(view); + this._triggerAttach(displayedViews, 'before:'); + } + + this.attachHtml(view); + this.currentView = view; + + if (attachedRegion && triggerAttach) { + displayedViews = this._displayedViews(view); + this._triggerAttach(displayedViews); + } + + if (isChangingView) { + this.triggerMethod('swap', view, this, options); + } + + this.triggerMethod('show', view, this, options); + Marionette.triggerMethodOn(view, 'show', view, this, options); + + return this; + } + + return this; + }, + + triggerBeforeAttach: true, + triggerAttach: true, + + _triggerAttach: function(views, prefix) { + var eventName = (prefix || '') + 'attach'; + _.each(views, function(view) { + Marionette.triggerMethodOn(view, eventName, view, this); }, this); - - return regions; }, - + + _displayedViews: function(view) { + return _.union([view], _.result(view, '_getNestedViews') || []); + }, + + _ensureElement: function() { + if (!_.isObject(this.el)) { + this.$el = this.getEl(this.el); + this.el = this.$el[0]; + } + + if (!this.$el || this.$el.length === 0) { + if (this.getOption('allowMissingEl')) { + return false; + } else { + throw new Marionette.Error('An "el" ' + this.$el.selector + ' must exist in DOM'); + } + } + return true; + }, + + _ensureViewIsIntact: function(view) { + if (!view) { + throw new Marionette.Error({ + name: 'ViewNotValid', + message: 'The view passed is undefined and therefore invalid. You must pass a view instance to show.' + }); + } + + if (view.isDestroyed) { + throw new Marionette.Error({ + name: 'ViewDestroyedError', + message: 'View (cid: "' + view.cid + '") has already been destroyed and cannot be used.' + }); + } + }, + + // Override this method to change how the region finds the DOM + // element that it manages. Return a jQuery selector object scoped + // to a provided parent el or the document if none exists. + getEl: function(el) { + return Backbone.$(el, Marionette._getValue(this.options.parentEl, this)); + }, + + // Override this method to change how the new view is + // appended to the `$el` that the region is managing + attachHtml: function(view) { + this.$el.contents().detach(); + + this.el.appendChild(view.el); + }, + + // Destroy the current view, if there is one. If there is no + // current view, it does nothing and returns immediately. + empty: function(options) { + var view = this.currentView; + + var preventDestroy = Marionette._getValue(options, 'preventDestroy', this); + // If there is no view in the region + // we should not remove anything + if (!view) { return; } + + view.off('destroy', this.empty, this); + this.triggerMethod('before:empty', view); + if (!preventDestroy) { + this._destroyView(); + } + this.triggerMethod('empty', view); + + // Remove region pointer to the currentView + delete this.currentView; + + if (preventDestroy) { + this.$el.contents().detach(); + } + + return this; + }, + + // call 'destroy' or 'remove', depending on which is found + // on the view (if showing a raw Backbone view or a Marionette View) + _destroyView: function() { + var view = this.currentView; + + if (view.destroy && !view.isDestroyed) { + view.destroy(); + } else if (view.remove) { + view.remove(); + + // appending isDestroyed to raw Backbone View allows regions + // to throw a ViewDestroyedError for this view + view.isDestroyed = true; + } + }, + + // Attach an existing view to the region. This + // will not call `render` or `onShow` for the new view, + // and will not replace the current HTML for the `el` + // of the region. + attachView: function(view) { + this.currentView = view; + return this; + }, + + // Checks whether a view is currently present within + // the region. Returns `true` if there is and `false` if + // no view is present. + hasView: function() { + return !!this.currentView; + }, + + // Reset the region by destroying any existing view and + // clearing out the cached `$el`. The next time a view + // is shown via this region, the region will re-query the + // DOM for the region's `el`. + reset: function() { + this.empty(); + + if (this.$el) { + this.el = this.$el.selector; + } + + delete this.$el; + return this; + } + + }, + + // Static Methods + { + + // Build an instance of a region by passing in a configuration object + // and a default region class to use if none is specified in the config. + // + // The config object should either be a string as a jQuery DOM selector, + // a Region class directly, or an object literal that specifies a selector, + // a custom regionClass, and any options to be supplied to the region: + // + // ```js + // { + // selector: "#foo", + // regionClass: MyCustomRegion, + // allowMissingEl: false + // } + // ``` + // + buildRegion: function(regionConfig, DefaultRegionClass) { + if (_.isString(regionConfig)) { + return this._buildRegionFromSelector(regionConfig, DefaultRegionClass); + } + + if (regionConfig.selector || regionConfig.el || regionConfig.regionClass) { + return this._buildRegionFromObject(regionConfig, DefaultRegionClass); + } + + if (_.isFunction(regionConfig)) { + return this._buildRegionFromRegionClass(regionConfig); + } + + throw new Marionette.Error({ + message: 'Improper region configuration type.', + url: 'marionette.region.html#region-configuration-types' + }); + }, + + // Build the region from a string selector like '#foo-region' + _buildRegionFromSelector: function(selector, DefaultRegionClass) { + return new DefaultRegionClass({el: selector}); + }, + + // Build the region from a configuration object + // ```js + // { selector: '#foo', regionClass: FooRegion, allowMissingEl: false } + // ``` + _buildRegionFromObject: function(regionConfig, DefaultRegionClass) { + var RegionClass = regionConfig.regionClass || DefaultRegionClass; + var options = _.omit(regionConfig, 'selector', 'regionClass'); + + if (regionConfig.selector && !options.el) { + options.el = regionConfig.selector; + } + + return new RegionClass(options); + }, + + // Build the region directly from a given `RegionClass` + _buildRegionFromRegionClass: function(RegionClass) { + return new RegionClass(); + } + }); + + // Region Manager + // -------------- + + // Manage one or more related `Marionette.Region` objects. + Marionette.RegionManager = Marionette.Controller.extend({ + constructor: function(options) { + this._regions = {}; + this.length = 0; + + Marionette.Controller.call(this, options); + + this.addRegions(this.getOption('regions')); + }, + + // Add multiple regions using an object literal or a + // function that returns an object literal, where + // each key becomes the region name, and each value is + // the region definition. + addRegions: function(regionDefinitions, defaults) { + regionDefinitions = Marionette._getValue(regionDefinitions, this, arguments); + + return _.reduce(regionDefinitions, function(regions, definition, name) { + if (_.isString(definition)) { + definition = {selector: definition}; + } + if (definition.selector) { + definition = _.defaults({}, definition, defaults); + } + + regions[name] = this.addRegion(name, definition); + return regions; + }, {}, this); + }, + // Add an individual region to the region manager, // and return the region instance - addRegion: function(name, definition){ + addRegion: function(name, definition) { var region; - - var isObject = _.isObject(definition); - var isString = _.isString(definition); - var hasSelector = !!definition.selector; - - if (isString || (isObject && hasSelector)){ - region = Marionette.Region.buildRegion(definition, Marionette.Region); - } else if (_.isFunction(definition)){ - region = Marionette.Region.buildRegion(definition, Marionette.Region); - } else { + + if (definition instanceof Marionette.Region) { region = definition; + } else { + region = Marionette.Region.buildRegion(definition, Marionette.Region); } - + + this.triggerMethod('before:add:region', name, region); + + region._parent = this; this._store(name, region); - this.triggerMethod("region:add", name, region); + + this.triggerMethod('add:region', name, region); return region; }, - + // Get a region by name - get: function(name){ + get: function(name) { return this._regions[name]; }, - + + // Gets all the regions contained within + // the `regionManager` instance. + getRegions: function() { + return _.clone(this._regions); + }, + // Remove a region by name - removeRegion: function(name){ + removeRegion: function(name) { var region = this._regions[name]; this._remove(name, region); + + return region; }, - - // Close all regions in the region manager, and + + // Empty all regions in the region manager, and // remove them - removeRegions: function(){ - _.each(this._regions, function(region, name){ + removeRegions: function() { + var regions = this.getRegions(); + _.each(this._regions, function(region, name) { this._remove(name, region); }, this); + + return regions; }, - - // Close all regions in the region manager, but + + // Empty all regions in the region manager, but // leave them attached - closeRegions: function(){ - _.each(this._regions, function(region, name){ - region.close(); - }, this); + emptyRegions: function() { + var regions = this.getRegions(); + _.invoke(regions, 'empty'); + return regions; }, - - // Close all regions and shut down the region + + // Destroy all regions and shut down the region // manager entirely - close: function(){ + destroy: function() { this.removeRegions(); - Marionette.Controller.prototype.close.apply(this, arguments); + return Marionette.Controller.prototype.destroy.apply(this, arguments); }, - + // internal method to store regions - _store: function(name, region){ + _store: function(name, region) { + if (!this._regions[name]) { + this.length++; + } + this._regions[name] = region; - this._setLength(); }, - + // internal method to remove a region - _remove: function(name, region){ - region.close(); + _remove: function(name, region) { + this.triggerMethod('before:remove:region', name, region); + region.empty(); + region.stopListening(); + + delete region._parent; delete this._regions[name]; - this._setLength(); - this.triggerMethod("region:remove", name, region); - }, - - // set the number of regions current held - _setLength: function(){ - this.length = _.size(this._regions); + this.length--; + this.triggerMethod('remove:region', name, region); } - - }); - - // Borrowing this code from Backbone.Collection: - // http://backbonejs.org/docs/backbone.html#section-106 - // - // Mix in methods from Underscore, for iteration, and other - // collection related features. - var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', - 'select', 'reject', 'every', 'all', 'some', 'any', 'include', - 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', - 'last', 'without', 'isEmpty', 'pluck']; - - _.each(methods, function(method) { - RegionManager.prototype[method] = function() { - var regions = _.values(this._regions); - var args = [regions].concat(_.toArray(arguments)); - return _[method].apply(_, args); - }; }); + + Marionette.actAsCollection(Marionette.RegionManager.prototype, '_regions'); + - return RegionManager; -})(Marionette); - - -// Template Cache -// -------------- - -// Manage templates stored in `