From 938d0e9995a84d10b4bad24332c856e0a509778f Mon Sep 17 00:00:00 2001 From: Robyn Thiessen-Bock Date: Wed, 1 Nov 2023 16:12:24 -0400 Subject: [PATCH] Standardize spacing add docs to EMLGeoCoverageView Issue #2159 --- src/js/views/metadata/EMLGeoCoverageView.js | 572 +++++++++++--------- 1 file changed, 321 insertions(+), 251 deletions(-) diff --git a/src/js/views/metadata/EMLGeoCoverageView.js b/src/js/views/metadata/EMLGeoCoverageView.js index 6b404231a..ba5245566 100644 --- a/src/js/views/metadata/EMLGeoCoverageView.js +++ b/src/js/views/metadata/EMLGeoCoverageView.js @@ -1,253 +1,323 @@ /* 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 +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", + + /** + * The HTML tag name for this view element + * @type {string} + * @default "div" + */ + tagName: "div", + + /** + * The class names to add to this view's HTML element + */ + className: "row-fluid eml-geocoverage", + + /** + * Attributes for the HTML element. + */ + attributes: { + "data-category": "geoCoverage", + }, + + /** + * Events applied to this view's HTML elements by Backbone. + */ + events: { + change: "updateModel", // <- TODO: does this work? + "mouseover .remove": "toggleRemoveClass", + "mouseout .remove": "toggleRemoveClass", + }, + + /** + * The template to use for this view in edit mode + */ + editTemplate: _.template(EMLGeoCoverageTemplate), + + /** + * Initializes the EMLGeoCoverageView + * @param {Object} options - A literal object with options to pass to the + * view + * @param {EMLGeoCoverage} options.model - The EMLGeoCoverage model to + * render + * @param {boolean} options.edit - Flag to toggle whether this view is in + * edit mode + * @param {boolean} options.isNew - Flag to toggle whether this view is + * new + */ + 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; + }, + + /** + * Renders the EMLGeoCoverageView + * @returns {EMLGeoCoverageView} Returns the view + */ + render: function () { + try { + // 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; + } catch (e) { + console.log("Error rendering EMLGeoCoverageView: ", e); + 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 {Event} e - The event that triggered this function + */ + updateModel: function (e) { + console.log("updateModel", 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); + } else if (attribute == "north" && this.model.get("north") != null) + /* Otherwise, if the non-empty number inputs are updated, we simply + * update the corresponding value in the other point */ - 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; - }); + 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"); + }, + + /** + * Unmark this view as news + */ + notNew: function () { + this.$el.removeClass("new"); + this.isNew = false; + }, + } + ); + + return EMLGeoCoverageView; +});