/* global define */ define(['underscore', 'jquery', 'backbone', 'models/metadata/eml211/EMLParty', 'text!templates/metadata/EMLParty.html'], function(_, $, Backbone, EMLParty, EMLPartyTemplate){ /** @class EMLPartyView @classdesc The EMLParty renders the content of an EMLParty model @classcategory Views/Metadata @extends Backbone.View */ var EMLPartyView = Backbone.View.extend( /** @lends EMLPartyView.prototype */{ type: "EMLPartyView", tagName: "div", className: "row-fluid eml-party", editTemplate: _.template(EMLPartyTemplate), initialize: function(options){ if(!options) var options = {}; this.isNew = options.isNew || (options.model? false : true); this.model = options.model || new EMLParty(); this.edit = options.edit || false; this.$el.data({ model: this.model }); }, events: { "change" : "updateModel", "focusout" : "showValidation", "keyup .phone" : "formatPhone", "mouseover .remove" : "previewRemove", "mouseout .remove" : "previewRemove" }, render: function(){ //Format the given names var name = this.model.get("individualName") || {}, fullGivenName = ""; //Take multiple given names and combine into one given name. //TODO: Support multiple given names as an array if (Array.isArray(name.givenName)) { fullGivenName = _.map(name.givenName, function(name) { if(typeof name != "undefined" && name) return name.trim(); else return ""; }).join(' '); } else fullGivenName = name.givenName; //Get the address object var address = Array.isArray(this.model.get("address"))? (this.model.get("address")[0] || {}) : (this.model.get("address") || {}); //Use the template with the editing elements if this view has the "edit" flag on if(this.edit){ //Send all the EMLParty info to the template this.$el.html(this.editTemplate({ uniqueId : this.model.cid })); //Populate the form with all the EMLParty values this.$("#" + this.model.cid + "-givenName").val(fullGivenName || ""); this.$("#" + this.model.cid + "-surName").val(name.surName || ""); this.$("#" + this.model.cid + "-position").val(this.model.get("positionName") || ""); this.$("#" + this.model.cid + "-organizationName").val(this.model.get("organizationName") || ""); this.$("#" + this.model.cid + "-email").val(this.model.get("email").length? this.model.get("email")[0] : ""); this.$("#" + this.model.cid + "-website").val(this.model.get("onlineUrl").length? this.model.get("onlineUrl")[0] : ""); this.$("#" + this.model.cid + "-phone").val(this.model.get("phone").length? this.model.get("phone")[0] : ""); this.$("#" + this.model.cid + "-fax").val(this.model.get("fax").length? this.model.get("fax")[0] : ""); this.$("#" + this.model.cid + "-orcid").val(Array.isArray(this.model.get("userId"))? this.model.get("userId")[0] : this.model.get("userId") || ""); this.$("#" + this.model.cid + "-address").val(address.deliveryPoint && address.deliveryPoint.length? address.deliveryPoint[0] : ""); this.$("#" + this.model.cid + "-address2").val(address.deliveryPoint && address.deliveryPoint.length > 1? address.deliveryPoint[1] : ""); this.$("#" + this.model.cid + "-city").val(address.city || ""); this.$("#" + this.model.cid + "-state").val(address.administrativeArea || ""); this.$("#" + this.model.cid + "-zip").val(address.postalCode || ""); this.$("#" + this.model.cid + "-country").val(address.country || ""); } //If this EML Party is new/empty, then add the new class if(this.isNew){ this.$el.addClass("new"); } //Save the view and model on the element this.$el.data({ model: this.model, view: this }); this.$el.attr("data-category", this.model.get("type")); return this; }, updateModel: function(e){ if(!e) return false; //Get the attribute that was changed var changedAttr = $(e.target).attr("data-attribute"); if(!changedAttr) return false; //Get the current value var currentValue = this.model.get(changedAttr); //Addresses and Names have special rules for updating switch(changedAttr){ case "deliveryPoint": this.updateAddress(e); return; case "city": this.updateAddress(e); return; case "administrativeArea": this.updateAddress(e); return; case "country": this.updateAddress(e); return; case "postalCode": this.updateAddress(e); return; case "surName": this.updateName(e); return; case "givenName": this.updateName(e); return; case "salutation": this.updateName(e); return; } //Update the EMLParty model with the new value if(Array.isArray(currentValue)){ //Get the position that this new value should go in var position = this.$("[data-attribute='" + changedAttr + "']").index(e.target); if( $(e.target).val() == "" ){ //Remove the current value from the array if there is no value in the input field currentValue.splice(position, 1); } else{ var emlModel = this.model.getParentEML(), value = $(e.target).val(); if( emlModel ){ value = emlModel.cleanXMLText(value); } //Put the new value in the array at the correct position currentValue[position] = value; } this.model.set(changedAttr, currentValue); this.model.trigger("change:" + changedAttr); this.model.trigger("change"); } else{ //If the value of the input field is nothing, then reset the field if( $(e.target).val() == "" ){ this.model.set(changedAttr, this.model.defaults()[changedAttr]); } else{ var emlModel = this.model.getParentEML(), value = $(e.target).val(); if( emlModel ){ value = emlModel.cleanXMLText(value); } this.model.set(changedAttr, value); } } //If this is a new EML Party, add it to the parent EML211 model if(this.isNew){ var mergeSuccess = this.model.mergeIntoParent(); //If the merge was sucessfull, mark this as not new if( mergeSuccess ) this.notNew(); } //If this EMLParty model has been removed from the parent EML model, //then add it back if( this.model.get("removed") ){ var position = this.$el.parent().children(".eml-party").index(this.$el); this.model.get("parentModel").addParty(this.model); this.model.set("removed", false); } this.model.trickleUpChange(); }, updateAddress: function(e){ if(!e) return false; //Get the address part that was changed var changedAttr = $(e.target).attr("data-attribute"); if(!changedAttr) return false; //TODO: Allow multiple addresses - right now we only support editing the first address var address = this.model.get("address")[0] || {}, currentValue = address[changedAttr]; //Get the parent EML model and the value from the input element var emlModel = this.model.getParentEML(), value = $(e.target).val(); //If there is a parent EML model, clean up the text for XML if( emlModel ){ value = emlModel.cleanXMLText(value); } //Update the address if(Array.isArray(currentValue)){ //Get the position that this new value should go in var position = this.$("[data-attribute='" + changedAttr + "']").index(e.target); //Put the new value in the array at the correct position currentValue[position] = value; } //Make sure delivery points are saved as arrays else if(changedAttr == "deliveryPoint"){ address[changedAttr] = [value]; } else address[changedAttr] = value; //Update the model var allAddresses = this.model.get("address"); allAddresses[0] = address; this.model.set("address", allAddresses); //If this is a new EML Party, add it to the parent EML211 model if(this.isNew){ var mergeSuccess = this.model.mergeIntoParent(); //If the merge was sucessfull, mark this as not new if( mergeSuccess ) this.notNew(); } //If this EMLParty model has been removed from the parent EML model, //then add it back if( this.model.get("removed") ){ var position = this.$el.parent().children(".eml-party").index(this.$el); this.model.get("parentModel").addParty(this.model); this.model.set("removed", false); } //Manually trigger the change event since it's an object this.model.trigger("change:address"); this.model.trigger("change"); this.model.trickleUpChange(); }, updateName: function(e){ if(!e) return false; //Get the address part that was changed var changedAttr = $(e.target).attr("data-attribute"); if(!changedAttr) return false; //TODO: Allow multiple given names - right now we only support editing the first given name var name = this.model.get("individualName") || {}, currentValue = String.prototype.trim(name[changedAttr]); //Get the parent EML model and the value from the input element var emlModel = this.model.getParentEML(), value = $(e.target).val().trim(); //If there is a parent EML model, clean up the text for XML if( emlModel ){ value = emlModel.cleanXMLText(value); } //Update the name if(Array.isArray(currentValue)){ //Get the position that this new value should go in var position = this.$("[data-attribute='" + changedAttr + "']").index(e.target); //Put the new value in the array at the correct position currentValue[position] = value; } else if(changedAttr == "givenName"){ name.givenName = value; } else name[changedAttr] = value; //Update the value on the model this.model.set("individualName", name); //If this is a new EML Party, add it to the parent EML211 model if(this.isNew){ var mergeSuccess = this.model.mergeIntoParent(); //If the merge was sucessfull, mark this as not new if( mergeSuccess ) this.notNew(); } //If this EMLParty model has been removed from the parent EML model, //then add it back if( this.model.get("removed") ){ var position = this.$el.parent().children(".eml-party").index(this.$el); this.model.get("parentModel").addParty(this.model); this.model.set("removed", false); } //Manually trigger a change on the name attribute this.model.trigger("change:individualName"); this.model.trigger("change"); this.model.trickleUpChange(); }, /** * Validates and displays error messages for the persons' name, position * and organization name. * */ showValidation: function() { //Remove the error styling this.$(".notification").empty(); this.$(".error").removeClass("error"); // Check if there are values to validate if( this.isEmpty() ) { //Remove this EMLParty model from it's parent model instead //of showing a validation error, since it's completely empty this.model.removeFromParent(); return; } //If the model is valid, exit else if (this.model.isValid()) { return; } else{ //Start the full error message string for all the EMLParty errors var errorMessages = ""; //Iterate over each field that has a validation error _.mapObject( this.model.validationError, function(errorMsg, attribute){ //Find the input element for this attribute and add the error styling this.$("[data-attribute='" + attribute + "']").addClass("error"); //Add this error message to the full error messages string errorMessages += errorMsg + " "; }, this); //Add the full error message text to the notification area and add the error styling this.$(".notification").text(errorMessages).addClass("error"); } }, /** * Checks if the user has entered any data in the fields. * * @return {bool} True if the user hasn't entered any party info, otherwise returns false */ isEmpty: function() { // If we add any new fields, be sure to add the data-attribute here. var attributes = ["country", "city", "administrativeArea", "postalCode", "deliveryPoint","userId", "fax", "phone", "onlineUrl", "email", "givenName", "surName", "positionName", "organizationName"]; for(var i in attributes) { var attribute = "[data-attribute='"+attributes[i]+"']"; if(this.$(attribute).val() != "") return false; } return true; }, // A function to format text to look like a phone number formatPhone: function(e){ // Strip all characters from the input except digits var input = $(e.target).val().replace(/\D/g,''); // Trim the remaining input to ten characters, to preserve phone number format input = input.substring(0,10); // Based upon the length of the string, we add formatting as necessary var size = input.length; if(size == 0){ input = input; }else if(size < 4){ input = '('+input; }else if(size < 7){ input = '('+input.substring(0,3)+') '+input.substring(3,6); }else{ input = '('+input.substring(0,3)+') '+input.substring(3,6)+' - '+input.substring(6,10); } $(e.target).val(input); }, previewRemove: function(){ this.$("input, img, label").toggleClass("remove-preview"); }, /** * Changes this view and its model from -new- to -not new- * "New" means this EMLParty model is not referenced or stored on a * parent model, and this view is being displayed to the user so they can * add a new party to their EML (versus edit an existing one). */ notNew: function(){ this.isNew = false; this.$el.removeClass("new"); this.$el.find(".new").removeClass("new"); } }); return EMLPartyView; });