diff --git a/codemeta_generation.js b/codemeta_generation.js index 9cd3851..eaf7ccd 100644 --- a/codemeta_generation.js +++ b/codemeta_generation.js @@ -1,81 +1,142 @@ /** * Copyright (C) 2019 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ "use strict"; function emptyToUndefined(v) { if (v == null || v == "") return undefined; else return v; } function getIfSet(query) { return emptyToUndefined(document.querySelector(query).value); } +function setIfDefined(query, value) { + if (value !== undefined) { + document.querySelector(query).value = value; + } +} + // Names of codemeta properties with a matching HTML field name const directCodemetaFields = [ 'codeRepository', 'contIntegration', 'dateCreated', 'datePublished', 'dateModified', 'issueTracker', 'name', 'version', ]; +// Names of codemeta properties with a matching HTML field name, +// in a Person object +const directPersonCodemetaFields = [ + 'givenName', + 'familyName', + 'email', +]; + function generatePerson(idPrefix) { - return { + var doc = { "@type": "Person", - "givenName": getIfSet(`#${idPrefix}_givenName`), - "familyName": getIfSet(`#${idPrefix}_familyName`), - "email": getIfSet(`#${idPrefix}_email`), "@id": getIfSet(`#${idPrefix}_id`), } + directPersonCodemetaFields.forEach(function (item, index) { + doc[item] = getIfSet(`#${idPrefix}_${item}`); + }); + + return doc; } function generatePersons(prefix) { var persons = []; var nbPersons = getNbPersons(prefix); for (let personId = 1; personId <= nbPersons; personId++) { persons.push(generatePerson(`${prefix}_${personId}`)); } return persons; } function generateCodemeta() { var inputForm = document.querySelector('#inputForm'); - var codemetaText; + var codemetaText, errorHTML; + if (inputForm.checkValidity()) { var doc = { "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "license": "https://spdx.org/licenses/" + getIfSet('#license'), }; + // Generate most fields directCodemetaFields.forEach(function (item, index) { doc[item] = getIfSet('#' + item) }); + // Generate dynamic fields doc = Object.assign(doc, { "author": generatePersons('author'), "contributor": generatePersons('contributor'), }); codemetaText = JSON.stringify(doc, null, 4); + errorHTML = ""; } else { - codemetaText = "invalid input (see error above)"; + codemetaText = ""; + errorHTML = "invalid input (see error above)"; inputForm.reportValidity(); } - document.querySelector('#codemetaText').textContent = codemetaText; + document.querySelector('#codemetaText').innerText = codemetaText; + setError(errorHTML); +} + +function importPersons(prefix, legend, docs) { + if (docs === 'undefined') { + return; + } + + docs.forEach(function (doc, index) { + var personId = addPerson(prefix, legend); + + setIfDefined(`#${personId}_id`, doc['@id']); + directPersonCodemetaFields.forEach(function (item, index) { + setIfDefined(`#${prefix}_${personId}_${item}`, doc[item]); + }); + }) +} + +function importCodemeta() { + var inputForm = document.querySelector('#inputForm'); + var codemetaText = document.querySelector('#codemetaText').innerText; + var doc; + + try { + doc = JSON.parse(codemetaText); + } + catch (e) { + setError(`Could not read codemeta document because it is not valid JSON (${e})`); + return; + } + resetForm(); + + directCodemetaFields.forEach(function (item, index) { + setIfDefined('#' + item, doc[item]); + }); + + importPersons('author', 'Author', doc['author']) + importPersons('contributor', 'Contributor', doc['contributor']) + + setError(""); } diff --git a/dynamic_form.js b/dynamic_form.js index ef1c5d4..5d40a49 100644 --- a/dynamic_form.js +++ b/dynamic_form.js @@ -1,110 +1,112 @@ /** * Copyright (C) 2019 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ "use strict"; function createPersonFieldset(personPrefix, legend) { // Creates a fieldset containing inputs for informations about a person var fieldset = document.createElement("fieldset") fieldset.classList.add("person"); fieldset.id = personPrefix; fieldset.innerHTML = ` ${legend}

`; return fieldset; } function addPersonWithId(container, prefix, legend, id) { var fieldset = createPersonFieldset(`${prefix}_${id}`, `${legend} #${id}`); container.appendChild(fieldset); } function addPerson(prefix, legend) { var container = document.querySelector(`#${prefix}_container`); var personId = getNbPersons(prefix) + 1; addPersonWithId(container, prefix, legend, personId); setNbPersons(prefix, personId); + + return personId; } function removePerson(prefix) { var personId = getNbPersons(prefix); document.querySelector(`#${prefix}_${personId}`).remove(); setNbPersons(prefix, personId-1); } // Initialize a group of persons (authors, contributors) on page load. // Useful if the page is reloaded. function initPersons(prefix, legend) { var nbPersons = getNbPersons(prefix); var personContainer = document.querySelector(`#${prefix}_container`) for (let personId = 1; personId <= nbPersons; personId++) { addPersonWithId(personContainer, prefix, legend, personId); } } function removePersons(prefix) { var nbPersons = getNbPersons(prefix); var personContainer = document.querySelector(`#${prefix}_container`) for (let personId = 1; personId <= nbPersons; personId++) { removePerson(prefix) } } function resetForm() { removePersons('author'); removePersons('contributor'); // Reset the form after deleting elements, so nbPersons doesn't get // reset before it's read. document.querySelector('#inputForm').reset(); } function initCallbacks() { document.querySelector('#generateCodemeta') .addEventListener('click', generateCodemeta); document.querySelector('#resetForm') .addEventListener('click', resetForm); document.querySelector('#importCodemeta') .addEventListener('click', importCodemeta); document.querySelector('#inputForm') .addEventListener('change', generateCodemeta); initPersons('author', 'Author'); initPersons('contributor', 'Contributor'); } diff --git a/index.html b/index.html index 810272c..8b9d1ad 100644 --- a/index.html +++ b/index.html @@ -1,135 +1,138 @@ CodeMeta generator

CodeMeta generator

Most fields are optional. Mandatory fields will be highlighted when generating Codemeta.

The software itself

Development community / tools

Current version of the software

Authors

Order of authors does not matter.

Contributors

Order of contributors does not matter.

+
+

+


 
     
 
 
diff --git a/style.css b/style.css
index 01647cf..82ef4cb 100644
--- a/style.css
+++ b/style.css
@@ -1,23 +1,29 @@
 /**
  * Copyright (C) 2019  The Software Heritage developers
  * See the AUTHORS file at the top-level directory of this distribution
  * License: GNU Affero General Public License version 3, or any later version
  * See top-level LICENSE file for more information
  */
 
 .person {
     display: inline-block;
 }
 
 #fieldsetSoftwareItself, #fieldsetDevelopmentCommunity, #fieldsetCurrentVersion {
     display: inline-block;
 }
 
 input[type=URL] {
     /* URLs are longer than the other fields */
     min-width: 20em;
 }
 
 #codemetaText {
     width: 100%;
+    min-height: 10em;
+    border: 1px solid black;
+}
+
+#errorMessage {
+    color: red;
 }
diff --git a/utils.js b/utils.js
index 2d56bc9..7f413b4 100644
--- a/utils.js
+++ b/utils.js
@@ -1,18 +1,22 @@
 /**
  * Copyright (C) 2019  The Software Heritage developers
  * See the AUTHORS file at the top-level directory of this distribution
  * License: GNU Affero General Public License version 3, or any later version
  * See top-level LICENSE file for more information
  */
 
 "use strict";
 
 function getNbPersons(prefix) {
     var nbField = document.querySelector(`#${prefix}_nb`);
     return parseInt(nbField.value, 10);
 }
 
 function setNbPersons(prefix, nb) {
     var nbField = document.querySelector(`#${prefix}_nb`);
     nbField.value = nb;
 }
+
+function setError(msg) {
+    document.querySelector("#errorMessage").innerHTML = msg;
+}