diff --git a/examples/config/CVocConf.schema.json b/examples/config/CVocConf.schema.json
index a3dcfbe..f0a86dd 100644
--- a/examples/config/CVocConf.schema.json
+++ b/examples/config/CVocConf.schema.json
@@ -212,12 +212,22 @@
"js-url":
{
"$id": "#/fieldconfig/properties/js-url",
- "type": "string",
- "title": "The Script URL",
- "description": "The URL for the JavaScript that should be included in the page to support the connection of this field to the specified service",
+ "oneOf":[
+ {
+ "type": "string",
+ "title": "The Script URL",
+ "description": "The URL for the JavaScript that should be included in the page to support the connection of this field to the specified service"
+ },
+ {
+ "type": "array",
+ "title": "Script URLs",
+ "description": "The URLs for all the JavaScripts that should be included in the page to support the connection of this field to the specified service"
+ }
+ ],
"examples":
[
- "https://gdcc.github.io/dataverse-external-vocab-support/scripts/skosmos.js"
+ "https://gdcc.github.io/dataverse-external-vocab-support/scripts/skosmos.js",
+ ["https://gdcc.github.io/dataverse-external-vocab-support/scripts/fundreg.js","https://gdcc.github.io/dataverse-external-vocab-support/scripts/cvocutils.js"]
]
},
diff --git a/examples/config/grantNumberAgencyFundreg.json b/examples/config/grantNumberAgencyFundreg.json
new file mode 100644
index 0000000..2753171
--- /dev/null
+++ b/examples/config/grantNumberAgencyFundreg.json
@@ -0,0 +1,36 @@
+[
+ {
+ "field-name": "grantNumberAgency",
+ "term-uri-field": "grantNumberAgency",
+ "js-url": ["/cvoc/js/fundreg.js","/cvoc/js/cvocutils.js"],
+ "protocol": "fundreg",
+ "retrieval-uri": "https://data.crossref.org/fundingdata/funder/{0}",
+ "allow-free-text": true,
+ "prefix": "http://dx.doi.org/10.13039/",
+ "managed-fields": {},
+ "languages":"",
+ "vocabs": {
+ "funders": {
+ "uriSpace": "http://dx.doi.org/10.13039/"
+ }
+ },
+ "retrieval-filtering": {
+ "@context": {
+ "termName": "https://schema.org/name",
+ "scheme": "http://www.w3.org/2004/02/skos/core#inScheme",
+ "lang": "@language",
+ "content": "@value"
+ },
+ "scheme": {
+ "pattern": "http://data.crossref.org/fundingdata/vocabulary"
+ },
+ "termName": {
+ "pattern": "{0}",
+ "params": ["/altLabel/Label=*/literalForm"]
+ },
+ "@type": {
+ "pattern": "https://schema.org/Organization"
+ }
+ }
+ }
+]
\ No newline at end of file
diff --git a/examples/config/rorAuthAffiliation.json b/examples/config/rorAuthAffiliation.json
new file mode 100644
index 0000000..7bade9b
--- /dev/null
+++ b/examples/config/rorAuthAffiliation.json
@@ -0,0 +1,36 @@
+[
+ {
+ "field-name": "authorAffiliation",
+ "term-uri-field": "authorAffiliation",
+ "js-url": ["/cvoc/js/ror.js","/cvoc/js/cvocutils.js"],
+ "protocol": "ror",
+ "retrieval-uri": "https://api.ror.org/organizations/{0}",
+ "allow-free-text": true,
+ "prefix": "https://ror.org/",
+ "managed-fields": {},
+ "languages":"",
+ "vocabs": {
+ "rors": {
+ "uriSpace": "https://ror.org/"
+ }
+ },
+ "retrieval-filtering": {
+ "@context": {
+ "termName": "https://schema.org/name",
+ "scheme": "http://www.w3.org/2004/02/skos/core#inScheme",
+ "lang": "@language",
+ "content": "@value"
+ },
+ "scheme": {
+ "pattern": "http://www.grid.ac/ontology/"
+ },
+ "termName": {
+ "pattern": "{0}",
+ "params": ["/name"]
+ },
+ "@type": {
+ "pattern": "https://schema.org/Organization"
+ }
+ }
+ }
+]
\ No newline at end of file
diff --git a/scripts/cvocutils.js b/scripts/cvocutils.js
new file mode 100644
index 0000000..3da79b9
--- /dev/null
+++ b/scripts/cvocutils.js
@@ -0,0 +1,60 @@
+//Common Methods - used in more than one script
+
+// Put the text in a result that matches the term in a span with class
+// select2-rendered__match that can be styled (e.g. bold)
+function markMatch2(text, term) {
+ // Find where the match is
+ var match = text.toUpperCase().indexOf(term.toUpperCase());
+ var $result = $('');
+ // If there is no match, move on
+ if (match < 0) {
+ return $result.text(text);
+ }
+
+ // Put in whatever text is before the match
+ $result.text(text.substring(0, match));
+
+ // Mark the match
+ var $match = $('');
+ $match.text(text.substring(match, match + term.length));
+
+ // Append the matching text
+ $result.append($match);
+
+ // Put in whatever is after the match
+ $result.append(text.substring(match + term.length));
+
+ return $result;
+}
+
+function storeValue(prefix, id, value) {
+ try {
+ if(localStorage.getItem(prefix + id)==null) {
+ // Store the most recent 1000 values across all scripts
+ //ToDo: Use IndexedDB to manage storage for each script separately and avoid impacting other tools using localStorage
+ if (localStorage.length > 1000) {
+ localStorage.removeItem(localStorage.key(0));
+ }
+ localStorage.setItem(prefix + id, value);
+ }
+ } catch (e) {
+ console.log("Problem using localStorage: " + e);
+ }
+}
+
+function getValue(prefix, id) {
+ try {
+ let altNames='';
+ let name = localStorage.getItem(prefix + id);
+ if(name !== null) {
+ let pos = name.indexOf('#');
+ if(pos > 0) {
+ altNames=name.substring(pos+1).split(',');
+ name=name.substring(0, pos);
+ }
+ }
+ return {name, altNames};
+ } catch (e) {
+ console.log("Problem getting value from localStorage: " + e);
+ }
+}
\ No newline at end of file
diff --git a/scripts/fundreg.js b/scripts/fundreg.js
new file mode 100644
index 0000000..b64fcc5
--- /dev/null
+++ b/scripts/fundreg.js
@@ -0,0 +1,250 @@
+console.log("fundreg.js..");
+var fundregSelector = "span[data-cvoc-protocol='fundreg']";
+var fundregInputSelector = "input[data-cvoc-protocol='fundreg']";
+var fundregRetrievalUrl = "https://api.crossref.org/funders";
+var fundregPrefix = "fundreg";
+//Max chars that displays well for a child field
+var fundregMaxLength = 30;
+
+$(document).ready(function() {
+ expandFunders();
+ updateFunderInputs();
+});
+
+function expandFunders() {
+ console.log("expandFunders");
+ // Check each selected element
+ $(fundregSelector).each(function() {
+ var funderElement = this;
+ // If it hasn't already been processed
+ if (!$(funderElement).hasClass('expanded')) {
+ // Mark it as processed
+ $(funderElement).addClass('expanded');
+ var id = funderElement.textContent;
+ if (!id.startsWith("http://dx.doi.org/10.13039/")) {
+ $(funderElement).html(getFunderDisplayHtml(id, ['No Crossref Entry'], false));
+ } else {
+ //Remove the URL prefix - "http://dx.doi.org/10.13039/".length = 27
+ id = id.substring(27);
+ //Check for cached entry
+ let value = getValue(fundregPrefix, id);
+ if(value.name !=null) {
+ $(funderElement).html(getFunderDisplayHtml(value.name, value.altNames, false));
+ } else {
+
+ // Try it as an CrossRef Funders entry (could validate that it has the right form or can just let the GET fail)
+ $.ajax({
+ type: "GET",
+ url: fundregRetrievalUrl + "/" + id,
+ dataType: 'json',
+ //Adding this, and using https is supposed to let us call a faster pool of machines
+ //(They will contact us if they see problems - see https://api.crossref.org/swagger-ui/index.html.)
+ data: 'mailto=dataverse-gdcc@googlegroups.com',
+ headers: {
+ 'Accept': 'application/json',
+ },
+ success: function(funder, status) {
+ console.log(funder);
+ // If found, construct the HTML for display
+ var name = funder.message.name;
+ var altNames= funder.message['alt-names'];
+
+ $(funderElement).html(getFunderDisplayHtml(name, altNames, false));
+ //Store values in localStorage to avoid repeating calls to CrossRef
+ storeValue(fundregPrefix, id, name + "#" + altNames);
+ },
+ failure: function(jqXHR, textStatus, errorThrown) {
+ // Generic logging - don't need to do anything if 404 (leave
+ // display as is)
+ if (jqXHR.status != 404) {
+ console.error("The following error occurred: " + textStatus, errorThrown);
+ }
+ }
+ });
+ }
+ }
+ }
+ });
+}
+
+function getFunderDisplayHtml(name, altNames, truncate=true) {
+ if (typeof(altNames) == 'undefined') {
+ altNames = [];
+ }
+ if (truncate && (name.length >= fundregMaxLength)) {
+ // show the first characters of a long name
+ altNames.unshift(name);
+ name=name.substring(0,fundregMaxLength) + "…";
+ }
+ return $('').append(name).attr("title", altNames);
+}
+
+function updateFunderInputs() {
+ // For each input element within funderInputSelector elements
+ $(fundregInputSelector).each(function() {
+ var funderInput = this;
+ if (!funderInput.hasAttribute('data-funder')) {
+ // Random identifier
+ let num = Math.floor(Math.random() * 100000000000);
+ // Hide the actual input and give it a data-funder number so we can
+ // find it
+ $(funderInput).hide();
+ $(funderInput).attr('data-funder', num);
+ // Todo: if not displayed, wait until it is to then create the
+ // select 2 with a non-zero width
+ // Add a select2 element to allow search and provide a list of
+ // choices
+ var selectId = "funderAddSelect_" + num;
+ $(funderInput).after(
+ '