Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/cypress/integration/persons.js b/cypress/integration/persons.js
index d32016b..a296afc 100644
--- a/cypress/integration/persons.js
+++ b/cypress/integration/persons.js
@@ -1,264 +1,424 @@
/**
* Copyright (C) 2020 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
*/
/*
* Tests the author/contributor dynamic fieldsets
*/
"use strict";
describe('Zero author', function() {
it('can be exported', function() {
cy.get('#name').type('My Test Software');
cy.get('#generateCodemeta').click();
cy.get('#errorMessage').should('have.text', '');
cy.get('#codemetaText').then((elem) => JSON.parse(elem.text()))
.should('deep.equal', {
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
});
});
it('can be imported from no list', function() {
cy.get('#codemetaText').then((elem) =>
elem.text(JSON.stringify({
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
}))
);
cy.get('#importCodemeta').click();
cy.get('#author_nb').should('have.value', '0');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('not.exist');
});
it('can be imported from empty list', function() {
cy.get('#codemetaText').then((elem) =>
elem.text(JSON.stringify({
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [],
}))
);
cy.get('#importCodemeta').click();
cy.get('#author_nb').should('have.value', '0');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('not.exist');
});
});
describe('One full author', function() {
it('can be exported', function() {
cy.get('#name').type('My Test Software');
cy.get('#author_nb').should('have.value', '0');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('not.exist');
cy.get('#author_1_givenName').should('not.exist');
cy.get('#author_add').click();
cy.get('#author_nb').should('have.value', '1');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('exist');
cy.get('#author_2').should('not.exist');
cy.get('#author_1_givenName').should('have.value', '');
cy.get('#author_1_familyName').should('have.value', '');
cy.get('#author_1_email').should('have.value', '');
cy.get('#author_1_id').should('have.value', '');
cy.get('#author_1_affiliation').should('have.value', '');
cy.get('#author_1_givenName').type('Jane');
cy.get('#author_1_familyName').type('Doe');
cy.get('#author_1_email').type('jdoe@example.org');
cy.get('#author_1_id').type('http://example.org/~jdoe');
cy.get('#author_1_affiliation').type('http://example.org/');
cy.get('#generateCodemeta').click();
cy.get('#errorMessage').should('have.text', '');
cy.get('#codemetaText').then((elem) => JSON.parse(elem.text()))
.should('deep.equal', {
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [
{
"@type": "Person",
"@id": "http://example.org/~jdoe",
"givenName": "Jane",
"familyName": "Doe",
"email": "jdoe@example.org",
"affiliation": {
"@type": "Organization",
"@id": "http://example.org/",
}
}
],
});
});
it('can be imported', function() {
cy.get('#codemetaText').then((elem) =>
elem.text(JSON.stringify({
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [
{
"@type": "Person",
"@id": "http://example.org/~jdoe",
"givenName": "Jane",
"familyName": "Doe",
"email": "jdoe@example.org",
"affiliation": {
"@type": "Organization",
"@id": "http://example.org/",
}
}
],
}))
);
cy.get('#importCodemeta').click();
cy.get('#author_nb').should('have.value', '1');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('exist');
cy.get('#author_2').should('not.exist');
cy.get('#author_1_givenName').should('have.value', 'Jane');
cy.get('#author_1_familyName').should('have.value', 'Doe');
cy.get('#author_1_email').should('have.value', 'jdoe@example.org');
cy.get('#author_1_id').should('have.value', 'http://example.org/~jdoe');
cy.get('#author_1_affiliation').should('have.value', 'http://example.org/');
});
});
describe('Affiliation id', function() {
it('can be exported', function() {
cy.get('#name').type('My Test Software');
cy.get('#author_add').click();
cy.get('#author_1_givenName').type('Jane');
cy.get('#author_1_affiliation').type('http://example.org/');
cy.get('#generateCodemeta').click();
cy.get('#errorMessage').should('have.text', '');
cy.get('#codemetaText').then((elem) => JSON.parse(elem.text()))
.should('deep.equal', {
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [
{
"@type": "Person",
"givenName": "Jane",
"affiliation": {
"@type": "Organization",
"@id": "http://example.org/",
}
}
],
});
});
it('can be imported', function() {
cy.get('#codemetaText').then((elem) =>
elem.text(JSON.stringify({
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [
{
"@type": "Person",
"@id": "http://example.org/~jdoe",
"givenName": "Jane",
"familyName": "Doe",
"email": "jdoe@example.org",
"affiliation": {
"@type": "Organization",
"@id": "http://example.org/",
}
}
],
}))
);
cy.get('#importCodemeta').click();
cy.get('#author_nb').should('have.value', '1');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('exist');
cy.get('#author_2').should('not.exist');
cy.get('#author_1_affiliation').should('have.value', 'http://example.org/');
});
});
describe('Affiliation name', function() {
it('can be exported', function() {
cy.get('#name').type('My Test Software');
cy.get('#author_add').click();
cy.get('#author_1_givenName').type('Jane');
cy.get('#author_1_affiliation').type('Example Org');
cy.get('#generateCodemeta').click();
cy.get('#errorMessage').should('have.text', '');
cy.get('#codemetaText').then((elem) => JSON.parse(elem.text()))
.should('deep.equal', {
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [
{
"@type": "Person",
"givenName": "Jane",
"affiliation": {
"@type": "Organization",
"name": "Example Org",
}
}
],
});
});
it('can be imported', function() {
cy.get('#codemetaText').then((elem) =>
elem.text(JSON.stringify({
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
"@type": "SoftwareSourceCode",
"name": "My Test Software",
"author": [
{
"@type": "Person",
"@id": "http://example.org/~jdoe",
"givenName": "Jane",
"familyName": "Doe",
"email": "jdoe@example.org",
"affiliation": {
"@type": "Organization",
"name": "Example Org",
}
}
],
}))
);
cy.get('#importCodemeta').click();
cy.get('#author_nb').should('have.value', '1');
cy.get('#author_0').should('not.exist');
cy.get('#author_1').should('exist');
cy.get('#author_2').should('not.exist');
cy.get('#author_1_affiliation').should('have.value', 'Example Org');
});
});
+
+describe('Author order change', function() {
+ it('is a noop with a single author', function() {
+ cy.get('#name').type('My Test Software');
+
+ cy.get('#author_add').click();
+ cy.get('#author_1_givenName').type('Jane');
+ cy.get('#author_1_affiliation').type('Example Org');
+
+ cy.get('#author_1_moveToRight').click()
+
+ cy.get('#author_1_givenName').should('have.value', 'Jane');
+ cy.get('#author_1_affiliation').should('have.value', 'Example Org');
+
+ cy.get('#author_1_moveToLeft').click()
+
+ cy.get('#author_1_givenName').should('have.value', 'Jane');
+ cy.get('#author_1_affiliation').should('have.value', 'Example Org');
+ });
+
+ it('flips two authors', function() {
+ cy.get('#name').type('My Test Software');
+
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_1_givenName').type('Jane');
+ cy.get('#author_1_affiliation').type('Example Org');
+ cy.get('#author_2_givenName').type('John');
+ cy.get('#author_2_familyName').type('Doe');
+ cy.get('#author_3_givenName').type('Alex');
+
+ cy.get('#author_1_moveToRight').click()
+
+ cy.get('#author_1_givenName').should('have.value', 'John');
+ cy.get('#author_1_familyName').should('have.value', 'Doe');
+ cy.get('#author_1_affiliation').should('have.value', '');
+
+ cy.get('#author_2_givenName').should('have.value', 'Jane');
+ cy.get('#author_2_familyName').should('have.value', '');
+ cy.get('#author_2_affiliation').should('have.value', 'Example Org');
+
+ cy.get('#author_3_givenName').should('have.value', 'Alex');
+ cy.get('#author_3_familyName').should('have.value', '');
+ cy.get('#author_3_affiliation').should('have.value', '');
+ });
+
+ it('updates generated Codemeta', function() {
+ cy.get('#name').type('My Test Software');
+
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_1_givenName').type('Jane');
+ cy.get('#author_1_affiliation').type('Example Org');
+ cy.get('#author_2_givenName').type('John');
+ cy.get('#author_2_familyName').type('Doe');
+
+ cy.get('#generateCodemeta').click();
+
+ cy.get('#codemetaText').then((elem) => JSON.parse(elem.text()))
+ .should('deep.equal', {
+ "@context": "https://doi.org/10.5063/schema/codemeta-2.0",
+ "@type": "SoftwareSourceCode",
+ "name": "My Test Software",
+ "author": [
+ {
+ "@type": "Person",
+ "givenName": "Jane",
+ "affiliation": {
+ "@type": "Organization",
+ "name": "Example Org",
+ }
+ },
+ {
+ "@type": "Person",
+ "givenName": "John",
+ "familyName": "Doe",
+ },
+ ],
+ });
+
+ cy.get('#author_1_moveToRight').click();
+
+ cy.get('#codemetaText').then((elem) => JSON.parse(elem.text()))
+ .should('deep.equal', {
+ "@context": "https://doi.org/10.5063/schema/codemeta-2.0",
+ "@type": "SoftwareSourceCode",
+ "name": "My Test Software",
+ "author": [
+ {
+ "@type": "Person",
+ "givenName": "John",
+ "familyName": "Doe",
+ },
+ {
+ "@type": "Person",
+ "givenName": "Jane",
+ "affiliation": {
+ "@type": "Organization",
+ "name": "Example Org",
+ }
+ },
+ ],
+ });
+ });
+
+ it('wraps around to the right', function() {
+ cy.get('#name').type('My Test Software');
+
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_1_givenName').type('Jane');
+ cy.get('#author_1_affiliation').type('Example Org');
+ cy.get('#author_2_givenName').type('John');
+ cy.get('#author_2_familyName').type('Doe');
+ cy.get('#author_3_givenName').type('Alex');
+
+ cy.get('#author_1_moveToLeft').click()
+
+ cy.get('#author_1_givenName').should('have.value', 'Alex');
+ cy.get('#author_1_familyName').should('have.value', '');
+ cy.get('#author_1_affiliation').should('have.value', '');
+
+ cy.get('#author_2_givenName').should('have.value', 'John');
+ cy.get('#author_2_familyName').should('have.value', 'Doe');
+ cy.get('#author_2_affiliation').should('have.value', '');
+
+ cy.get('#author_3_givenName').should('have.value', 'Jane');
+ cy.get('#author_3_familyName').should('have.value', '');
+ cy.get('#author_3_affiliation').should('have.value', 'Example Org');
+ });
+
+ it('wraps around to the left', function() {
+ cy.get('#name').type('My Test Software');
+
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_add').click();
+ cy.get('#author_1_givenName').type('Jane');
+ cy.get('#author_1_affiliation').type('Example Org');
+ cy.get('#author_2_givenName').type('John');
+ cy.get('#author_2_familyName').type('Doe');
+ cy.get('#author_3_givenName').type('Alex');
+
+ cy.get('#author_3_moveToRight').click()
+
+ cy.get('#author_1_givenName').should('have.value', 'Alex');
+ cy.get('#author_1_familyName').should('have.value', '');
+ cy.get('#author_1_affiliation').should('have.value', '');
+
+ cy.get('#author_2_givenName').should('have.value', 'John');
+ cy.get('#author_2_familyName').should('have.value', 'Doe');
+ cy.get('#author_2_affiliation').should('have.value', '');
+
+ cy.get('#author_3_givenName').should('have.value', 'Jane');
+ cy.get('#author_3_familyName').should('have.value', '');
+ cy.get('#author_3_affiliation').should('have.value', 'Example Org');
+ });
+})
diff --git a/index.html b/index.html
index 691f4ec..38f7cbe 100644
--- a/index.html
+++ b/index.html
@@ -1,357 +1,355 @@
<!doctype html>
<!--
Copyright (C) 2019-2020 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
-->
<html lang="en">
<head>
<meta charset="utf-8">
<title>CodeMeta generator</title>
<script src="./js/utils.js"></script>
<script src="./js/fields_data.js"></script>
<script src="./js/dynamic_form.js"></script>
<script src="./js/codemeta_generation.js"></script>
<script src="./js/validation/primitives.js"></script>
<script src="./js/validation/things.js"></script>
<script src="./js/validation/index.js"></script>
<link rel="stylesheet" type="text/css" href="./main.css">
<link rel="stylesheet" type="text/css" href="./codemeta.css">
</head>
<body>
<header>
<h1>CodeMeta generator</h1>
</header>
<main>
<p>Most fields are optional. Mandatory fields will be highlighted when generating Codemeta.</p>
<noscript>
<p id="noscriptError">
This application requires Javascript to show dynamic fields in the form,
and generate a JSON file; but your browser does not support Javascript.
If you cannot use a browser with Javascript support, you can try
<a href="https://codemeta.github.io/tools/">one of the other available tools</a>
or write the codemeta.json file directly.
</p>
</noscript>
<form id="inputForm">
<fieldset id="fieldsetSoftwareItself" class="leafFieldset">
<legend>The software itself</legend>
<p title="The name of the software">
<label for="name">Name</label>
<input type="text" name="name" id="name" aria-describedby="name_descr"
placeholder="My Software" required="required" />
<span class="field-description" id="name_descr">the software title</span>
</p>
<p title="a brief description of the software">
<label for="description">Description</label>
<textarea rows="4" cols="50"
name="description" id="description"
placeholder="My Software computes ephemerides and orbit propagation. It has been developed from early ´80." ></textarea>
</p>
<p title="The date on which the software was created.">
<label for="dateCreated">Creation date</label>
<input type="text" name="dateCreated" id="dateCreated"
placeholder="YYYY-MM-DD" pattern="\d{4}-\d{2}-\d{2}" />
</p>
<p title="Date of first publication.">
<label for="datePublished">First release date</label>
<input type="text" name="datePublished" id="datePublished"
placeholder="YYYY-MM-DD" pattern="\d{4}-\d{2}-\d{2}" />
</p>
<p>
<label for="license">License</label>
<input list="licenses" name="license" id="license"
aria-describedby="licenses_descr"> <!-- TODO: insert placeholder -->
<datalist id="licenses">
</datalist>
<!-- This datalist is be filled automatically -->
<br />
<span class="field-description" id="licenses_descr">from <a href="https://spdx.org/license-list">SPDX licence list</a></span>
</p>
</fieldset>
<fieldset id="fieldsetDiscoverabilityAndCitation" class="leafFieldset">
<legend>Discoverability and citation</legend>
<p title="Unique identifier">
<label for="identifier">Unique identifier</label>
<input type="text" name="identifier" id="identifier"
placeholder="10.151.xxxxx" aria-describedby="identifier_descr" />
<br />
<span class="field-description" id="identifier_descr">
such as ISBNs, GTIN codes, UUIDs etc.. <a href="http://schema.org/identifier">http://schema.org/identifier</a>
</span>
</p>
<!-- TODO:define better
I looked at the schema.org definition of identifier (https://schema.org/identifier),
it can be text, url or PropertyValue.
Used as follows in data representation with microdata:
<div property="identifier" typeof="PropertyValue">
<span property="propertyID">DOI</span>:
<span property="value">10.151.xxxxx</span>
</div>
we can use that with identifier-type and identifier-value to have a clearer idea
of what needs to be in the input.
-->
<p title="Type of the software application">
<label for="applicationCategory">Application category</label>
<input type="text" name="applicationCategory" id="applicationCategory"
placeholder="Astronomy" />
</p>
<p title="Comma-separated list of keywords">
<label for="keywords">Keywords</label>
<input type="text" name="keywords" id="keywords"
placeholder="ephemerides, orbit, astronomy" />
</p>
<p title="Funding / grant">
<label for="funding">Funding</label>
<input type="text" name="funding" id="funding" aria-describedby="funding_descr"
placeholder="PRA_2018_73"/>
<br />
<span class="field-description" id="funding_descr">grant funding software development</span>
</p>
<p title="Funding / organization">
<label for="funder">Funder</label>
<input type="text" name="funder" id="funder" aria-describedby="funder_descr"
placeholder="Università di Pisa"/>
<br />
<span class="field-description" id="funder_descr">organization funding software development</span>
</p>
Authors and contributors can be added below
</fieldset>
<fieldset id="fieldsetDevelopmentCommunity" class="leafFieldset">
<legend>Development community / tools</legend>
<p title="Link to the repository where the un-compiled, human readable code and related code is located (SVN, Git, GitHub, CodePlex, institutional GitLab instance, etc.).">
<label for="codeRepository">Code repository</label>
<input type="URL" name="codeRepository" id="codeRepository"
placeholder="git+https://github.com/You/RepoName.git" />
</p>
<p title="Link to continuous integration service (Travis-CI, Gitlab CI, etc.).">
<label for="contIntegration">Continuous integration</label>
<input type="URL" name="contIntegration" id="contIntegration"
placeholder="https://travis-ci.org/You/RepoName" />
</p>
<p title="Link to a place for users/developpers to report and manage bugs (JIRA, GitHub issues, etc.).">
<label for="issueTracker">Issue tracker</label>
<input type="URL" name="issueTracker" id="issueTracker"
placeholder="https://github.com/You/RepoName/issues" />
</p>
<p title="Related document, software, tools">
<label for="relatedLink">Related links</label>
<br />
<textarea rows="4" cols="50"
name="relatedLink" id="relatedLink"></textarea>
</fieldset>
<fieldset id="fieldsetRuntime" class="leafFieldset">
<legend>Run-time environment</legend>
<p title="Programming Languages, separated by commas">
<label for="programmingLanguage">Programming Language</label>
<input type="text" name="programmingLanguage" id="programmingLanguage"
placeholder="C#, Java, Python 3" />
</p>
<p title="Runtime Platforms, separated by commas">
<label for="runtimePlatform">Runtime Platform</label>
<input type="text" name="runtimePlatform" id="runtimePlatform"
placeholder=".NET, JVM" />
</p>
<p title="Operating Systems, separated by commas">
<label for="operatingSystem">Operating System</label>
<input type="text" name="operatingSystem" id="operatingSystem"
placeholder="Android 1.6, Linux, Windows, macOS" />
</p>
<p title="Required software to run/use this one.">
<label for="softwareRequirements">Other software requirements</label>
<br />
<textarea rows="4" cols="50"
name="softwareRequirements" id="softwareRequirements"
placeholder=
"Python 3.4
https://github.com/psf/requests"></textarea>
</fieldset>
<fieldset id="fieldsetCurrentVersion" class="leafFieldset">
<legend>Current version of the software</legend>
<p title="Version number of the software">
<label for="version">Version number</label>
<input type="text" name="version" id="version"
placeholder="1.0.0" />
</p>
<p title="The date on which the software was most recently modified.">
<label for="dateModified">Release date</label>
<input type="text" name="dateModified" id="dateModified"
placeholder="YYYY-MM-DD" pattern="\d{4}-\d{2}-\d{2}" />
</p>
<p title="Download link">
<label for="downloadUrl">Download URL</label>
<input type="URL" name="downloadUrl" id="downloadUrl"
placeholder="https://example.org/MySoftware.tar.gz" />
</p>
<p title="a brief description of the software">
<label for="releaseNotes">Release notes</label>
<br />
<textarea rows="4" cols="50"
name="releaseNotes" id="releaseNotes"
placeholder=
"Change log: this and that;
Bugfixes: that and this." ></textarea>
</p>
<!--TODO: referencePublication as ScholarlyArticle array -->
</fieldset>
<fieldset id="fieldsetAdditionalInfo" class="leafFieldset">
<legend>Additional Info</legend>
<p title="Scholarly article describing this software">
<label for="referencePublication">Reference Publication</label>
<input type="URL" name="referencePublication" id="referencePublication"
placeholder="https://doi.org/10.1000/xyz123" />
</p>
<p title="Development Status">
<label for="developmentStatus">Development Status</label>
<datalist id="developmentStatuses">
<option value="concept">
<option value="wip">
<option value="suspended">
<option value="abandoned">
<option value="active">
<option value="inactive">
<option value="unsupported">
<option value="moved">
</datalist>
<input list="developmentStatuses" id="developmentStatus" aria-describedby="developmentStatuses_descr"
pattern="concept|wip|suspended|abandoned|active|inactive|unsupported|moved">
<br />
<span class="field-description" id="developmentStatuses_descr">
see <a href="http://www.repostatus.org">www.repostatus.org</a> for details
</span>
</p>
<p title="Part of">
<label for="isPartOf">Is part of</label>
<input type="URL" name="isPartOf" id="isPartOf"
placeholder="http://The.Bigger.Framework.org" />
</p>
</fieldset>
<div class="dynamicFields">
<fieldset class="persons" id="author_container">
<legend>Authors</legend>
- <p>Order of authors does not matter.</p>
-
<input type="hidden" id="author_nb" value="0" />
<div id="addRemoveAuthor">
<input type="button" id="author_add" value="Add one"
onclick="addPerson('author', 'Author');" />
<input type="button" id="author_remove" value="Remove last"
onclick="removePerson('author');" />
</div>
</fieldset>
<fieldset class="persons" id="contributor_container">
<legend>Contributors</legend>
<p>Order of contributors does not matter.</p>
<input type="hidden" id="contributor_nb" value="0" />
<div id="addRemoveContributor">
<input type="button" id="contributor_add" value="Add one"
onclick="addPerson('contributor', 'Contributor');" />
<input type="button" id="contributor_remove" value="Remove last"
onclick="removePerson('contributor');" />
</div>
</fieldset>
</div>
</form>
<form>
<input type="button" id="generateCodemeta" value="Generate codemeta.json"
title="Creates a codemeta.json file below, from the information provided above." />
<input type="button" id="resetForm" value="Reset form"
title="Erases all fields." />
<input type="button" id="validateCodemeta" value="Validate codemeta.json"
title="Checks the codemeta.json file below is valid, and displays errors." />
<input type="button" id="importCodemeta" value="Import codemeta.json"
title="Fills the fields above based on the codemeta.json file below." />
</form>
<p id="errorMessage">
</p>
<p>codemeta.json:</p>
<pre contentEditable="true" id="codemetaText"></pre>
</main>
<footer>
<p style="text-align:center;">
Do you want to improve this tool ?
Check out the
<a href="https://github.com/codemeta/codemeta-generator">
CodeMeta-generator repository</a>
<br />
Join the
<a href="https://github.com/codemeta/codemeta">CodeMeta community</a>
discussion
<br />
The CodeMeta vocabulary -
<a href="https://doi.org/10.5063/schema/codemeta-2.0">v2.0</a>
</p>
<h2 style="text-align:right;">Contributed by</h2>
<p style="text-align:right;">
<a href="https://www.softwareheritage.org/save-and-reference-research-software/">
<img alt="Software Heritage" src="https://annex.softwareheritage.org/public/logo/software-heritage-logo-title-motto.svg"
width="300">
</a>
</p>
</footer>
<script>
initFieldsData();
initCallbacks();
loadStateFromStorage();
</script>
</body>
</html>
diff --git a/js/dynamic_form.js b/js/dynamic_form.js
index 8fef145..15b2785 100644
--- a/js/dynamic_form.js
+++ b/js/dynamic_form.js
@@ -1,131 +1,186 @@
/**
* 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";
+// List of all HTML fields in a Person fieldset.
+const personFields = [
+ 'givenName',
+ 'familyName',
+ 'email',
+ 'id',
+ 'affiliation',
+];
+
function createPersonFieldset(personPrefix, legend) {
// Creates a fieldset containing inputs for informations about a person
var fieldset = document.createElement("fieldset")
+ var moveButtons;
fieldset.classList.add("person");
fieldset.classList.add("leafFieldset");
fieldset.id = personPrefix;
fieldset.innerHTML = `
<legend>${legend}</legend>
+ <div class="moveButtons">
+ <input type="button" id="${personPrefix}_moveToLeft" value="<" class="moveToLeft"
+ title="Moves this person to the left." />
+ <input type="button" id="${personPrefix}_moveToRight" value=">" class="moveToRight"
+ title="Moves this person to the right." />
+ </div>
<p>
<label for="${personPrefix}_givenName">Given name</label>
<input type="text" id="${personPrefix}_givenName" name="${personPrefix}_givenName"
placeholder="Jane" required="true" />
</p>
<p>
<label for="${personPrefix}_familyName">Family name</label>
<input type="text" id="${personPrefix}_familyName" name="${personPrefix}_familyName"
placeholder="Doe" />
</p>
<p>
<label for="${personPrefix}_email">E-mail address</label>
<input type="email" id="${personPrefix}_email" name="${personPrefix}_email"
placeholder="jane.doe@example.org" />
</p>
<p>
<label for="${personPrefix}_id">URI</label>
<input type="url" id="${personPrefix}_id" name="${personPrefix}_id"
placeholder="http://orcid.org/0000-0002-1825-0097" />
</p>
<p>
<label for="${personPrefix}_affiliation">Affiliation</label>
<input type="text" id="${personPrefix}_affiliation" name="${personPrefix}_affiliation"
placeholder="Department of Computer Science, University of Pisa" />
</p>
`;
return fieldset;
}
function addPersonWithId(container, prefix, legend, id) {
- var fieldset = createPersonFieldset(`${prefix}_${id}`, `${legend} #${id}`);
+ var personPrefix = `${prefix}_${id}`;
+ var fieldset = createPersonFieldset(personPrefix, `${legend} #${id}`);
container.appendChild(fieldset);
+
+ document.querySelector(`#${personPrefix}_moveToLeft`)
+ .addEventListener('click', () => movePerson(prefix, id, "left"));
+ document.querySelector(`#${personPrefix}_moveToRight`)
+ .addEventListener('click', () => movePerson(prefix, id, "right"));
+}
+
+function movePerson(prefix, id1, direction) {
+ var nbPersons = getNbPersons(prefix);
+ var id2;
+
+ // Computer id2, the id of the person to flip id1 with (wraps around the
+ // end of the list of persons)
+ if (direction == "left") {
+ id2 = id1 - 1;
+ if (id2 <= 0) {
+ id2 = nbPersons;
+ }
+ }
+ else {
+ id2 = id1 + 1;
+ if (id2 > nbPersons) {
+ id2 = 1;
+ }
+ }
+
+ // Flip the field values, one by one
+ personFields.forEach((fieldName) => {
+ var field1 = document.querySelector(`#${prefix}_${id1}_${fieldName}`);
+ var field2 = document.querySelector(`#${prefix}_${id2}_${fieldName}`);
+ var value1 = field1.value;
+ var value2 = field2.value;
+ field2.value = value1;
+ field1.value = value2;
+ });
+
+ // Form was changed; regenerate
+ generateCodemeta();
}
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 fieldToLower(event) {
event.target.value = event.target.value.toLowerCase();
}
function initCallbacks() {
document.querySelector('#license')
.addEventListener('change', validateLicense);
document.querySelector('#generateCodemeta')
.addEventListener('click', generateCodemeta);
document.querySelector('#resetForm')
.addEventListener('click', resetForm);
document.querySelector('#validateCodemeta')
.addEventListener('click', () => parseAndValidateCodemeta(true));
document.querySelector('#importCodemeta')
.addEventListener('click', importCodemeta);
document.querySelector('#inputForm')
.addEventListener('change', generateCodemeta);
document.querySelector('#developmentStatus')
.addEventListener('change', fieldToLower);
initPersons('author', 'Author');
initPersons('contributor', 'Contributor');
}
diff --git a/main.css b/main.css
index 3cdd50f..dfa7c62 100644
--- a/main.css
+++ b/main.css
@@ -1,72 +1,78 @@
/**
* 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
*/
/* This file contains the main CSS to make the form/application usable,
* without being especially pretty.
*/
#noscriptError {
color: red;
}
.person {
display: inline-block;
}
#inputForm {
max-width: 100%;
display: flex;
flex-wrap: wrap;
}
/* A fieldset that contains only label/input pairs */
.leafFieldset {
flex: auto;
}
p input, p textarea {
width: 100%;
box-sizing: border-box;
}
.dynamicFields {
width: 100%;
}
+.dynamicFields .moveButtons {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+}
+
#license {
/* License names are long */
min-width: 20em;
}
#funding {
/* Funding names are long */
min-width: 20em;
}
input[type=URL] {
/* URLs are longer than the other fields */
min-width: 20em;
}
.field-description {
color : rgb(100, 104, 103);
font-size: small;
}
#codemetaText {
width: 100%;
min-height: 10em;
border: 1px solid black;
}
#errorMessage {
color: red;
}
input:invalid {
color: red;
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jul 4, 3:29 PM (1 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3252891

Event Timeline