@kit-data-manager/pid-component
Version:
The PID-Component is a web component that can be used to evaluate and display FAIR Digital Objects, PIDs, ORCiDs, and possibly other identifiers in a user-friendly way. It is easily extensible to support other identifier types.
1,147 lines (1,133 loc) • 109 kB
JavaScript
/*!
*
* Copyright 2024-2026 Karlsruhe Institute of Technology.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
'use strict';
var index = require('./index-SLWnk0w6.js');
require('./json-viewer.entry.cjs.js');
class GenericIdentifierType {
constructor(value, settings) {
this._isDarkMode = false;
this._settings = [];
this._items = [];
this._actions = [];
this._value = value;
this._settings = settings ? settings : [];
this.updateDarkMode();
}
get isDarkMode() {
return this._isDarkMode;
}
get settings() {
return this._settings;
}
set settings(value) {
this._settings = value;
this.updateDarkMode();
}
get items() {
return this._items;
}
get actions() {
return this._actions;
}
get value() {
return this._value;
}
get data() {
return undefined;
}
isResolvable() {
return true;
}
renderBody() {
return undefined;
}
updateDarkMode() {
var _a;
const darkModeSetting = (_a = this._settings) === null || _a === void 0 ? void 0 : _a.find(setting => setting.name === 'darkMode');
if (darkModeSetting) {
const darkMode = darkModeSetting.value;
if (darkMode === 'dark') {
this._isDarkMode = true;
}
else if (darkMode === 'light') {
this._isDarkMode = false;
}
else if (darkMode === 'system' && typeof window !== 'undefined' && window.matchMedia) {
this._isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
}
else {
this._isDarkMode = false;
}
}
}
let cacheInstance;
async function open() {
if ('caches' in self) {
cacheInstance = await caches.open('pid-component');
}
}
async function cachedFetch(url, init) {
await open();
if (cacheInstance) {
const response = await cacheInstance.match(url);
if (response) {
return response.json();
}
else {
let response;
try {
const parts = url.split('://');
if (parts.length > 1 && parts[0] !== 'https') {
response = await fetch(`https://${parts[1]}`, init);
if (!response) {
console.log(`404 for https://${parts[1]} - trying http://${parts[1]}`);
response = await fetch(`http://${parts[1]}`, init);
}
}
else {
response = await fetch(url, init);
}
}
catch (error) {
console.error('Fetch failed:', error);
throw error;
}
await cacheInstance.put(url, response.clone());
return response.json();
}
}
else {
const response = await fetch(url, init);
return response.json();
}
}
async function clearCache() {
if (cacheInstance) {
await cacheInstance.delete('pid-component');
}
}
class ORCIDInfo {
constructor(orcid, ORCiDJSON, familyName, givenNames, employments, preferredLocale, biography, emails, keywords, researcherUrls, country) {
this._orcid = orcid;
this._familyName = familyName;
this._givenNames = givenNames;
this._employments = employments;
this._preferredLocale = preferredLocale;
this._biography = biography;
this._emails = emails;
this._keywords = keywords;
this._researcherUrls = researcherUrls;
this._country = country;
this._ORCiDJSON = ORCiDJSON;
}
get orcid() {
return this._orcid;
}
get familyName() {
return this._familyName;
}
get givenNames() {
return this._givenNames;
}
get ORCiDJSON() {
return this._ORCiDJSON;
}
get employments() {
return this._employments;
}
get preferredLocale() {
return this._preferredLocale;
}
get biography() {
return this._biography;
}
get emails() {
return this._emails;
}
get keywords() {
return this._keywords;
}
get researcherUrls() {
return this._researcherUrls;
}
get country() {
return this._country;
}
static isORCiD(text) {
const regex = new RegExp('^(https://orcid.org/)?[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]');
return regex.test(text);
}
static async getORCiDInfo(orcid) {
if (!ORCIDInfo.isORCiD(orcid))
throw new Error('Invalid input');
if (orcid.match('^(https://orcid.org/)?[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]') !== null)
orcid = orcid.replace('https://orcid.org/', '');
orcid = orcid
.replace(/^orcid:/i, '')
.replace(/^https?:\/\/orcid.org\//i, '')
.replace(/\/+$/, '')
.replace(/\.+$/, '')
.replace(/"+/g, '')
.replace(/'+/g, '')
.replace(/\s+/g, '')
.replace(/,+$/, '')
.replace(/;+$/, '')
.replace(/:+$/, '')
.trim();
const rawOrcidJSON = await cachedFetch(`https://pub.orcid.org/v3.0/${orcid}`, {
headers: {
Accept: 'application/json',
},
});
let familyName = '';
let givenNames = [];
try {
familyName = rawOrcidJSON['person']['name']['family-name']['value'];
}
catch (e) {
console.debug(e);
}
try {
givenNames = rawOrcidJSON['person']['name']['given-names']['value'];
}
catch (e) {
console.debug(e);
}
const affiliations = rawOrcidJSON['activities-summary']['employments']['affiliation-group'];
const employments = [];
try {
for (let i = 0; i < affiliations.length; i++) {
const employmentSummary = affiliations[i]['summaries'][0]['employment-summary'];
const employment = new Employment(new Date(), null, '', '');
if (employmentSummary['start-date'] !== null)
employment.startDate = new Date(employmentSummary['start-date']['year']['value'], employmentSummary['start-date']['month']['value'], employmentSummary['start-date']['day']['value']);
if (employmentSummary['end-date'] !== null)
employment.endDate = new Date(employmentSummary['end-date']['year']['value'], employmentSummary['end-date']['month']['value'], employmentSummary['end-date']['day']['value']);
employment.organization = employmentSummary['organization']['name'];
employment.department = employmentSummary['department-name'];
employments.push(employment);
}
}
catch (e) {
console.debug(e);
}
const preferredLocale = rawOrcidJSON['preferences']['locale'] !== null ? rawOrcidJSON['preferences']['locale'] : undefined;
const biography = rawOrcidJSON['person']['biography'] !== null ? rawOrcidJSON['person']['biography']['content'] : undefined;
const emails = [];
if (rawOrcidJSON['person']['emails']['email'] !== null) {
for (const email of rawOrcidJSON['person']['emails']['email']) {
emails.push({
email: email['email'],
primary: email['primary'],
verified: email['verified'],
});
}
}
const keywords = [];
if (rawOrcidJSON['person']['keywords']['keyword'] !== null) {
for (const keyword of rawOrcidJSON['person']['keywords']['keyword']) {
keywords.push({
content: keyword['content'],
index: keyword['display-index'],
});
}
keywords.sort((a, b) => a.index - b.index);
}
const researcherUrls = [];
if (rawOrcidJSON['person']['researcher-urls']['researcher-url'] !== null) {
for (const researcherUrl of rawOrcidJSON['person']['researcher-urls']['researcher-url']) {
researcherUrls.push({
url: researcherUrl['url']['value'],
name: researcherUrl['url-name'],
index: researcherUrl['display-index'],
});
}
researcherUrls.sort((a, b) => a.index - b.index);
}
const country = rawOrcidJSON['person']['addresses']['address'].length > 0 ? rawOrcidJSON['person']['addresses']['address'][0]['country']['value'] : undefined;
return new ORCIDInfo(orcid, rawOrcidJSON, familyName, givenNames, employments, preferredLocale, biography, emails, keywords, researcherUrls, country);
}
static fromJSON(serialized) {
const data = JSON.parse(serialized);
const employments = data.employments.map(employment => Employment.fromJSON(employment));
return new ORCIDInfo(data.orcid, data.ORCiDJSON, data.familyName, data.givenNames, employments, data.preferredLocale, data.biography, data.emails, data.keywords, data.researcherUrls, data.country);
}
getAffiliationsAt(date) {
const affiliations = [];
for (const employment of this._employments) {
if (employment.startDate <= date && employment.endDate === null)
affiliations.push(employment);
if (employment.startDate <= date && employment.endDate !== null && employment.endDate >= date)
affiliations.push(employment);
}
return affiliations;
}
getAffiliationAsString(affiliation, showDepartment = true) {
if (affiliation === undefined || affiliation.organization === null)
return undefined;
else {
if (showDepartment && affiliation.department !== null)
return `${affiliation.organization} [${affiliation.department}]`;
else
return affiliation.organization;
}
}
toObject() {
return {
orcid: this._orcid,
ORCiDJSON: this._ORCiDJSON,
familyName: this._familyName,
givenNames: this._givenNames,
employments: this._employments.map(employment => JSON.stringify(employment.toObject())),
preferredLocale: this._preferredLocale,
biography: this._biography,
emails: this._emails,
keywords: this._keywords,
researcherUrls: this._researcherUrls,
country: this._country,
};
}
}
class Employment {
constructor(startDate, endDate, organization, department) {
this.startDate = startDate;
this.endDate = endDate;
this.organization = organization;
this.department = department;
}
static fromJSON(serialized) {
const data = JSON.parse(serialized);
const startDate = new Date(data.startDate);
const endDate = data.endDate === null ? null : new Date(data.endDate);
return new Employment(startDate, endDate, data.organization, data.department);
}
toObject() {
return {
startDate: this.startDate,
endDate: this.endDate,
organization: this.organization,
department: this.department,
};
}
}
class FoldableItem {
constructor(priority, keyTitle, value, keyTooltip, keyLink, valueRegex, renderDynamically) {
this._estimatedTypePriority = 0;
this._priority = priority;
this._keyTitle = keyTitle;
this._value = value;
this._keyTooltip = keyTooltip;
this._keyLink = keyLink;
this._valueRegex = valueRegex;
this._renderDynamically = renderDynamically !== undefined ? renderDynamically : true;
this._estimatedTypePriority = this._renderDynamically ? 0 : Number.MAX_SAFE_INTEGER;
}
get priority() {
return this._priority;
}
get keyTitle() {
return this._keyTitle;
}
get value() {
return this._value;
}
get keyTooltip() {
return this._keyTooltip;
}
get keyLink() {
return this._keyLink;
}
get valueRegex() {
return this._valueRegex;
}
get renderDynamically() {
return this._renderDynamically;
}
get estimatedTypePriority() {
return this._estimatedTypePriority;
}
isValidValue() {
return this._valueRegex ? this._valueRegex.test(this._value) : true;
}
equals(other) {
return (this._keyTitle === other._keyTitle &&
this._value === other._value &&
this._keyTooltip === other._keyTooltip &&
this._keyLink === other._keyLink &&
this._renderDynamically === other._renderDynamically);
}
}
class FoldableAction {
constructor(priority, title, link, style) {
this._priority = priority;
this._title = title;
this._link = link;
this._style = style;
}
get priority() {
return this._priority;
}
get title() {
return this._title;
}
get link() {
return this._link;
}
get style() {
return this._style;
}
equals(other) {
return this._priority === other._priority && this._title === other._title && this._link === other._link && this._style === other._style;
}
}
class ORCIDType extends GenericIdentifierType {
constructor() {
super(...arguments);
this.affiliationAt = new Date(Date.now());
this.showAffiliation = true;
}
get data() {
var _a, _b;
return JSON.stringify((_b = (_a = this._orcidInfo) === null || _a === void 0 ? void 0 : _a.toObject()) !== null && _b !== void 0 ? _b : {});
}
quickCheck() {
return ORCIDInfo.isORCiD(this.value);
}
async hasMeaningfulInformation() {
this._orcidInfo = await ORCIDInfo.getORCiDInfo(this.value);
return this._orcidInfo.ORCiDJSON !== undefined;
}
async init(data) {
if (data !== undefined) {
this._orcidInfo = ORCIDInfo.fromJSON(data);
console.debug('reload ORCIDInfo from data', this._orcidInfo);
}
else {
this._orcidInfo = await ORCIDInfo.getORCiDInfo(this.value);
console.debug('load ORCIDInfo from API', this._orcidInfo);
}
if (this.settings) {
for (const i of this.settings) {
switch (i['name']) {
case 'affiliationAt':
this.affiliationAt = new Date(i['value']);
break;
case 'showAffiliation':
this.showAffiliation = i['value'] === true || i['value'] === 'true' || i['value'] === '1';
break;
}
}
}
this.items.push(new FoldableItem(0, 'ORCiD', this._orcidInfo.orcid, 'ORCiD is a free service for researchers to distinguish themselves by creating a unique personal identifier.', 'https://orcid.org', undefined, false));
try {
const givenNames = this._orcidInfo.givenNames;
if (givenNames) {
new FoldableItem(2, 'Given Names', this._orcidInfo.givenNames.toString(), 'The given names of the person.');
}
}
catch (e) {
console.log('Failed to obtain given names from ORCiD record.', e);
}
this.actions.push(new FoldableAction(0, 'Open ORCiD profile', `https://orcid.org/${this._orcidInfo.orcid}`, 'primary'));
try {
const affiliations = this._orcidInfo.getAffiliationsAt(new Date(Date.now()));
for (const data of affiliations) {
const affiliation = this._orcidInfo.getAffiliationAsString(data);
if (affiliation !== undefined && affiliation.length > 2)
this.items.push(new FoldableItem(50, 'Current Affiliation', affiliation, 'The current affiliation of the person.', undefined, undefined, false));
}
}
catch (e) {
console.log('Failed to obtain affiliations from ORCiD record.', e);
}
if (this._orcidInfo.getAffiliationsAt(this.affiliationAt) !== this._orcidInfo.getAffiliationsAt(new Date()) &&
this.affiliationAt.toLocaleDateString('en-US') !== new Date().toLocaleDateString('en-US')) {
const affiliationsThen = this._orcidInfo.getAffiliationsAt(this.affiliationAt);
for (const data of affiliationsThen) {
const affiliation = this._orcidInfo.getAffiliationAsString(data);
if (affiliation !== undefined && affiliation.length > 2)
this.items.push(new FoldableItem(49, 'Affiliation at ' +
this.affiliationAt.toLocaleDateString('en-US', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
}), affiliation, 'The affiliation of the person at the given date.', undefined, undefined, false));
}
}
if (this._orcidInfo.emails) {
const primary = this._orcidInfo.emails.filter(email => email.primary)[0];
const other = this._orcidInfo.emails.filter(email => !email.primary);
if (primary) {
this.items.push(new FoldableItem(20, 'Primary E-Mail address', primary.email, 'The primary e-mail address of the person.'));
this.actions.push(new FoldableAction(0, 'Send E-Mail', `mailto:${primary.email}`, 'secondary'));
}
if (other.length > 0)
this.items.push(new FoldableItem(70, 'Other E-Mail addresses', other.map(email => email.email).join(', '), 'All other e-mail addresses of the person.'));
if (this._orcidInfo.preferredLocale)
this.items.push(new FoldableItem(25, 'Preferred Language', this._orcidInfo.preferredLocale, 'The preferred locale/language of the person.'));
for (const url of this._orcidInfo.researcherUrls) {
this.items.push(new FoldableItem(100, url.name.length > 1 ? url.name : 'User-specified reference', url.url, 'A link to a website specified by the person.'));
}
if (this._orcidInfo.keywords.length > 50)
this.items.push(new FoldableItem(60, 'Keywords', this._orcidInfo.keywords.map(keyword => keyword.content).join(', '), 'Keywords specified by the person.', undefined, undefined, false));
if (this._orcidInfo.biography)
this.items.push(new FoldableItem(200, 'Biography', this._orcidInfo.biography, 'The biography of the person.', undefined, undefined, false));
if (this._orcidInfo.country)
this.items.push(new FoldableItem(30, 'Country', this._orcidInfo.country, 'The country of the person.'));
}
}
isResolvable() {
return this._orcidInfo.ORCiDJSON !== undefined;
}
renderPreview() {
return (index.h("span", { class: `inline-flex flex-nowrap items-baseline font-mono min-w-0 max-w-full ${this.isDarkMode ? 'text-gray-200' : ''}` }, index.h("svg", { version: "1.1", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 256 256", class: 'mr-1 h-4 flex-none px-0.5 self-center' }, index.h("style", { type: "text/css" }, `.st0{fill:#A6CE39;}`, `.st1{fill:#FFFFFF;}`), index.h("path", { class: "st0", d: "M256,128c0,70.7-57.3,128-128,128C57.3,256,0,198.7,0,128C0,57.3,57.3,0,128,0C198.7,0,256,57.3,256,128z" }), index.h("g", null, index.h("path", { class: "st1", d: "M86.3,186.2H70.9V79.1h15.4v48.4V186.2z" }), index.h("path", { class: "st1", d: "M108.9,79.1h41.6c39.6,0,57,28.3,57,53.6c0,27.5-21.5,53.6-56.8,53.6h-41.8V79.1z M124.3,172.4h24.5\n c34.9,0,42.9-26.5,42.9-39.7c0-21.5-13.7-39.7-43.7-39.7h-23.7V172.4z" }), index.h("path", { class: "st1", d: "M88.7,56.8c0,5.5-4.5,10.1-10.1,10.1c-5.6,0-10.1-4.6-10.1-10.1c0-5.6,4.5-10.1,10.1-10.1\n C84.2,46.7,88.7,51.3,88.7,56.8z" }))), index.h("span", { class: `min-w-0 overflow-hidden text-ellipsis whitespace-nowrap ${this.isDarkMode ? 'text-gray-200' : ''}` }, this._orcidInfo.familyName, ", ", this._orcidInfo.givenNames, ' ', this.showAffiliation && this._orcidInfo.getAffiliationsAt(new Date()).length > 0
? `(${this._orcidInfo.getAffiliationAsString(this._orcidInfo.getAffiliationsAt(new Date())[0], false)}${this._orcidInfo.getAffiliationsAt(this.affiliationAt).length > 0 &&
this.affiliationAt.toLocaleDateString() !== new Date().toLocaleDateString() &&
this._orcidInfo.getAffiliationsAt(this.affiliationAt)[0].organization !== this._orcidInfo.getAffiliationsAt(new Date())[0].organization
? `, then: ${this._orcidInfo.getAffiliationsAt(this.affiliationAt)[0].organization}`
: ''})`
: '')));
}
getSettingsKey() {
return 'ORCIDType';
}
}
class HandleType extends GenericIdentifierType {
constructor() {
super(...arguments);
this._parts = [];
}
get data() {
var _a, _b;
return JSON.stringify((_b = (_a = this._pidRecord) === null || _a === void 0 ? void 0 : _a.toObject()) !== null && _b !== void 0 ? _b : {});
}
quickCheck() {
return PID.isPID(this.value);
}
async hasMeaningfulInformation() {
const pid = PID.getPIDFromString(this.value);
this._pidRecord = await pid.resolve();
return this._pidRecord.values.length > 0;
}
async init(data) {
if (data !== undefined) {
this._pidRecord = PIDRecord.fromJSON(data);
this._parts = await Promise.all([
{
text: this._pidRecord.pid.prefix,
nextExists: true,
},
{
text: this._pidRecord.pid.suffix,
nextExists: false,
},
]);
console.debug('reload PIDRecord from data', this._pidRecord);
}
else {
const pid = PID.getPIDFromString(this.value);
this._parts = [
{
text: pid.prefix,
nextExists: true,
},
{
text: pid.suffix,
nextExists: false,
},
];
if (!this._pidRecord) {
this._pidRecord = await pid.resolve();
console.debug('load PIDRecord from API', this._pidRecord);
}
else {
console.debug('using cached PIDRecord');
}
}
for (const value of this._pidRecord.values) {
if (value.type instanceof PIDDataType) {
this.items.push(new FoldableItem(0, value.type.name, value.data.value, value.type.description, value.type.redirectURL, value.type.regex));
}
}
this.actions.push(new FoldableAction(0, 'Open in FAIR-DOscope', `https://kit-data-manager.github.io/fairdoscope/?pid=${this._pidRecord.pid.toString()}`, 'primary'));
this.actions.push(new FoldableAction(0, 'View in Handle.net registry', `https://hdl.handle.net/${this._pidRecord.pid.toString()}`, 'secondary'));
return;
}
isResolvable() {
return this._pidRecord.values.length > 0;
}
renderPreview() {
return (index.h("span", { class: 'font-mono font-bold align-baseline' }, this._parts.map(element => {
return (index.h("span", null, index.h("color-highlight", { text: element.text }), element.nextExists ? index.h("span", { class: `mx-0.5` }, "/") : ''));
})));
}
getSettingsKey() {
return 'HandleType';
}
}
class DOI {
constructor(doi) {
this._doi = doi
.replace(/^https?:\/\/doi\.org\//i, '')
.replace(/^https?:\/\/dx\.doi\.org\//i, '')
.replace(/^doi:/i, '')
.replace(/\/+$/, '')
.replace(/\.+$/, '')
.trim();
}
get doi() {
return this._doi;
}
static isDOI(text) {
const cleaned = text
.replace(/^https?:\/\/doi\.org\//i, '')
.replace(/^https?:\/\/dx\.doi\.org\//i, '')
.replace(/^doi:/i, '');
return /^10\.\d{4,9}\/[-._;()/:A-Za-z0-9]+$/.test(cleaned);
}
static getDOIFromString(doi) {
if (!DOI.isDOI(doi))
throw new Error('Invalid DOI format');
return new DOI(doi);
}
static fromJSON(serialized) {
const data = JSON.parse(serialized);
return new DOI(data.doi);
}
toURL() {
return `https://doi.org/${this._doi}`;
}
toString() {
return this._doi;
}
toObject() {
return {
doi: this._doi,
};
}
}
const userFriendlyResourceType = {
'article': '📰 Article',
'book': '📚 Book',
'chapter': '📖 Chapter',
'software': '💻 Software',
'dataset': '📊 Dataset',
'image': '🖼️ Image',
'video': '🎥 Video',
'audio': '🎵 Audio',
'presentation': '🧑🏫 Presentation',
'preprint': '📝 Preprint',
'thesis': '🎓 Thesis',
'report': '📋 Report',
'standard': '📜 Standard',
'workflow': '🔄 Workflow',
'model': '🧮 Model',
'paper': '📄 Paper',
'journal': '📰 Journal',
'code': '💻 Code',
'institution': '🏛️ Institution',
'conferencepaper': '🎤 Conference Paper',
'database': '🗄️ Database',
'other': '❓ Other',
'journalarticle': '📄 Journal Article',
'proceedingsarticle': '🎤 Proceedings Article',
'reportseries': '📋 Report Series',
'bookchapter': '📖 Book Chapter',
'monograph': '📚 Monograph',
'editedbook': '📚 Edited Book',
'reportpaper': '📋 Report Paper',
};
function beautifyResourceType(resourceType) {
const normalized = resourceType
.toLowerCase()
.replace('_', '').replace('-', '');
return userFriendlyResourceType[normalized] || resourceType;
}
const DataCiteLogo = () => (index.h("svg", { version: "1.1", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 130 103.8", class: 'h-4' }, index.h("defs", null, index.h("style", null, `.cls-1{fill:#00b1e2;}`, `.cls-2{fill:#243b54;}`)), index.h("path", { class: "cls-1", d: "M5,73.38c.86.16,1.63.32,2.65.47,43.5,8.64,108.26-2.8,116.59-23.89,6.54-17.05-30-29.11-72.62-27.63a13.94,13.94,0,0,0-2.49.15c22.73,2.26,43.2,11.29,35,25.38C75.2,63.27,37.3,73.54,5,73.38" }), index.h("path", { class: "cls-2", d: "M100.27,75.53C92.72,121.3,53.18,94,43.84,62.15,30.3,29.07,42.36-13.43,76.22,11.48c-28-12.85-31,24.36-19,50.82,10,22.11,31.59,36.35,42,13.54.47-.15.86-.15,1-.31" })));
const CrossRefLogo = () => (index.h("svg", { version: "1.1", xmlns: "http://www.w3.org/2000/svg", x: "0px", y: "0px", class: 'h-4', viewBox: "0 0 65.400002 95.199999" }, index.h("style", { type: "text/css" }, `.st0{fill:#3EB1C8;}`, `.st1{fill:#D8D2C4;}`, `.st2{fill:#4F5858;}`, `.st3{fill:#FFC72C;}`, `.st4{fill:#EF3340;}`), index.h("g", { id: "g16", transform: "translate(-69.570409,-17.62496)" }, index.h("polygon", { class: "st0", points: "111.8,66.8 135.4,59 177.2,73.3 111.8,95.5 ", id: "polygon1", transform: "translate(-42.229591,17.32496)" }), index.h("polygon", { class: "st1", points: "111.8,51.2 135.4,59 177.2,44.6 153.6,36.8 ", id: "polygon2", transform: "translate(-42.229591,17.32496)" }), index.h("polygon", { class: "st2", points: "135.4,59 177.2,44.6 177.2,73.3 ", id: "polygon3", transform: "translate(-42.229591,17.32496)" }), index.h("polygon", { class: "st3", points: "177.2,29 153.6,36.8 111.8,22.5 177.2,0.3 ", id: "polygon4", transform: "translate(-42.229591,17.32496)" }), index.h("polygon", { class: "st4", points: "153.6,36.8 111.8,51.2 111.8,22.5 ", id: "polygon5", transform: "translate(-42.229591,17.32496)" }))));
class DataCiteInfo {
constructor(doi, response) {
var _a;
this._doi = doi;
this._rawMetadata = response;
this._attributes = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.attributes) || {};
}
get title() {
const titles = this._attributes.titles || [];
const mainTitle = titles.find((t) => {
if (typeof t === 'string')
return true;
return !t.titleType || t.titleType === 'Title';
});
if (typeof mainTitle === 'string')
return mainTitle;
return (mainTitle === null || mainTitle === void 0 ? void 0 : mainTitle.title) || '';
}
get creators() {
const creators = this._attributes.creators || [];
return creators.map((creator) => {
var _a, _b;
if (typeof creator === 'string') {
return { name: creator };
}
const result = {
name: creator.name || '',
givenName: creator.givenName,
familyName: creator.familyName,
};
if (!result.name && creator.givenName && creator.familyName) {
result.name = `${creator.givenName} ${creator.familyName}`;
}
else if (!result.name) {
result.name = creator.givenName || creator.familyName || '';
}
const orcidIdentifier = (_a = creator.nameIdentifiers) === null || _a === void 0 ? void 0 : _a.find((id) => { var _a; return ((_a = id.nameIdentifierScheme) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'orcid'; });
if (orcidIdentifier === null || orcidIdentifier === void 0 ? void 0 : orcidIdentifier.nameIdentifier) {
result.orcid = orcidIdentifier.nameIdentifier
.replace(/^https?:\/\/orcid\.org\//i, '')
.replace(/^orcid:/i, '');
}
if (creator.affiliation && creator.affiliation.length > 0) {
const primaryAffiliation = creator.affiliation[0];
result.affiliation = primaryAffiliation.name;
const rorIdentifier = primaryAffiliation.affiliationIdentifier;
if (rorIdentifier && ((_b = primaryAffiliation.affiliationIdentifierScheme) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'ror') {
result.ror = rorIdentifier.replace(/^https?:\/\/ror\.org\//i, '');
}
}
return result;
}).filter((c) => c.name);
}
get correspondingAuthor() {
var _a, _b;
const contributors = this._attributes.contributors || [];
const corresponding = contributors.find((c) => { var _a; return ((_a = c.contributorType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'contactperson'; });
if (!corresponding)
return undefined;
const result = {
name: corresponding.name || '',
givenName: corresponding.givenName,
familyName: corresponding.familyName,
isCorresponding: true,
};
if (!result.name && corresponding.givenName && corresponding.familyName) {
result.name = `${corresponding.givenName} ${corresponding.familyName}`;
}
const orcidIdentifier = (_a = corresponding.nameIdentifiers) === null || _a === void 0 ? void 0 : _a.find((id) => { var _a; return ((_a = id.nameIdentifierScheme) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'orcid'; });
if (orcidIdentifier === null || orcidIdentifier === void 0 ? void 0 : orcidIdentifier.nameIdentifier) {
result.orcid = orcidIdentifier.nameIdentifier
.replace(/^https?:\/\/orcid\.org\//i, '')
.replace(/^orcid:/i, '');
}
if (corresponding.affiliation && corresponding.affiliation.length > 0) {
const primaryAffiliation = corresponding.affiliation[0];
result.affiliation = primaryAffiliation.name;
const rorIdentifier = primaryAffiliation.affiliationIdentifier;
if (rorIdentifier && ((_b = primaryAffiliation.affiliationIdentifierScheme) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'ror') {
result.ror = rorIdentifier.replace(/^https?:\/\/ror\.org\//i, '');
}
}
return result;
}
get publisher() {
return this._attributes.publisher;
}
get publicationDate() {
const dates = this._attributes.dates || [];
const issued = dates.find((d) => { var _a; return ((_a = d.dateType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'issued'; });
if (issued === null || issued === void 0 ? void 0 : issued.date)
return issued.date;
if (this._attributes.publicationYear) {
return `${this._attributes.publicationYear}`;
}
return undefined;
}
get resourceType() {
var _a;
return ((_a = this._attributes.types) === null || _a === void 0 ? void 0 : _a.resourceTypeGeneral) || this._attributes.resourceTypeGeneral;
}
get resourceTypeSpecific() {
var _a;
return (_a = this._attributes.types) === null || _a === void 0 ? void 0 : _a.resourceType;
}
get description() {
const descriptions = this._attributes.descriptions || [];
const abstract = descriptions.find((d) => {
var _a;
if (typeof d === 'string')
return true;
return ((_a = d.descriptionType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'abstract' || !d.descriptionType;
});
if (typeof abstract === 'string')
return abstract;
return abstract === null || abstract === void 0 ? void 0 : abstract.description;
}
get url() {
return this._attributes.url || this._doi.toURL();
}
get subjects() {
const subjects = this._attributes.subjects || [];
return subjects.map((s) => {
if (typeof s === 'string')
return s;
return s.subject || '';
}).filter(Boolean);
}
get rawMetadata() {
return this._rawMetadata;
}
static async fetch(doi) {
const apiUrl = `https://api.datacite.org/dois/${encodeURIComponent(doi.toString())}`;
try {
const response = (await cachedFetch(apiUrl, {
headers: {
Accept: 'application/vnd.api+json',
},
}));
if (!response || !response.data)
return null;
return new DataCiteInfo(doi, response);
}
catch (error) {
console.debug('DataCite API error:', error);
return null;
}
}
static fromObject(doiObj, obj) {
return new DataCiteInfo(doiObj, obj.rawMetadata);
}
generateItems() {
const items = [];
let index = 10;
if (this.title) {
items.push(new FoldableItem(index++, 'Title', this.title, 'The title of the resource.', undefined, undefined, false));
}
const correspondingAuthor = this.correspondingAuthor;
if (correspondingAuthor) {
items.push(new FoldableItem(index++, 'Corresponding Author', correspondingAuthor.orcid || `${correspondingAuthor.name}${correspondingAuthor.affiliation ? ` (${correspondingAuthor.affiliation})` : ''}`, `This field indicates the first author of the resource, who is often the corresponding author.`));
}
const creators = this.creators;
creators.forEach((creator, idx) => {
if (idx === 0 && correspondingAuthor)
return;
items.push(new FoldableItem(index++, `Author`, creator.orcid || `${creator.name}${creator.affiliation ? ` (${creator.affiliation})` : ''}`, 'A creator/author of the resource.', creator.orcid ? `https://orcid.org/${creator.orcid}` : undefined));
});
if (this.publisher) {
items.push(new FoldableItem(index++, 'Publisher', this.publisher, 'The publisher of the resource.'));
}
if (this.publicationDate) {
items.push(new FoldableItem(index++, 'Publication Date', this.publicationDate, 'The publication date in ISO 8601 format.'));
}
if (this.resourceType) {
const displayType = this.resourceTypeSpecific || this.resourceType;
items.push(new FoldableItem(index++, 'Resource Type', beautifyResourceType(displayType), 'The type of the resource.'));
}
if (this.description) {
items.push(new FoldableItem(index++, 'Description', this.description, 'The description or abstract of the resource.', undefined, undefined, false));
}
this.subjects.forEach((subject) => {
items.push(new FoldableItem(index++, 'Subject', subject, 'A subject area or keyword associated with the resource.'));
});
return items;
}
toObject() {
return {
doi: JSON.stringify(this._doi.toObject()),
rawMetadata: this._rawMetadata,
};
}
}
var CitationStyle;
(function (CitationStyle) {
CitationStyle["APA"] = "APA";
CitationStyle["CHICAGO"] = "Chicago";
CitationStyle["IEEE"] = "IEEE";
CitationStyle["HARVARD"] = "Harvard";
CitationStyle["ANGLIA_RUSKIN"] = "Anglia Ruskin";
})(CitationStyle || (CitationStyle = {}));
function formatCitationPreview(title, creators, year, style = CitationStyle.APA) {
if (!title || creators.length === 0) {
return { citation: title || 'Untitled', tooltip: title || 'Untitled' };
}
const firstAuthor = creators[0];
const authorCount = creators.length;
switch (style) {
case CitationStyle.APA:
return {
citation: formatAPA(firstAuthor, authorCount, title, year),
tooltip: formatAPA(firstAuthor, authorCount, title, year),
};
case CitationStyle.CHICAGO:
return {
citation: formatChicago(firstAuthor, authorCount, title, year),
tooltip: formatChicago(firstAuthor, authorCount, title, year),
};
case CitationStyle.IEEE:
return {
citation: formatIEEE(firstAuthor, authorCount, title, year),
tooltip: formatIEEE(firstAuthor, authorCount, title, year),
};
case CitationStyle.HARVARD:
return {
citation: formatHarvard(firstAuthor, authorCount, title, year),
tooltip: formatHarvard(firstAuthor, authorCount, title, year),
};
case CitationStyle.ANGLIA_RUSKIN:
return {
citation: formatAngliaRuskin(firstAuthor, authorCount, title, year),
tooltip: formatAngliaRuskin(firstAuthor, authorCount, title, year),
};
default:
return {
citation: formatAPA(firstAuthor, authorCount, title, year),
tooltip: formatAPA(firstAuthor, authorCount, title, year),
};
}
}
function formatAPA(author, count, title, year, truncate) {
const authorName = author.familyName || author.name.split(' ').pop() || author.name;
const etAl = count > 1 ? ' et al.' : '';
const yearPart = year ? ` (${year.split('-')[0]})` : '';
truncateTitle(title, 60);
return `${authorName}${etAl}${yearPart}. ${title}`;
}
function formatChicago(author, count, title, year, truncate) {
const authorName = author.familyName || author.name.split(' ').pop() || author.name;
const firstName = author.givenName || author.name.split(' ')[0] || '';
const etAl = count > 1 ? ' et al.' : '';
const yearPart = year ? ` ${year.split('-')[0]}.` : '';
truncateTitle(title, 60);
return `${authorName}, ${firstName}${etAl}.${yearPart} "${title}"`;
}
function formatIEEE(author, count, title, year, truncate) {
const initial = author.givenName ? author.givenName.charAt(0) + '.' : '';
const authorName = author.familyName || author.name.split(' ').pop() || author.name;
const etAl = count > 1 ? ' et al.' : '';
truncateTitle(title, 60);
const yearPart = year ? `, ${year.split('-')[0]}` : '';
return `${initial} ${authorName}${etAl}, "${title}"${yearPart}`;
}
function formatHarvard(author, count, title, year, truncate) {
const authorName = author.familyName || author.name.split(' ').pop() || author.name;
const initials = author.givenName
? author.givenName.split(' ').map(n => n.charAt(0) + '.').join('')
: '';
const etAl = count > 1 ? ' et al.' : '';
const yearPart = year ? `, ${year.split('-')[0]}` : '';
truncateTitle(title, 60);
return `${authorName}, ${initials}${etAl}${yearPart}. ${title}`;
}
function formatAngliaRuskin(author, count, title, year, truncate) {
const authorName = (author.familyName || author.name.split(' ').pop() || author.name).toUpperCase();
const etAl = count > 1 ? ' ET AL.' : '';
const yearPart = year ? ` ${year.split('-')[0]}.` : '';
truncateTitle(title, 60);
return `${authorName}${etAl}${yearPart} ${title}`;
}
function truncateTitle(title, maxLength) {
if (title.length <= maxLength)
return title;
const truncated = title.substring(0, maxLength);
const lastSpace = truncated.lastIndexOf(' ');
if (lastSpace > maxLength * 0.7) {
return truncated.substring(0, lastSpace) + '...';
}
return truncated + '...';
}
function getDefaultCitationStyle() {
return CitationStyle.APA;
}
function getCitationStyleFromSettings(settings) {
if (!settings)
return getDefaultCitationStyle();
const styleSetting = settings.find(s => s.name === 'citationStyle');
if (!styleSetting)
return getDefaultCitationStyle();
const styleValue = String(styleSetting.value).toUpperCase();
switch (styleValue) {
case 'APA':
return CitationStyle.APA;
case 'CHICAGO':
return CitationStyle.CHICAGO;
case 'IEEE':
return CitationStyle.IEEE;
case 'HARVARD':
return CitationStyle.HARVARD;
case 'ANGLIA_RUSKIN':
return CitationStyle.ANGLIA_RUSKIN;
default:
return getDefaultCitationStyle();
}
}
class DataCiteDOIType extends GenericIdentifierType {
get data() {
var _a, _b;
return JSON.stringify((_b = (_a = this._dataCiteInfo) === null || _a === void 0 ? void 0 : _a.toObject()) !== null && _b !== void 0 ? _b : {});
}
quickCheck() {
return DOI.isDOI(this.value);
}
async hasMeaningfulInformation() {
this._doi = DOI.getDOIFromString(this.value);
this._dataCiteInfo = await DataCiteInfo.fetch(this._doi);
return this._dataCiteInfo !== null && this._dataCiteInfo.title !== '';
}
async init(data) {
if (data !== undefined) {
this._dataCiteInfo = DataCiteInfo.fromObject(this._doi, JSON.parse(data));
}
else {
this._doi = DOI.getDOIFromString(this.value);
this._dataCiteInfo = await DataCiteInfo.fetch(this._doi);
}
if (!this._dataCiteInfo)
return;
this.items.push(new FoldableItem(0, 'DOI', this._doi.toString(), 'The DOI used for this resource. Digital Object Identifier is a persistent identifier for academic and research resources.', 'https://www.doi.org/', undefined, false));
this.items.push(new FoldableItem(1, 'Metadata Source', 'DataCite', 'Metadata provided by DataCite', 'https://datacite.org'));
const metadataItems = this._dataCiteInfo.generateItems();
this.items.push(...metadataItems);
if (this._dataCiteInfo.url) {
this.actions.push(new FoldableAction(0, 'Open Resource', this._dataCiteInfo.url, 'primary'));
}
this.actions.push(new FoldableAction(1, 'Resolve DOI', this._doi.toURL(), 'secondary'));
this.actions.push(new FoldableAction(2, 'View DataCite Metadata', `https://api.datacite.org/dois/${encodeURIComponent(this._doi.toString())}`, 'secondary'));
}
isResolvable() {
return this._dataCiteInfo !== null && this._dataCiteInfo.title !== '';
}
renderPreview() {
var _a, _b, _c;
const citationStyle = getCitationStyleFromSettings(this.settings);
const creators = ((_a = this._dataCiteInfo) === null || _a === void 0 ? void 0 : _a.creators) || [];
const year = (_b = this._dataCiteInfo) === null || _b === void 0 ? void 0 : _b.publicationDate;
const { citation, tooltip } = formatCitationPreview(((_c = this._dataCiteInfo) === null || _c === void 0 ? void 0 : _c.title) || '', creators, year, citationStyle);
return (index.h("span", { class: `inline-flex flex-nowrap items-baseline font-mono min-w-0 max-w-full ${this.isDarkMode ? 'text-gray-200' : ''}` }, index.h("span", { class: 'flex-none px-0.5 h-4 self-center' }, DataCiteLogo()), index.h("span", { class: 'min-w-0 pl-2 overflow-hidden text-ellipsis whitespace-nowrap', title: tooltip }, citation)));
}
getSettingsKey() {
return 'DataCiteDOIType';
}
}
class CrossRefInfo {
constructor(doi, response, type = 'work') {
this._doi = doi;
this._type = type;
this._rawMetadata = response;
if (type === 'funder') {
this._message = {};
}
else {
const cr = response;
this._message = typeof cr.message === 'string' ? {} : cr.message || {};
}
}
get type() {
return this._type;
}
get title() {
if (this._type === 'funder') {
const funderResponse = this._rawMetadata;
const funderMsg = typeof funderResponse.message === 'string' ? null : funderResponse.message;
return (funderMsg === null || funderMsg === void 0 ? void 0 : funderMsg.name) || '';
}
const titles = this._message.title || [];
return titles[0] || '';
}
get creators() {
if (this._type === 'funder')
return [];
const authors = this._message.author || [];
return authors.map((author) => {
const result = {
name: author.name || '',
givenName: author.given,
familyName: author.family,
};
if (!result.name) {
if (author.given && author.family) {
result.name = `${author.given} ${author.family}`;
}
else {
result.name = author.given || author.family || '';
}
}
if (author.ORCID) {
result.orcid = author.ORCID.replace(/^https?:\/\/orcid\.org\//i, '');
}
if (author.affiliation && author.affiliation.length > 0) {
result.affiliation = author.affiliation[0].name;
}
return result;
}).filter((c) => c.name);
}
get correspondingAuthor() {
if (this._type === 'funder')
return undefined;
const authors = this._message.author || [];
const firstAuthor = authors.find((a) => a.sequence === 'first') || authors[0];
if (!firstAuthor)
return undefined;
const result = {
name: firstAuthor.name || '',
givenName: firstAuthor.given,
familyName: firstAuthor.family,
isCorresponding: true,
};
if (!result.name) {
if (firstAuthor.given && firstAuthor.family) {
result.name = `${firstAuthor.given} ${firstAuthor.family}`;
}
else {
result.name = firstAuthor.given || firstAuthor.family || '';
}
}
if (firstAuthor.ORCID) {
result.orcid = firstAuthor.ORCID.replace(/^https?:\/\/orcid\.org\//i, '');
}
if (firstAuthor.affiliation && firstAuthor.affiliation.length > 0) {
result.affiliation = firstAuthor.affiliation[0].name;
}
return result;
}
get publisher() {
if (this._type === 'funder')
return undefined;
return this._message.publisher;
}
get publicationDate() {
var _a;
if (this._type === 'funder') {
const funderResponse = this._rawMetadata;
const funderMsg = typeof funderResponse.message === 'string' ? null : funderResponse.message;
if (funderMsg === null || funderMsg === void 0 ? void 0 : funderMsg.established) {
return `${funderMsg.established}`;
}
return undefined;
}
const dateObj = this._message.issued || this._message.published || this._message.created;
if (!((_a = dateObj === null || dateObj === void 0 ? void 0 : dateObj['date-parts']) === null || _a === void 0 ? void 0 : _a[0]))
return undefined;
const parts = dateObj['date-parts'][0];
const year = parts[0];
const month = parts[1];
const day = parts[2];
if (year && month && day) {
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
}
else if (year && month) {
return `${year}-${String(month).p