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
* @extends Backbone.View
*/
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)
: "<a></a>";
$(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 <a href='" +
MetacatUI.root +
"/profile/" +
group.groupId +
"'>here</a>",
"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;
});