From f8ab572be1492d5ccaf99a7d6d464cab7929cb4a Mon Sep 17 00:00:00 2001 From: Robyn Thiessen-Bock Date: Mon, 31 Jul 2023 18:24:03 -0400 Subject: [PATCH] Move/consolidate DOI methods to AppModel - CitationModel, DataONEObject, SolrResult, and MetadataView previously all used very similar DOI methods - These methods have been moved to the appModel, the other views/models call those - Also added getCanonicalDOIIRI to DataONEObject Relates to #1380 --- src/js/models/AppModel.js | 70 ++++++++++++++++++++++++++++++++++ src/js/models/CitationModel.js | 22 ++--------- src/js/models/DataONEObject.js | 57 ++++++++++----------------- src/js/models/SolrResult.js | 41 ++------------------ src/js/views/MetadataView.js | 10 +---- 5 files changed, 99 insertions(+), 101 deletions(-) diff --git a/src/js/models/AppModel.js b/src/js/models/AppModel.js index 377f4d100..c8d6c914e 100644 --- a/src/js/models/AppModel.js +++ b/src/js/models/AppModel.js @@ -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; }); diff --git a/src/js/models/CitationModel.js b/src/js/models/CitationModel.js index 602083710..817f44cc4 100644 --- a/src/js/models/CitationModel.js +++ b/src/js/models/CitationModel.js @@ -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); }, /** @@ -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); }, /** @@ -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); }, /** diff --git a/src/js/models/DataONEObject.js b/src/js/models/DataONEObject.js index 76d99c2e4..8d8c3cd23 100644 --- a/src/js/models/DataONEObject.js +++ b/src/js/models/DataONEObject.js @@ -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 @@ -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 diff --git a/src/js/models/SolrResult.js b/src/js/models/SolrResult.js index f6e179d50..2e51cd8fa 100644 --- a/src/js/models/SolrResult.js +++ b/src/js/models/SolrResult.js @@ -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")); }, /* diff --git a/src/js/views/MetadataView.js b/src/js/views/MetadataView.js index a7dffeadc..94c9f9343 100644 --- a/src/js/views/MetadataView.js +++ b/src/js/views/MetadataView.js @@ -2905,15 +2905,9 @@ define(['jquery', * Note: Really could be generalized to more identifier schemes. */ getCanonicalDOIIRI: function (identifier) { - var pattern = /(10\.\d{4,9}\/[-\._;()\/:A-Z0-9]+)$/, - match = identifier.match(pattern); - - if (match === null || match.length !== 2 || match[1].length <= 0) { - return null; - } - - return "https://doi.org/" + match[1]; + return MetacatUI.appModel.DOItoURL(identifier) || null; }, + /** * Insert citation information as meta tags into the head of the page *