/* global define */
define(['underscore', 'jquery', 'backbone',
'models/DataONEObject',
'models/metadata/eml211/EMLAttribute',
'models/metadata/eml211/EMLMeasurementScale',
'views/metadata/EMLMeasurementScaleView',
'text!templates/metadata/eml-attribute.html'],
function(_, $, Backbone, DataONEObject, EMLAttribute, EMLMeasurementScale,
EMLMeasurementScaleView, EMLAttributeTemplate){
/**
* @class EMLAttributeView
* @classdesc An EMLAttributeView displays the info about one attribute in a data object
* @classcategory Views/Metadata
* @extends Backbone.View
*/
var EMLAttributeView = Backbone.View.extend(
/** @lends EMLAttributeView.prototype */{
tagName: "div",
className: "eml-attribute",
id: null,
/* The HTML template for an attribute */
template: _.template(EMLAttributeTemplate),
/* Events this view listens to */
events: {
"change .input": "updateModel",
"focusout" : "showValidation",
"keyup .error" : "hideValidation",
"click .radio" : "hideValidation"
},
initialize: function(options){
if(!options)
var options = {};
this.isNew = (options.isNew == true) ? true : options.model? false : true;
this.model = options.model || new EMLAttribute({xmlID: DataONEObject.generateId()});
},
render: function(){
var templateInfo = {
title: this.model.get("attributeName")? this.model.get("attributeName") : "Add New Attribute"
}
_.extend(templateInfo, this.model.toJSON());
//Render the template
var viewHTML = this.template(templateInfo);
//Insert the template HTML
this.$el.html(viewHTML);
var measurementScaleModel = this.model.get("measurementScale");
if( !this.model.get("measurementScale") ){
//Create a new EMLMeasurementScale model if this is a new attribute
measurementScaleModel = EMLMeasurementScale.getInstance();
}
//Save a reference to this EMLAttribute model
measurementScaleModel.set("parentModel", this.model);
//Create an EMLMeasurementScaleView for this attribute's measurement scale
var measurementScaleView = new EMLMeasurementScaleView({
model: measurementScaleModel,
parentView: this
});
//Render the EMLMeasurementScaleView and insert it into this view
measurementScaleView.render();
this.$(".measurement-scale-container").append(measurementScaleView.el);
this.measurementScaleView = measurementScaleView;
//Mark this view DOM as new if it is a new attribute
if(this.isNew){
this.$el.addClass("new");
}
//Save a reference to this model's id in the DOM
this.$el.attr("data-attribute-id", this.model.cid);
},
postRender: function(){
this.measurementScaleView.postRender();
},
updateModel: function(e){
if(!e) return;
var emlModel = this.model.get("parentModel"),
tries = 0;
while (emlModel.type !== "EML" && tries < 6){
emlModel = emlModel.get("parentModel");
tries++;
}
var newValue = emlModel? emlModel.cleanXMLText( $(e.target).val() ) : $(e.target).val(),
category = $(e.target).attr("data-category"),
currentValue = this.model.get(category);
//If the new value is just a string of space characters, then set it to an empty string
if( typeof newValue == "string" && !newValue.trim().length ){
newValue = "";
}
// If the current value is an array...
if(Array.isArray(currentValue)){
//Get the position of the updated DOM element
var index = this.$(".input[data-category='" + category + "']").index(e.target);
//If there is at least one value already in the array...
if(currentValue.length > 0){
//If the new value is a falsey value, then don't' set it on the model
if( typeof newValue == "undefined" || newValue === false || newValue === null){
//Remove one element at this index instead of inserting an
// empty value
var newArray = currentValue.splice(index, 1);
//Set the new array on the model
this.model.set(category, newArray);
}
//Otherwise, insert the value in the array at the calculated index
else{
currentValue[index] = newValue;
}
}
// Otherwise if it's an empty array AND there is a value to set...
else if( typeof newValue != "undefined" && newValue !== false && newValue !== null){
//Push the new value into this array
currentValue.push(newValue);
}
//Trigger a change on this model attribute
this.model.trigger("change:" + category);
}
//If the value is not an array...
else{
//Check that there is an actual value here
if( typeof newValue != "undefined" && newValue !== false && newValue !== null){
this.model.set(category, newValue);
}
}
},
showValidation: function(){
var view = this;
setTimeout(function(){
//If the user focused on another element in this view, don't do anything
if( _.contains($(document.activeElement).parents(), view.el) )
return;
//Reset the error messages and styling
view.$el.removeClass("error");
view.$(".error").removeClass("error");
view.$(".notification").text("");
if(!view.model.isValid()){
var errors = view.model.validationError;
_.each(Object.keys(errors), function(attr){
view.$(".input[data-category='" + attr + "']").addClass("error");
view.$(".radio [data-category='" + attr + "']").addClass("error");
view.$("[data-category='" + attr + "'] .notification").text(errors[attr]).addClass("error");
}, view);
view.$el.addClass("error");
}
//If the measurement scale model is not valid
if(view.model.get("measurementScale") && !view.model.get("measurementScale").isValid()){
view.measurementScaleView.showValidation();
}
}, 200);
},
hideValidation: function(e){
var input = $(e.target),
category = input.attr("data-category");
input.removeClass("error");
this.$("[data-category='" + category + "'] .notification").removeClass("error").empty();
}
});
return EMLAttributeView;
});