/* global define */ define(['underscore', 'jquery', 'backbone', 'models/metadata/eml211/EMLGeoCoverage', 'text!templates/metadata/EMLGeoCoverage.html'], function (_, $, Backbone, EMLGeoCoverage, EMLGeoCoverageTemplate) { /** * @class EMlGeoCoverageView * @classdesc The EMLGeoCoverage renders the content of an EMLGeoCoverage model * @classcategory Views/Metadata * @extends Backbone.View */ var EMLGeoCoverageView = Backbone.View.extend( /** @lends EMLGeoCoverageView.prototype */{ type: "EMLGeoCoverageView", tagName: "div", className: "row-fluid eml-geocoverage", attributes: { "data-category": "geoCoverage" }, editTemplate: _.template(EMLGeoCoverageTemplate), initialize: function (options) { if (!options) var options = {}; this.isNew = options.isNew || (options.model ? false : true); this.model = options.model || new EMLGeoCoverage(); this.edit = options.edit || false; }, events: { "change": "updateModel", "mouseover .remove": "toggleRemoveClass", "mouseout .remove": "toggleRemoveClass" }, render: function (e) { //Save the view and model on the element this.$el.data({ model: this.model, view: this }); this.$el.html(this.editTemplate({ edit: this.edit, model: this.model.toJSON() })); if (this.isNew) { this.$el.addClass("new"); } return this; }, /** * Updates the model. * If this is called from the user switching between latitude and longitude boxes, * we check to see if the input was valid and display any errors if we need to. * * @param e The event */ updateModel: function (e) { if (!e) return false; e.preventDefault(); //Get the attribute and value var element = $(e.target), value = element.val(), attribute = element.attr("data-attribute"); //Get the attribute that was changed if (!attribute) return false; var emlModel = this.model.getParentEML(); if(emlModel){ value = emlModel.cleanXMLText(value); } //Are the NW and SE points the same? i.e. is this a single point and not a box? var isSinglePoint = (this.model.get("north") != null && this.model.get("north") == this.model.get("south")) && (this.model.get("west") != null && this.model.get("west") == this.model.get("east")), hasEmptyInputs = this.$("[data-attribute='north']").val() == "" || this.$("[data-attribute='south']").val() == "" || this.$("[data-attribute='west']").val() == "" || this.$("[data-attribute='east']").val() == ""; //Update the model if (value == "") this.model.set(attribute, null); else this.model.set(attribute, value); //If the NW and SE points are the same point... if (isSinglePoint && hasEmptyInputs) { /* If the user updates one of the empty number inputs, then we can assume they do not * want a single point and are attempting to enter a second point. So we should empty the * value from the model for the corresponding coordinate * For example, if the UI shows a lat,long pair of NW: [10] [30] SE: [ ] [ ] then the model * values would be N: 10, W: 30, S: 10, E: 30 * if the user updates that to: NW: [10] [30] SE: [5] [ ] * then we want to remove the "east" value of "30", so the model would be: N: 10, W: 30, S: 5, E: null */ if (attribute == "north" && this.$("[data-attribute='west']").val() == "") this.model.set("west", null); else if (attribute == "south" && this.$("[data-attribute='east']").val() == "") this.model.set("east", null); else if (attribute == "east" && this.$("[data-attribute='south']").val() == "") this.model.set("south", null); else if (attribute == "west" && this.$("[data-attribute='north']").val() == "") this.model.set("north", null); /* * If the user removes one of the latitude or longitude values, reset the opposite point */ else if (((attribute == "north" && this.model.get("north") == null) || (attribute == "west" && this.model.get("west") == null)) && (this.$("[data-attribute='south']").val() == "" && this.$("[data-attribute='east']").val() == "")) { this.model.set("south", null); this.model.set("east", null); } else if (((attribute == "south" && this.model.get("south") == null) || (attribute == "east" && this.model.get("east") == null)) && (this.$("[data-attribute='north']").val() == "" && this.$("[data-attribute='west']").val() == "")) { this.model.set("north", null); this.model.set("west", null); } /* Otherwise, if the non-empty number inputs are updated, * we simply update the corresponding value in the other point */ else if (attribute == "north" && this.model.get("north") != null) this.model.set("south", value); else if (attribute == "south" && this.model.get("south") != null) this.model.set("north", value); else if (attribute == "west" && this.model.get("west") != null) this.model.set("east", value); else if (attribute == "east" && this.model.get("east") != null) this.model.set("west", value); } else { //Find out if we are missing a complete NW or SE point var isMissingNWPoint = (this.model.get("north") == null && this.model.get("west") == null), isMissingSEPoint = (this.model.get("south") == null && this.model.get("east") == null); // If there is a full NW point but no SE point, we can assume the user wants a single point and // so we will copy the NW values to the SE if (this.model.get("north") != null && this.model.get("west") != null && isMissingSEPoint) { this.model.set("south", this.model.get("north")); this.model.set("east", this.model.get("west")); } // Same for when there is a SE point but no NW point else if (this.model.get("south") != null && this.model.get("east") != null && isMissingNWPoint) { this.model.set("north", this.model.get("south")); this.model.set("west", this.model.get("east")); } } // Validate the coordinate boxes //this.validateCoordinates(e); //If this model is part of the EML inside the root data package, mark the package as changed if (this.model.get("parentModel")) { if (this.model.get("parentModel").type == "EML" && _.contains(MetacatUI.rootDataPackage.models, this.model.get("parentModel"))) { MetacatUI.rootDataPackage.packageModel.set("changed", true); } } this.validate(); }, /** * Checks to see if any error messages need to be removed. If not, then it performs validation * across the row and displays any errors. This id called when the user clicks out of an edit box * on to the page. * * @param e The event * @param options */ validate: function (e, options) { //Query for the EMlGeoCoverageView element that the user is actively interacting with var activeGeoCovEl = $(document.activeElement).parents(".eml-geocoverage"); //If the user is not actively in this view, then exit if (activeGeoCovEl.length && activeGeoCovEl[0] == this.el) return; //If the model is valid, then remove error styling and exit if( this.model.isValid() ) { this.$(".error").removeClass("error"); this.$el.removeClass("error"); this.$(".notification").empty(); this.model.trigger("valid"); return; } else{ this.showValidation(); } }, /* * Resets the error messaging and displays the current error messages for this model * This function is used by the EML211EditorView during the package validation process */ showValidation: function(){ this.$(".error").removeClass("error"); this.$el.removeClass("error"); this.$(".notification").empty(); var errorMessages = ""; for( field in this.model.validationError ){ this.$("[data-attribute='" + field + "']").addClass("error"); errorMessages += this.model.validationError[field] + " "; } this.$(".notification").text(errorMessages).addClass("error"); }, /** * Highlight what will be removed when the remove icon is hovered over * */ toggleRemoveClass: function () { this.$el.toggleClass("remove-preview"); }, /** * Unmarks this view as new * */ notNew: function () { this.$el.removeClass("new"); this.isNew = false; } }); return EMLGeoCoverageView; });