/*global define */ define(['jquery', 'underscore', 'backbone', 'collections/UserGroup', 'views/GroupListView', 'text!templates/userGroup.html', 'text!templates/alert.html'], function($, _, Backbone, UserGroup, GroupListView, Template, AlertTemplate) { 'use strict'; /** * @class UserGroupView * @classdesc A subview that displays group management. View controls creation of groups and addition * of members to groups * @classcategory Views * @screenshot views/UserGroupView.png */ var UserGroupView = Backbone.View.extend( /** @lends UserGroupView.prototype */ { tagName: "div", className: "span8 subsection", attributes: {'data-section': 'groups'}, type: "UserGroupView", events: { "blur #add-group-name" : "checkGroupName", "click #add-group-submit" : "createGroup" }, template: _.template(Template), alertTemplate: _.template(AlertTemplate), initialize: function(options){ if((typeof options == "undefined")) var options = {}; this.model = options.model; this.subviews = new Array(); }, render: function(){ this.$el.html(this.template()); this.insertCreateGroupForm(); this.listenTo(this.model, "change:isMemberOf", this.getGroups); this.getGroups(); this.delegateEvents(); return this; }, /** * Creates a view of a list of groups that the User is a member of * * @param {UserGroup} userGroup A user group model * @param {Object} viewOptions an object of options for the view */ createGroupList: function(userGroup, viewOptions) { //Only create a list for new groups that aren't yet on the page var existingGroupLists = _.where(this.subviews, {type: "GroupListView"}); if(existingGroupLists) var groupIds = _.pluck(existingGroupLists, "groupId"); if(groupIds && (_.contains(groupIds, userGroup.groupId))) return; //Create a list of the view options if(typeof viewOptions == "object") viewOptions.collection = userGroup; else viewOptions = { collection: userGroup }; //Create the view and save it as a subview var groupView = new GroupListView(viewOptions); this.subviews.push(groupView); //Collapse the views if need be if((userGroup.get("isMemberOf") && (userGroup.get("isMemberOf").length > 3)) || (userGroup.length > 3)) groupView.collapseMemberList(); //Finally, render it and return return groupView.render().el; }, /** * Gets the groups the this user is a part of and creates a UserGroup collection for each */ getGroups: function(){ var view = this, groups = [], model = this.model; //Create a group Collection for each group this user is a member of _.each(_.sortBy(model.get("isMemberOf"), "name"), function(group){ var userGroup = new UserGroup([model], group); groups.push(userGroup); view.listenTo(userGroup, "sync", function(){ var list = this.createGroupList(userGroup); this.$("#group-list-container").append(list); }); userGroup.getGroup(); }); }, /** * Inserts a new form for this user to create a new group. * The form container is grabbed from the template */ insertCreateGroupForm: function(){ //Reset the form $("#add-group-form-container").find("input[type='text']").val("").removeClass("has-error"); $("#group-name-notification-container").empty().removeClass("notification success error"); //Create a pending group that is stored locally until the user submits it this.pendingGroup = new UserGroup([this.model], { pending: true }); var groupView = new GroupListView({ collection: this.pendingGroup }); this.subviews.push(groupView) groupView.setElement(this.$("#add-group-container .member-list")); groupView.render(); }, /** * Returns a container that includes a view of the user's group membership * @param {UserGroup[]} groups An array of UserGroup models * @param {String} listContainer An html string template of a container that will get appended * @returns {String} HTML string filled with groups information */ insertMembership: function(groups, listContainer){ var model = this.model, list = $(document.createElement("ul")).addClass("list-group member-list"), listHeader = $(document.createElement("h5")).addClass("list-group-item list-group-header").text("Member of " + groups.length + " groups") _.each(groups, function(group, i){ var name = group.name || "Group", listItem = $(document.createElement("li")).addClass("list-group-item"), groupLink = group.groupId? $(document.createElement("a")).attr("href", MetacatUI.root + "/profile/" + group.groupId).text(name).appendTo(listItem) : ""; $(list).append(listItem); }); if(this.model.get("username") == MetacatUI.appUserModel.get("username")){ var link = $(document.createElement("a")).attr("href", MetacatUI.root + "/profile/" + MetacatUI.appUserModel.get("username") + "/s=settings/s=groups").text("Create New Group"), icon = $(document.createElement("i")).addClass("icon icon-on-left icon-plus"), listItem = $(document.createElement("li")).addClass("list-group-item create-group").append( $(link).prepend(icon) ); $(list).append(listItem); } listContainer.html(list); list.before(listHeader); return listContainer; }, /** * Will send a request for info about this user and their groups, and redraw the group lists. * Will also reset the "Create New Group" form */ refreshGroupLists: function(){ this.insertCreateGroupForm(); this.model.getInfo(); }, /** * Gets the group name the user has entered and attempts to get this group from the server * If no group is found, then the group name is marked as available. Otherwise an error msg is displayed * @param {Event} e */ checkGroupName: function(e){ if(!e || !e.target) return; var view = this, $notification = $("#group-name-notification-container"), $input = $(e.target); //Get the name typed in by the user var name = $input.val().trim(); if(!name) return; this.listenToOnce(this.pendingGroup, "nameChecked", function(collection){ //If the group name/id is available, then display so if(collection.nameAvailable){ var icon = $(document.createElement("i")).addClass("icon icon-ok"), message = "The name " + collection.name + " is available", container = $(document.createElement("div")).addClass("notification success"); $notification.html($(container).append(icon, message)); $input.removeClass("has-error"); } else{ var icon = $(document.createElement("i")).addClass("icon icon-remove"), message = "The name " + collection.name + " is already taken", container = $(document.createElement("div")).addClass("notification error"); $notification.html($(container).append(icon, message)); $input.addClass("has-error"); } }); this.pendingGroup.checkName(name); }, /** * Syncs the pending group with the server * @param {Event} e */ createGroup: function(e){ e.preventDefault(); //If there is no name specified, give warning if(!this.pendingGroup.name){ var $notification = $("#group-name-notification-container"), $input = $("#add-group-name"); var icon = $(document.createElement("i")).addClass("icon icon-exclamation"), message = "You must enter a group name", container = $(document.createElement("div")).addClass("notification error"); $notification.html($(container).append(icon, message)); $input.addClass("has-error"); return; } //If this name is not available, exit else if(this.pendingGroup.nameAvailable == false) return; var view = this, group = this.pendingGroup; var success = function(data){ view.showAlert("Success! Your group has been saved. View it here", "alert-success", "#add-group-alert-container"); view.refreshGroupLists(); } var error = function(xhr){ var response = xhr? $.parseHTML(xhr.responseText) : null, description = ""; if(response && response.length) description = $(response).find("description").text(); if(description) description = "(" + description + ")."; else description = ""; view.showAlert("Your group could not be created. " + description + " Please try again.", "alert-error", "#add-group-alert-container") } //Create it! if(!this.pendingGroup.save(success, error)) error(); }, /** * Displays an alert message to the user * @param {String} msg Message of the alert * @param {String} classes A class tag * @param {String} container The container tag */ showAlert: function(msg, classes, container) { if(!classes) var classes = 'alert-success'; if(!container || !$(container).length) var container = this.$el; //Remove any alerts that are already in this container if($(container).children(".alert-container").length > 0) $(container).children(".alert-container").remove(); $(container).prepend( this.alertTemplate({ msg: msg, classes: classes }) ); }, /** * Closes the view and clears any subviews */ onClose: function() { this.$el.html(""); this.stopListening(this.model) this.subviews = new Array(); }, }); return UserGroupView; });