Skip to content

Commit 843470b

Browse files
committed
MIR-1566 Redesign affiliation submission
1 parent dd90c55 commit 843470b

File tree

14 files changed

+215
-132
lines changed

14 files changed

+215
-132
lines changed

mir-module/src/main/resources/META-INF/resources/editor/editor-includes.xed

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -676,42 +676,23 @@
676676
</xed:template>
677677

678678
<xed:template id="person.affiliation">
679-
<!-- affiliation without authorityURI -->
680-
<mir:textfield repeat="true" xpath="mods:affiliation[not(@authorityURI)]" help-text="{i18n:mir.help.affiliation}" label="mir.affiliation" />
681-
682-
<!-- affiliation with authorityURI https://ror.org/ -->
683-
<xed:repeat xpath="mods:affiliation[@authorityURI='https://ror.org/']" min="1" max="10">
684-
<div class="mir-form-group row">
679+
<xed:repeat xpath="mods:affiliation" min="1" max="10">
680+
<div class="mir-form-group row mir-affiliation-container">
685681
<label class="col-md-3 col-form-label text-end">
686-
<xed:output i18n="mir.affiliation.with.ror.id.label"/>
682+
<xed:output i18n="mir.affiliation"/>
687683
</label>
688-
689684
<div class="col-md-6">
690685
<xed:bind xpath=".">
691-
<select class="form-control mir-select-searchable mir-select-affiliation"
692-
data-placeholder="{i18n:mir.affiliation.with.ror.id.placeholder}">
693-
694-
<xed:choose>
695-
<xed:when test="string-length(@valueURI) &gt; 0">
696-
<option>
697-
<xsl:attribute name="value">
698-
<xsl:value-of select="concat(., ' (', @valueURI, ')')"/>
699-
</xsl:attribute>
700-
<xed:output value="."/>
701-
</option>
702-
</xed:when>
703-
<xed:otherwise>
704-
<option>
705-
<xed:output value="."/>
706-
</option>
707-
</xed:otherwise>
708-
</xed:choose>
709-
710-
</select>
686+
<input
687+
class="form-control mir-affiliation"
688+
type="text" autocomplete="off"
689+
placeholder="{i18n:mir.affiliation.placeholder}" />
690+
</xed:bind>
691+
<xed:bind xpath="@valueURI">
692+
<input class="mir-affiliation-id" type="hidden" />
711693
</xed:bind>
712-
713694
</div>
714-
<mir:help-pmud help-text="{i18n:mir.help.affiliation.with.ror.id}" pmud="true"/>
695+
<mir:help-pmud help-text="{i18n:mir.help.affiliation}" pmud="true"/>
715696
</div>
716697
</xed:repeat>
717698
</xed:template>

mir-module/src/main/resources/config/mir/messages_de.properties

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,7 @@ mir.actions.norights =
134134
mir.add.more.text.placeholder = F\u00FCr die Suche ist mindestens ein Zeichen erforderlich
135135
mir.admineditor = Bearbeiten im Admin-Editor
136136
mir.affiliation = Zugeh\u00F6rigkeit
137-
mir.affiliation.ror = Zugeh\u00F6rigkeit (ROR ID)
138-
mir.affiliation.with.ror.id.label = Zugeh\u00F6rigkeit (ROR)
139-
mir.affiliation.with.ror.id.placeholder = Geben Sie die ROR ID oder den Institutionsnamen an
137+
mir.affiliation.placeholder = Zugeh\u00F6rigkeit eingeben oder suchen
140138
mir.articlenumber = Artikelnummer:
141139
mir.articlenumber.short = Art.-Nr.:
142140
mir.backToTop.label = Nach oben
@@ -388,9 +386,7 @@ mir.help.abstract.aslink =
388386
mir.help.abstract.language = Geben Sie die Sprache an, in der das hier ver\u00F6ffentlichte Abstract verfasst ist. Bei Zusammenfassungen in verschiedenen Sprachen k\u00F6nnen Sie diese mit dem \u201E+\u201C-Button wiederholen.
389387
mir.help.abstract.ortext = Eine kurze Zusammenfassung des Dokumentinhalts.
390388
mir.help.access = Geben Sie hier an, wer auf die angehangenen Dokumente zugreifen darf.
391-
mir.help.affiliation = Organisation bzw. Institution der betreffenden Person.
392-
mir.help.affiliation.ror = <a href="https://ror.org/">ROR ID</a> der Organisation bzw. Institution der betreffenden Person.
393-
mir.help.affiliation.with.ror.id = Bitte suchen und w\u00E4hlen Sie Ihre Zugeh\u00F6rigkeit aus. Sie k\u00F6nnen Ihre Zugeh\u00F6rigkeit auch \u00FCber die ROR-ID finden.
389+
mir.help.affiliation = Geben Sie die institutionelle Zugeh\u00F6rigkeit ein oder suchen Sie nach einer ROR-registrierten Institution.
394390
mir.help.articlenumber = Die Nummer eines Artikels, der in einer Online-Zeitschrift oder auf einer Publikationsplattform erschienen ist.
395391
mir.help.artist.photographer = K\u00FCnstler des Werkes oder Fotograf des Bildes.
396392
mir.help.author.interviewee = Eine Person, Familie oder Organisation, die f\u00FCr die Erstellung oder den Beitrag zu einer Ressource verantwortlich ist, indem sie auf einen Interviewer, in der Regel einen Reporter, Meinungsforscher oder \u00E4hnlichen, reagiert.

mir-module/src/main/resources/config/mir/messages_en.properties

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ mir.actions.norights =
131131
mir.add.more.text.placeholder = At least one character is required to search
132132
mir.admineditor = Edit in admin editor
133133
mir.affiliation = Affiliation
134-
mir.affiliation.ror = Affiliation (ROR ID)
135-
mir.affiliation.with.ror.id.label = Affiliation with the ROR ID
136-
mir.affiliation.with.ror.id.placeholder = Enter the ROR ID or institution name
134+
mir.affiliation.placeholder = Enter or search affiliation
137135
mir.articlenumber = Article number:
138136
mir.articlenumber.short = Art.-No.:
139137
mir.backToTop.label = back to top
@@ -375,9 +373,7 @@ mir.help.abstract =
375373
mir.help.abstract.aslink = Weblink to abstract.
376374
mir.help.abstract.ortext = A short summary of the document content.
377375
mir.help.access = Specify who should be able to access the dataset after publication. The metadata will be public in any case.
378-
mir.help.affiliation = Organisation/Affiliation of the Person.
379-
mir.help.affiliation.ror = <a href="https://ror.org/">ROR ID</a> of the Organisation/Affiliation of the Person.
380-
mir.help.affiliation.with.ror.id = The organisation/affiliation of the Person with the <a href="https://ror.org/" target="_blank" rel="noopener noreferrer">ROR ID</a>.
376+
mir.help.affiliation = Enter the institutional affiliation or search for a ROR-registered institution.
381377
mir.help.articlenumber = The number of an article published in an online journal or publication platform.
382378
mir.help.artist.photographer = Creator of the Picture/Image.
383379
mir.help.author.interviewee = A person, family or organization responsible for creating or contributing to a resource by responding to an interviewer, usually a reporter, pollster, or some other information gathering agent.

mir-module/src/main/resources/config/mir/messages_it.properties

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ component.mods.metaData.options.MD5.show = Mostra somme MD5
55
editor.search.mir.openAccess = accesso libero
66
metadata.versionInfo.inProgress = Cronologia non ancora disponibile
77
mir.add.more.text.placeholder = Per la ricerca è richiesto almeno un carattere
8-
mir.affiliation.with.ror.id.label = Affiliazione con l'ID ROR
9-
mir.affiliation.with.ror.id.placeholder = Inserisci l'ID ROR o il nome dell'istituto
8+
mir.affiliation = Affiliazione
9+
mir.affiliation.placeholder = Inserire o cercare affiliazione
1010
mir.backToTop.label = Torna su
1111
mir.derivate.file.MD5 = somma MD5:
1212
mir.dropdown.all = Tutto
@@ -18,6 +18,7 @@ mir.dropdown.nameIdentifier = Mome identifikator
1818
mir.dropdown.title = Titolo
1919
mir.help.abstract = Un breve riassunto/abstract del contenuto del documento.
2020
mir.help.abstract.ortext = Un breve riassunto/abstract del contenuto del documento in diverse lingue.
21+
mir.help.affiliation = Inserire l'affiliazione istituzionale o cercare un'istituzione registrata in ROR.
2122
mir.help.comment = Qui si possono facoltativamente lasciare commenti sul documento.
2223
mir.help.conference = Inserire il titolo del convegno.
2324
mir.help.date.accepted = Data della discussione (accettazione del lavoro). La data deve essere indicata in formato ISO e tramite l\u2019uso di\r\ntrattini YYYY-MM-DD, YYYY-MM o YYYY.\r\n<br />\r\nAd esempio: 2003-01-27 o 2010 o 2009-01

mir-module/src/main/resources/xslt/editor/mir2xeditor.xsl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@
425425
</div>
426426
</fieldset>
427427
</xed:repeat>
428+
<script type="module" src="{$WebApplicationBaseURL}js/mir/editor-name.js"/>
428429
</xsl:template>
429430

430431
<xsl:template match="mir:role.repeated">
@@ -520,6 +521,7 @@
520521
handleRoleSelect($(e.currentTarget));
521522
});
522523
</script>
524+
<script type="module" src="{$WebApplicationBaseURL}js/mir/editor-name.js"/>
523525
</xsl:template>
524526

525527
<xsl:template match="mir:person.repeated">

mir-module/src/main/resources/xslt/editor/mods2xeditor.xsl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,6 @@
180180
</xsl:copy>
181181
</xsl:template>
182182

183-
<xsl:template match="mods:affiliation[@authorityURI='https://ror.org/'][@valueURI]">
184-
<mods:affiliation authorityURI="{@authorityURI}" valueURI="{@valueURI}">
185-
<xsl:value-of select="concat(., ' (', @valueURI, ')')"/>
186-
</mods:affiliation>
187-
</xsl:template>
188-
189183
<!-- Remove this mods:classification entry, will be created again while saving using mods:accessCondtition (see MIR-161) -->
190184
<xsl:template match="mods:classification[@authority='accessRestriction']">
191185
<!-- do nothing -->

mir-module/src/main/resources/xslt/editor/xeditor2mods.xsl

Lines changed: 10 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -120,77 +120,17 @@
120120
</mods:nameIdentifier>
121121
</xsl:template>
122122

123-
<xsl:template match="mods:affiliation">
124-
<xsl:variable name="fullValue" select="."/>
125-
126-
<xsl:choose>
127-
<!-- Case when affiliation contains a ROR URL -->
128-
<xsl:when test="contains($fullValue, 'ror.org/')">
129-
<!-- Extract name (everything before the opening parenthesis of the ROR URL) -->
130-
<xsl:variable name="beforeROR" select="substring-before($fullValue, '(http')"/>
131-
<xsl:variable name="name">
132-
<xsl:choose>
133-
<xsl:when test="$beforeROR != ''">
134-
<xsl:value-of select="normalize-space($beforeROR)"/>
135-
</xsl:when>
136-
<xsl:otherwise>
137-
<!-- If there's nothing before the ROR URL, use the part after as name -->
138-
<xsl:value-of select="normalize-space(substring-before($fullValue, ')'))"/>
139-
</xsl:otherwise>
140-
</xsl:choose>
141-
</xsl:variable>
142-
143-
<!-- Extract ROR URL -->
144-
<xsl:variable name="rorURL">
145-
<xsl:call-template name="extractRORURL">
146-
<xsl:with-param name="text" select="$fullValue"/>
147-
</xsl:call-template>
148-
</xsl:variable>
149-
150-
<mods:affiliation authorityURI="https://ror.org/">
151-
<xsl:if test="$rorURL != ''">
152-
<xsl:attribute name="valueURI">
153-
<xsl:value-of select="$rorURL"/>
154-
</xsl:attribute>
155-
</xsl:if>
156-
<xsl:value-of select="$name"/>
157-
</mods:affiliation>
158-
</xsl:when>
159-
160-
<!-- Case when affiliation is just plain text without ROR URL -->
161-
<xsl:otherwise>
162-
<mods:affiliation>
163-
<xsl:value-of select="$fullValue"/>
164-
</mods:affiliation>
165-
</xsl:otherwise>
166-
</xsl:choose>
167-
</xsl:template>
168-
169-
<!-- Helper template to extract ROR URL -->
170-
<xsl:template name="extractRORURL">
171-
<xsl:param name="text"/>
172-
173-
<!-- Find the start of http(s) -->
174-
<xsl:variable name="afterOpenParen" select="substring-after($text, '(')"/>
175-
<xsl:variable name="httpPos">
176-
<xsl:choose>
177-
<xsl:when test="contains($afterOpenParen, 'http://ror.org/')">
178-
<xsl:value-of select="'http://ror.org/'"/>
179-
</xsl:when>
180-
<xsl:when test="contains($afterOpenParen, 'https://ror.org/')">
181-
<xsl:value-of select="'https://ror.org/'"/>
182-
</xsl:when>
183-
<xsl:otherwise/>
184-
</xsl:choose>
185-
</xsl:variable>
186-
187-
<xsl:if test="$httpPos != ''">
188-
<xsl:variable name="afterHTTP" select="substring-after($afterOpenParen, $httpPos)"/>
189-
<xsl:variable name="rorID" select="substring-before($afterHTTP, ')')"/>
190-
<xsl:if test="$rorID != ''">
191-
<xsl:value-of select="concat($httpPos, $rorID)"/>
123+
<xsl:template match="mods:affiliation[@valueURI and not(@authorityURI)]">
124+
<xsl:copy>
125+
<xsl:copy-of select="@*" />
126+
<xsl:if test="not(@authorityURI)">
127+
<xsl:attribute name="authorityURI">https://ror.org</xsl:attribute>
128+
</xsl:if>
129+
<xsl:if test="not(@authority)">
130+
<xsl:attribute name="authority">ROR</xsl:attribute>
192131
</xsl:if>
193-
</xsl:if>
132+
<xsl:value-of select="." />
133+
</xsl:copy>
194134
</xsl:template>
195135

196136
<!-- Copy content of mods:accessCondtition to mods:classification to enable classification support (see MIR-161) -->

mir-module/src/main/ts/src/autocomplete.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ export class Autocomplete<T> {
2828
this.dropdown = document.createElement('ul');
2929
this.dropdown.classList.add('dropdown-menu', 'position-absolute');
3030
this.dropdown.style.display = 'none';
31-
this.dropdown.style.width = `${input.offsetWidth}px`;
3231

3332
const parent = input.parentElement;
3433
if (!parent) throw new Error('Input must have a parent element.');
@@ -92,6 +91,10 @@ export class Autocomplete<T> {
9291
signal: AbortSignal
9392
): Promise<void> {
9493
const items = await this.fetchData(query, signal);
94+
95+
const width = this.input.getBoundingClientRect().width;
96+
this.dropdown.style.width = `${width}px`;
97+
9598
items.forEach(item => {
9699
const li = document.createElement('li');
97100
li.classList.add('dropdown-item', 'text-wrap');
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Affiliation } from './types';
2+
3+
const API_URL = 'https://api.ror.org/v2/organizations';
4+
5+
interface RORName {
6+
types: string[];
7+
value: string;
8+
}
9+
10+
interface RORItem {
11+
id: string;
12+
names: RORName[];
13+
}
14+
15+
interface RORResponse {
16+
items: RORItem[];
17+
}
18+
19+
async function fetchRORItems(
20+
query: string,
21+
signal: AbortSignal
22+
): Promise<RORItem[]> {
23+
const response = await fetch(
24+
`${API_URL}?query=${encodeURIComponent(query)}`,
25+
{
26+
signal,
27+
}
28+
);
29+
if (!response.ok) {
30+
const text = await response.text().catch(() => '');
31+
throw new Error(`ROR API error (${response.status}): ${text}`);
32+
}
33+
const data: RORResponse = await response.json();
34+
return data.items;
35+
}
36+
37+
export async function fetchAffiliation(
38+
query: string,
39+
signal: AbortSignal
40+
): Promise<Affiliation[]> {
41+
if (!query.trim()) return [];
42+
const items = await fetchRORItems(query, signal);
43+
const affiliations: Affiliation[] = items.map(item => ({
44+
id: item.id,
45+
name:
46+
item.names.find(n => n.types.includes('ror_display'))?.value ||
47+
item.names[0]?.value ||
48+
'Unknown',
49+
}));
50+
return affiliations;
51+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type Affiliation = {
2+
name: string;
3+
id: string;
4+
};

0 commit comments

Comments
 (0)