Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inputs for missing value codes and explanations in the attribute editor #2166

Merged
merged 14 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 28 additions & 3 deletions src/css/metacatui-common.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ a:hover{
pointer-events: none;
opacity: .8;
}
.reset-btn-styles {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
}
.footnote{
font-size: .7em;
}
Expand Down Expand Up @@ -8674,6 +8683,24 @@ textarea.medium{
.eml-attribute input {
height: auto;
}
.eml-missing-value-rows {
display: grid;
gap: 0.7rem;
grid-auto-flow: row;
margin-bottom: 3rem;
}
.eml-missing-value {
display: grid;
grid-template-columns: 1fr 4fr 1.5rem;
gap: 0.5rem;
}
.eml-missing-value input {
margin-bottom: 0;
width: auto;
}
.eml-missing-value button {
font-size: 1.1rem;
}
.eml-measurement-scale .options{
box-sizing: border-box;
padding-top: 10px;
Expand Down Expand Up @@ -9036,6 +9063,4 @@ body > #extension-is-installed{
}
.citation.header button.show-authors{
margin-left: 5px;
}


}
85 changes: 85 additions & 0 deletions src/js/collections/metadata/eml/EMLMissingValueCodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"use strict";

define(["backbone", "models/metadata/eml211/EMLMissingValueCode"], function (
Backbone,
EMLMissingValueCode
) {
/**
* @class EMLMissingValueCodes
* @classdesc A collection of EMLMissingValueCodes.
* @classcategory Collections/Metadata/EML
* @since x.x.x
*/
var EMLMissingValueCodes = Backbone.Collection.extend(
/** @lends EMLMissingValueCodes.prototype */
{
/**
* The reference to the model class that this collection is made of.
* @type {Backbone.Model}
*/
model: EMLMissingValueCode,

/**
* Parse the incoming XML nodes
* @param {jQuery|Element} objectDOM - The XML DOM element that represents
*/
parse: function (objectDOM) {
const collection = this;

if (!objectDOM) return;
const $objectDOM = $(objectDOM);

// Get all of the missingValueCode nodes
const nodeName = "missingvaluecode";
const nodes = $objectDOM.filter(nodeName);
// Loop through each missingValueCode node
const opts = { parse: true };
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
// Create a new missingValueCode model & add it to the collection
const attrs = { objectDOM: node };
const missingValueCode = new EMLMissingValueCode(attrs, opts);
collection.add(missingValueCode);
}

return collection;
},

/**
* Update the DOM with the current model state for each model in the
* collection, then return the set of updated DOMs.
* @returns {Element[]} An array of updated DOM elements
*/
updateDOM: function () {
const objectDOMs = this.map((model) => model.updateDOM());
return objectDOMs;
},

/**
* Remove any empty models from the collection
*/
removeEmptyModels: function () {
this.remove(this.filter((model) => model.isEmpty()));
},

/**
* Validate the collection of missing value codes. This will remove any
* empty models from the collection.
* @returns {Array} An array of error messages
*/
validate: function () {
const errors = [];
this.forEach((model) => {
if (!model.isValid()) {
errors.push(model.validationError);
}
});
// return errors.length ? errors : null;
// For now, if there is at least one error, just return the first one
return errors.length ? errors[0] : null;
},
}
);

return EMLMissingValueCodes;
});
87 changes: 65 additions & 22 deletions src/js/models/metadata/eml211/EMLAttribute.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
define(["jquery", "underscore", "backbone", "uuid",
"models/metadata/eml211/EMLMeasurementScale", "models/metadata/eml211/EMLAnnotation",
"collections/metadata/eml/EMLMissingValueCodes",
"models/DataONEObject"],
function($, _, Backbone, uuid, EMLMeasurementScale, EMLAnnotation,
function ($, _, Backbone, uuid, EMLMeasurementScale, EMLAnnotation,
EMLMissingValueCodes,
DataONEObject) {

/**
Expand All @@ -25,7 +27,7 @@ define(["jquery", "underscore", "backbone", "uuid",
storageType: [], // Zero or more storage types
typeSystem: [], // Zero or more system types for storage type
measurementScale: null, // An EML{Non}NumericDomain or EMLDateTimeDomain object
missingValueCode: [], // Zero or more {code: value, definition: value} objects
missingValueCodes: new EMLMissingValueCodes(), // An EMLMissingValueCodes collection
accuracy: null, // An EMLAccuracy object
coverage: null, // an EMLCoverage object
methods: [], // Zero or more EMLMethods objects
Expand Down Expand Up @@ -72,14 +74,33 @@ define(["jquery", "underscore", "backbone", "uuid",

/* Initialize an EMLAttribute object */
initialize: function(attributes, options) {

if (!attributes) {
var attributes = {};
}

// If initialized with missingValueCode as an array, convert it to a collection
if (
attributes.missingValueCodes &&
attributes.missingValueCodes instanceof Array
) {
this.missingValueCodes =
new EMLMissingValueCodes(attributes.missingValueCode);
}

this.stopListening(this.get("missingValueCodes"));
this.listenTo(
this.get("missingValueCodes"),
"update",
this.trickleUpChange
)
this.on(
"change:attributeName " +
"change:attributeLabel " +
"change:attributeDefinition " +
"change:storageType " +
"change:measurementScale " +
"change:missingValueCode " +
"change:missingValueCodes " +
"change:accuracy " +
"change:coverage " +
"change:methods " +
Expand Down Expand Up @@ -130,7 +151,6 @@ define(["jquery", "underscore", "backbone", "uuid",
attributes.typeSystem.push(type || null);
});


var measurementScale = $objectDOM.find("measurementscale")[0];
if ( measurementScale ) {
attributes.measurementScale =
Expand All @@ -151,6 +171,12 @@ define(["jquery", "underscore", "backbone", "uuid",
attributes.annotation.push(annotation);
}, this);

// Add the missingValueCodes as a collection
attributes.missingValueCodes = new EMLMissingValueCodes();
attributes.missingValueCodes.parse(
$objectDOM.children("missingvaluecode")
);

attributes.objectDOM = $objectDOM[0];

return attributes;
Expand Down Expand Up @@ -187,7 +213,6 @@ define(["jquery", "underscore", "backbone", "uuid",
// This is new, create it
} else {
objectDOM = document.createElement(type);

}

// update the id attribute
Expand Down Expand Up @@ -291,7 +316,7 @@ define(["jquery", "underscore", "backbone", "uuid",
}
}
}
//If there is no attirbute definition, then return an empty String
// If there is no attribute definition, then return an empty String
// because it is invalid
else{
return "";
Expand Down Expand Up @@ -390,6 +415,22 @@ define(["jquery", "underscore", "backbone", "uuid",
$(after).after(anno.updateDOM());
}, this);

// Update the missingValueCodes
nodeToInsertAfter = undefined;
var missingValueCodes = this.get("missingValueCodes");
$(objectDOM).children("missingvaluecode").remove();
if (missingValueCodes) {
var missingValueCodeNodes = missingValueCodes.updateDOM();
if (missingValueCodeNodes) {
nodeToInsertAfter = this.getEMLPosition(objectDOM, "missingValueCode");
if (typeof nodeToInsertAfter === "undefined") {
$(objectDOM).append(missingValueCodeNodes);
} else {
$(nodeToInsertAfter).after(missingValueCodeNodes);
}
}
}

return objectDOM;
},

Expand Down Expand Up @@ -440,25 +481,27 @@ define(["jquery", "underscore", "backbone", "uuid",
errors.measurementScale = "Choose a measurement scale category for this attribute.";
}
else{
var measurementScaleIsValid = measurementScaleModel.isValid();

// If there is a measurement scale model and it is valid and there are no other
// errors, then trigger this model as valid and exit.
if( measurementScaleIsValid && !Object.keys(errors).length ){

this.trigger("valid", this);
return;

}
else if( !measurementScaleIsValid ){
if( !measurementScaleModel.isValid() ){
errors.measurementScale = "More information is needed.";
}
}

//If there is at least one error, then return the errors object
if(Object.keys(errors).length)
return errors;
}

// Validate the missing value codes
var missingValueCodesErrors = this.get("missingValueCodes")?.validate();
if (missingValueCodesErrors) {
// Just display the first error message
errors.missingValueCodes = Object.values(missingValueCodesErrors)[0]
}

// If there is a measurement scale model and it is valid and there are no other
// errors, then trigger this model as valid and exit.
if (!Object.keys(errors).length) {
this.trigger("valid", this);
return;
} else {
//If there is at least one error, then return the errors object
return errors;
}
},

/*
Expand Down
Loading