You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2014/08/19 12:30:40 UTC
[2/9] git commit: Simplifies showing catalogue details a bit.
Simplifies showing catalogue details a bit.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/cf1775be
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/cf1775be
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/cf1775be
Branch: refs/heads/master
Commit: cf1775bef90532be3f365ece3ceed8978f1c3105
Parents: 68ae235
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Fri Aug 8 14:52:08 2014 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Wed Aug 13 17:23:16 2014 +0100
----------------------------------------------------------------------
.../src/main/webapp/assets/js/view/catalog.js | 203 +++++++++----------
.../webapp/assets/tpl/catalog/nav-entry.html | 2 +-
.../main/webapp/assets/tpl/catalog/page.html | 5 -
3 files changed, 96 insertions(+), 114 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf1775be/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
index 6f8d059..0e89c58 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
@@ -30,11 +30,14 @@ define([
], function(_, $, Backbone, FormatJSON, Location, Entity, AddLocationModalView,
CatalogPageHtml, DetailsEntityHtml, DetailsGenericHtml, EntryHtml, LocationDetailsHtml) {
- // Holds the currently active details type, e.g. applications, policies
- var activeDetails;
+ // Holds the currently active details type, e.g. applications, policies. Bit of a workaround
+ // to share the active view with all instances of AccordionItemView, so clicking the 'reload
+ // catalog' button (handled by the parent of the AIVs) does not apply the 'active' class to
+ // more than one element.
+ var activeDetailsView;
// TODO: Loading item's details should perform page navigation
- var DetailsView = Backbone.View.extend({
+ var CatalogItemDetailsView = Backbone.View.extend({
events: {
"click .delete": "deleteItem"
@@ -42,36 +45,50 @@ define([
initialize: function() {
_.bindAll(this);
+ this.options.template = _.template(this.options.template || DetailsGenericHtml);
},
- render: function(extraMessage) {
+ render: function() {
+ if (!this.options.model) {
+ return this.renderEmpty();
+ } else {
+ return this.renderDetails();
+ }
+ },
+
+ renderEmpty: function(extraMessage) {
this.$el.html("<div class='catalog-details'>" +
"<h3>Select an entry on the left</h3>" +
(extraMessage ? extraMessage : "") +
"</div>");
+ return this;
},
- show: function(model, template) {
- // Keep the previously open section open between items
- var open = this.$(".in").attr("id");
- var newHtml = $(template({model: model}));
- $(newHtml).find("#"+open).addClass("in");
- this.$el.html(newHtml);
-
- // rewire events. previous callbacks are removed automatically.
- this.delegateEvents()
- },
+ renderDetails: function() {
+ var that = this,
+ model = this.options.model,
+ template = this.options.template;
+ var show = function() {
+ // Keep the previously open section open between items. Duplication between
+ // here and setDetailsView, below. This case handles view refreshes from this
+ // view directly (e.g. when indicating an error), below handles keeping the
+ // right thing open when navigating from view to view.
+ var open = this.$(".in").attr("id");
+ var newHtml = $(template({model: model}));
+ $(newHtml).find("#"+open).addClass("in");
+ that.$el.html(newHtml);
+ // rewire events. previous callbacks are removed automatically.
+ that.delegateEvents()
+ };
- showDetailsFor: function(model, template) {
this.activeModel = model;
- var that = this;
// Load the view with currently available data and refresh once the load is complete.
// Only refreshes the view if the model changes and the user hasn't selected another
// item while the load was executing.
- this.show(model, template);
+ show();
model.on("change", function() {
if (that.activeModel.cid === model.cid) {
- that.show(model, template);
+ show();
}
});
model.fetch()
@@ -79,13 +96,14 @@ define([
console.log("error loading", model.id, ":", errorThrown);
if (that.activeModel.cid === model.cid) {
model.error = true;
- that.show(model, template);
+ show();
}
})
// Runs after the change event fires, or after the xhr completes
.always(function () {
model.off("change");
});
+ return this;
},
deleteItem: function(event) {
@@ -94,7 +112,7 @@ define([
// removal. Useful if delete fails for e.g. lack of entitlement.
this.activeModel.destroy();
var displayName = $(event.currentTarget).data("name");
- this.render(displayName ? "Deleted " + displayName : "");
+ this.renderEmpty(displayName ? "Deleted " + displayName : "");
}
});
@@ -111,10 +129,6 @@ define([
}
});
- var accordionBodyTemplate = _.template(
- "<div class='accordion-head capitalized'><%= name %></div>" +
- "<div class='accordion-body' style='display: <%= display %>'></div>");
-
/** Use to fill single accordion view list. */
var AccordionItemView = Backbone.View.extend({
tag: "div",
@@ -123,21 +137,25 @@ define([
'click .accordion-head': 'toggle',
'click .accordion-nav-row': 'showDetails'
},
+ bodyTemplate: _.template(
+ "<div class='accordion-head capitalized'><%= name %></div>" +
+ "<div class='accordion-body' style='display: <%= display %>'></div>"),
initialize: function() {
_.bindAll(this);
this.name = this.options.name;
if (!this.name) {
throw new Error("Name should have been given for accordion entry");
+ } else if (!this.options.onItemSelected) {
+ throw new Error("onItemSelected(model, element) callback should have been given for accordion entry");
}
// Generic templates
this.template = _.template(this.options.template || EntryHtml);
- this.detailsTemplate = _.template(this.options.detailsTemplate || DetailsGenericHtml);
// Returns template applied to function arguments. Alter if collection altered.
// Will be run in the context of the AccordionItemView.
- this.templateArgs = this.options.templateArgs || function(model, index) {
+ this.entryTemplateArgs = this.options.entryTemplateArgs || function(model, index) {
return {type: model.get("type"), id: model.get("id")};
};
@@ -160,7 +178,7 @@ define([
},
render: function() {
- this.$el.html(accordionBodyTemplate({
+ this.$el.html(this.bodyTemplate({
name: this.name,
display: this.options.autoOpen ? "block" : "none"
}));
@@ -169,38 +187,32 @@ define([
},
renderEntries: function() {
+ var name = this.name, active = this.activeCid;
var templater = function(model, index) {
- var args = _.extend({cid: model.cid}, this.templateArgs(model));
+ var args = _.extend({
+ cid: model.cid,
+ extraClasses: (activeDetailsView == name && model.cid == active) ? "active" : ""
+ }, this.entryTemplateArgs(model));
return this.template(args);
};
var elements = this.collection.map(templater, this);
this.$(".accordion-body")
.empty()
.append(elements.join(''));
- // Rehighlight active model
- if (this.activeCid && activeDetails === this.name) {
- $(".accordion-nav-row").removeClass("active");
- this.setActiveItem(this.$("[data-cid='"+this.activeCid+"'"));
- }
},
refresh: function() {
this.collection.fetch();
},
- setActiveItem: function($element) {
- $(".accordion-nav-row").removeClass("active");
- $element.addClass("active");
- activeDetails = this.name;
- },
-
showDetails: function(event) {
var $event = $(event.currentTarget);
- if (!$event.hasClass("active")) {
- this.setActiveItem($event);
- var cid = this.activeCid = $(event.currentTarget).data("cid");
+ var cid = $event.data("cid");
+ if (activeDetailsView !== this.name || this.activeCid !== cid) {
+ activeDetailsView = this.name;
+ this.activeCid = cid;
var model = this.collection.get(cid);
- this.options.details.showDetailsFor(model, this.detailsTemplate);
+ this.options.onItemSelected(model, $event);
}
},
@@ -208,15 +220,14 @@ define([
var body = this.$(".accordion-body");
var hidden = this.hidden = body.css("display") == "none";
if (hidden) {
- this.$el.addClass('active');
body.removeClass("hide").slideDown('fast');
} else {
- this.$el.removeClass('active');
body.slideUp('fast')
}
}
});
+ // Controls whole page. Parent of accordion items and details view.
var CatalogResourceView = Backbone.View.extend({
tagName:"div",
className:"container container-fluid",
@@ -234,50 +245,49 @@ define([
initialize: function() {
$(".nav1").removeClass("active");
$(".nav1_catalog").addClass("active");
- this.detailsView = new DetailsView();
- this.accordion = this.options.accordion || [
- new AccordionItemView({
+ // Important that bind happens before accordion object is created. If it happens after
+ // `this' will not be set correctly for the onItemSelected callbacks.
+ _.bindAll(this);
+ this.accordion = this.options.accordion || {
+ "applications": new AccordionItemView({
name: "applications",
- details: this.detailsView,
- detailsTemplate: DetailsEntityHtml,
+ onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
model: Entity.Model,
autoOpen: true
}),
- new AccordionItemView({
+ "entities": new AccordionItemView({
name: "entities",
- details: this.detailsView,
- detailsTemplate: DetailsEntityHtml,
+ onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
model: Entity.Model
}),
- new AccordionItemView({
- name: "policies",
- detailsTemplate: DetailsGenericHtml,
- details: this.detailsView
+ "policies": new AccordionItemView({
+ onItemSelected: _.partial(this.showCatalogItem, DetailsGenericHtml),
+ name: "policies"
}),
- new AccordionItemView({
+ "locations": new AccordionItemView({
name: "locations",
- details: this.detailsView,
- detailsTemplate: LocationDetailsHtml,
+ onItemSelected: _.partial(this.showCatalogItem, LocationDetailsHtml),
collection: this.options.locations,
- templateArgs: function(location, index) {
+ entryTemplateArgs: function (location, index) {
return {
type: location.getPrettyName(),
id: location.getLinkByName("self")
};
}
})
- ];
- _.bindAll(this);
+ };
},
beforeClose: function() {
_.invoke(this.accordion, 'close');
},
- render: function(eventName) {
+ render: function() {
this.$el.html(_.template(CatalogPageHtml, {}));
- this.detailsView.$el = this.$("#details");
- this.detailsView.render();
+
+ // Show empty details view to start
+ this.setDetailsView(new CatalogItemDetailsView().render());
+
var parent = this.$(".catalog-accordion-parent");
_.each(this.accordion, function(child) {
parent.append(child.render().$el);
@@ -291,53 +301,30 @@ define([
},
createNewThing: function(event) {
- var that = this;
- if (_.contains(that.genericTabs, that.activeAccordion)) {
- that.addNewCatalogResource(event)
- } else if (that.activeAccordion=='locations') {
- that.addLocation(event)
- } else {
- that.$('#accordion-empty-to-create-info-message').slideDown('slow').delay(2000).slideUp('slow')
- }
- },
- addNewCatalogResource: function(event) {
- $('#new-entity-modal').modal('show')
},
- newEntitySubmit: function(event) {
- var $entityForm = $('#new-entity-form'),
- $entityModal = $('#new-entity-modal'),
- self = this;
- $entityModal.fadeTo(500,0.5);
- var options = {
- url:'/v1/catalog/',
- type:'post',
- success: function(data) {
- $entityModal.modal('hide');
- $entityModal.fadeTo(500,1);
- self.refresh()
- },
- error: function(data) {
- $entityModal.fadeTo(100,1).delay(200).fadeTo(200,0.2).delay(200).fadeTo(200,1);
- // TODO render the error (want better feedback than this poor-man's flashing)
- }
- };
- $entityForm.ajaxSubmit(options);
- return false
- },
-
- addLocation: function(event) {
- var locationModalView = new AddLocationModalView({
- model:new Location.Model(),
- appRouter:this.options.appRouter
- });
- this.$('#new-location-modal').replaceWith(locationModalView.render().$el);
- this.$('#new-location-modal').modal('show');
+ showCatalogItem: function(template, model, $target) {
+ this.$(".accordion-nav-row").removeClass("active");
+ $target.addClass("active");
+ var newView = new CatalogItemDetailsView({
+ model: model,
+ template: template
+ }).render();
+ this.setDetailsView(newView)
},
- deleteLocation: function(event) {
- this.model.get(event.currentTarget['id']).destroy();
+ setDetailsView: function(view) {
+ this.$("#details").html(view.el);
+ if (this.detailsView) {
+ // Try to re-open sections that were previously visible.
+ var openedItem = this.detailsView.$(".in").attr("id");
+ if (openedItem) {
+ view.$("#" + openedItem).addClass("in");
+ }
+ this.detailsView.close();
+ }
+ this.detailsView = view;
}
});
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf1775be/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
index 922f254..9c6dcbf 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
@@ -16,4 +16,4 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<div data-cid="<%= cid %>" class="accordion-nav-row"><%= type %></div>
+<div data-cid="<%= cid %>" class="accordion-nav-row <%= extraClasses %>"><%= type %></div>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf1775be/usage/jsgui/src/main/webapp/assets/tpl/catalog/page.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/page.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/page.html
index a945329..2c6a156 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/page.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/page.html
@@ -29,11 +29,6 @@ under the License.
</div>
</div>
<div class="navbar_main_wrapper">
- <div id="accordion-empty-to-create-info-message" class="label-message hide">
- <div class="label-important full-width">ERROR</div>
- No category selected.
- Select the category of the item type you wish to add.
- </div>
<div class="catalog-accordion-parent catalog-accordion-wrapper"></div>
</div>
</div>