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 all 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;
});
70 changes: 70 additions & 0 deletions src/js/models/AppModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2398,6 +2398,76 @@ define(['jquery', 'underscore', 'backbone'],
this.set("description", this.defaults.description);
},

/**
* Remove all DOI prefixes from a DOI string, including https, http, doi.org,
* dx.doi.org, and doi:.
* @param {string} str - The DOI string to remove prefixes from.
* @returns {string} - The DOI string without any prefixes.
* @since x.x.x
*/
removeAllDOIPrefixes: function (str) {
if (!str) return "";
// Remove https and http prefixes
str = str.replace(/^(https?:\/\/)?/, "");
// Remove domain prefixes, like doi.org and dx.doi.org
str = str.replace(/^(doi\.org\/|dx\.doi\.org\/)/, "");
// Remove doi: prefix
str = str.replace(/^doi:/, "");
return str;
},

/**
* Check if a string is a valid DOI.
* @param {string} doi - The string to check.
* @returns {boolean} - True if the string is a valid DOI, false otherwise.
* @since x.x.x
*/
isDOI: function (str) {
try {
if (!str) return false;
str = this.removeAllDOIPrefixes(str);
const doiRegex = /^10\.[0-9]{4,}(?:[.][0-9]+)*\/[^\s"<>]+$/;
return doiRegex.test(str);
} catch (e) {
console.error("Error checking if string is a DOI", e);
return false;
}
},

/**
* Get the URL for the online location of the object being cited when it
* has a DOI. If the DOI is not passed to the function, or if the string
* is not a DOI, then an empty string is returned.
* @param {string} str - The DOI string, handles both DOI and DOI URL,
* with or without prefixes
* @returns {string} - The DOI URL
* @since 2.23.0
*/
DOItoURL: function (str) {
if (!str) return "";
str = this.removeAllDOIPrefixes(str);
if (!this.isDOI(str)) return "";
return "https://doi.org/" + str;
},

/**
* Get the DOI from a DOI URL. The URL can be http or https, can include the
* "doi:" prefix or not, and can use "dx.doi.org" or "doi.org" as the
* domain. If a string is not passed to the function, or if the string is
* not for a DOI URL, then an empty string is returned.
* @param {string} url - The DOI URL
* @returns {string} - The DOI string, including the "doi:" prefix
* @since x.x.x
*/
URLtoDOI: function (url) {
if (!url) return "";
const doiURLRegex =
/https?:\/\/(dx\.)?doi\.org\/(doi:)?(10\.[0-9]{4,}(?:[.][0-9]+)*\/[^\s"<>]+)/;
const doiURLMatch = url.match(doiURLRegex);
if (doiURLMatch) return "doi:" + doiURLMatch[3];
return "";
},

});
return AppModel;
});
22 changes: 3 additions & 19 deletions src/js/models/CitationModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -977,15 +977,7 @@ define(["jquery", "underscore", "backbone", "collections/Citations"], function (
* @since 2.23.0
*/
isDOI: function (str) {
try {
if (!str) return false;
str = this.removeAllDOIPrefixes(str);
const doiRegex = /^10\.[0-9]{4,}(?:[.][0-9]+)*\/[^\s"<>]+$/;
return doiRegex.test(str);
} catch (e) {
console.error("Error checking if string is a DOI", e);
return false;
}
return MetacatUI.appModel.isDOI(str);
},

/**
Expand All @@ -999,10 +991,7 @@ define(["jquery", "underscore", "backbone", "collections/Citations"], function (
* @since 2.23.0
*/
DOItoURL: function (str) {
if (!str) return "";
str = this.removeAllDOIPrefixes(str);
if (!this.isDOI(str)) return "";
return "https://doi.org/" + str;
return MetacatUI.appModel.DOItoURL(str);
},

/**
Expand All @@ -1015,12 +1004,7 @@ define(["jquery", "underscore", "backbone", "collections/Citations"], function (
* @since 2.23.0
*/
URLtoDOI: function (url) {
if (!url) return "";
const doiURLRegex =
/https?:\/\/(dx\.)?doi\.org\/(doi:)?(10\.[0-9]{4,}(?:[.][0-9]+)*\/[^\s"<>]+)/;
const doiURLMatch = url.match(doiURLRegex);
if (doiURLMatch) return "doi:" + doiURLMatch[3];
return "";
return MetacatUI.appModel.URLtoDOI(url);
},

/**
Expand Down
57 changes: 20 additions & 37 deletions src/js/models/DataONEObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,22 @@ define(['jquery', 'underscore', 'backbone', 'uuid', 'he', 'collections/AccessPol
createViewURL: function(){
return MetacatUI.root + "/view/" + encodeURIComponent((this.get("seriesId") || this.get("id")));
},

/**
* Check if the seriesID or PID matches a DOI regex, and if so, return
* a canonical IRI for the DOI.
* @return {string|null} - The canonical IRI for the DOI, or null if
* neither the seriesId nor the PID match a DOI regex.
* @since x.x.x
*/
getCanonicalDOIIRI: function () {
const id = this.get("id");
const seriesId = this.get("seriesId");
let DOI = null;
if (this.isDOI(seriesId)) DOI = seriesId;
else if (this.isDOI(id)) DOI = id;
return MetacatUI.appModel.DOItoURL(DOI);
},

/**
* Converts the identifier string to a string safe to use in an XML id attribute
Expand Down Expand Up @@ -2132,43 +2148,10 @@ define(['jquery', 'underscore', 'backbone', 'uuid', 'he', 'collections/AccessPol
* @returns {boolean} True if it is a DOI
*/
isDOI: function(customString) {
var DOI_PREFIXES = ["doi:10.", "http://dx.doi.org/10.", "http://doi.org/10.", "http://doi.org/doi:10.",
"https://dx.doi.org/10.", "https://doi.org/10.", "https://doi.org/doi:10."],
DOI_REGEX = new RegExp(/^10.\d{4,9}\/[-._;()/:A-Z0-9]+$/i);;

//If a custom string is given, then check that instead of the seriesId and id from the model
if( typeof customString == "string" ){
for (var i=0; i < DOI_PREFIXES.length; i++) {
if (customString.toLowerCase().indexOf(DOI_PREFIXES[i].toLowerCase()) == 0 )
return true;
}

//If there is no DOI prefix, check for a DOI without the prefix using a regular expression
if( DOI_REGEX.test(customString) ){
return true;
}

}
else{
var seriesId = this.get("seriesId"),
pid = this.get("id");

for (var i=0; i < DOI_PREFIXES.length; i++) {
if (seriesId && seriesId.toLowerCase().indexOf(DOI_PREFIXES[i].toLowerCase()) == 0 )
return true;
else if (pid && pid.toLowerCase().indexOf(DOI_PREFIXES[i].toLowerCase()) == 0 )
return true;
}

//If there is no DOI prefix, check for a DOI without the prefix using a regular expression
if( DOI_REGEX.test(seriesId) || DOI_REGEX.test(pid) ){
return true;
}

}

return false;
},
return isDOI(customString) ||
isDOI(this.get("id")) ||
isDOI(this.get("seriesId"));
},

/**
* Creates an array of objects that represent Member Nodes that could possibly be this
Expand Down
41 changes: 4 additions & 37 deletions src/js/models/SolrResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,43 +208,10 @@ define(['jquery', 'underscore', 'backbone'],
* @param {string} customString - Optional. An identifier string to check instead of the id and seriesId attributes on the model
* @returns {boolean} True if it is a DOI
*/
isDOI: function(customString) {
var DOI_PREFIXES = ["doi:10.", "http://dx.doi.org/10.", "http://doi.org/10.", "http://doi.org/doi:10.",
"https://dx.doi.org/10.", "https://doi.org/10.", "https://doi.org/doi:10."],
DOI_REGEX = new RegExp(/^10.\d{4,9}\/[-._;()/:A-Z0-9]+$/i);;

//If a custom string is given, then check that instead of the seriesId and id from the model
if( typeof customString == "string" ){
for (var i=0; i < DOI_PREFIXES.length; i++) {
if (customString.toLowerCase().indexOf(DOI_PREFIXES[i].toLowerCase()) == 0 )
return true;
}

//If there is no DOI prefix, check for a DOI without the prefix using a regular expression
if( DOI_REGEX.test(customString) ){
return true;
}

}
else{
var seriesId = this.get("seriesId"),
pid = this.get("id");

for (var i=0; i < DOI_PREFIXES.length; i++) {
if (seriesId && seriesId.toLowerCase().indexOf(DOI_PREFIXES[i].toLowerCase()) == 0 )
return true;
else if (pid && pid.toLowerCase().indexOf(DOI_PREFIXES[i].toLowerCase()) == 0 )
return true;
}

//If there is no DOI prefix, check for a DOI without the prefix using a regular expression
if( DOI_REGEX.test(seriesId) || DOI_REGEX.test(pid) ){
return true;
}

}

return false;
isDOI: function (customString) {
return MetacatUI.appModel.isDOI(customString) ||
MetacatUI.appModel.isDOI(this.get("id")) ||
MetacatUI.appModel.isDOI(this.get("seriesId"));
},

/*
Expand Down
Loading