Source: views/metadata/EMLGeoCoverageView.js

/* 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
        */
        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;
    });