forgejo/web_src/js/webcomponents/lazy-webc.js
oliverpool 8f28cdefe0
Some checks are pending
/ release (push) Waiting to run
testing-integration / test-unit (push) Waiting to run
testing-integration / test-sqlite (push) Waiting to run
testing-integration / test-mariadb (v10.6) (push) Waiting to run
testing-integration / test-mariadb (v11.8) (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
feat(ui): add switch between formats when previewing CITATION.{cff,bib} files (#9103)
See #8222 for context (loosely related to #4595).

## Implemented changes

The conversion logic is kept in the frontend and the related npm libraries are lazy-loaded (unchanged).

### Show some tabs on the preview of the `CITATION.*` file to switch between the formats:

![image](/attachments/be02656f-d906-4191-aa84-d666ee5a90ba)
![image](/attachments/240384e3-dec8-4f02-94e6-261143193541)

### Convert the "Cite repository" to a simple link to the citation file

So that this change can be considered non-breaking

## Current state (before this PR)

The last non-test call of `git.Blob.GetBlobContent` is made to retrieve the content of an eventual CITATION file.
This is available in the `...` menu near the clone URL:
![image](/attachments/ef79128d-ee3f-4e43-a74d-a00e4dcfe6b4)
And is displayed as a popup:

![image](/attachments/7aa930f9-0766-47b9-8145-cbebb5b051b0)

Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/9103
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: oliverpool <git@olivier.pfad.fr>
Co-committed-by: oliverpool <git@olivier.pfad.fr>
2025-11-14 14:39:20 +01:00

72 lines
2.3 KiB
JavaScript

// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
import {onDomReady} from '../utils/dom.js';
/**
* Lazy-load the promise (making it a singleton).
* @param {()=>Promise} newPromise Promise factory.
* @returns {()=>Promise} Singleton promise
*/
function lazyPromise(newPromise) {
/** @type {Promise?} */
let p;
return () => {
p ??= newPromise();
return p;
};
}
// the following web components will only be loaded if present in the page (to reduce the bundle size for infrequently used components)
const loadableComponents = {
'model-viewer': lazyPromise(() => {
return import(/* webpackChunkName: "model-viewer" */ '@google/model-viewer');
}),
'pdf-object': lazyPromise(() => {
return import(/* webpackChunkName: "pdf-object" */ './pdf-object.js');
}),
'citation-information': lazyPromise(() => {
return import(/* webpackChunkName: "citation-information" */ './citation-information.js');
}),
};
/**
* Replace elt with an element having the given tag.
* @param {HTMLElement} elt The element to replace.
* @param {string} name The tagName of the new element.
*/
function replaceTag(elt, name) {
const successor = document.createElement(name);
// Move the children to the successor
while (elt.firstChild) {
successor.append(elt.firstChild);
}
// Copy the attributes to the successor
for (let index = elt.attributes.length - 1; index >= 0; --index) {
successor.attributes.setNamedItem(elt.attributes[index].cloneNode());
}
// Replace elt with the successor
elt.parentNode.replaceChild(successor, elt);
}
onDomReady(() => {
// The lazy-webc component will replace itself with an element of the type given in the attribute tag.
// This seems to be the best way without having to create a global mutationObserver.
// See https://codeberg.org/forgejo/forgejo/pulls/8510 for discussion.
window.customElements.define(
'lazy-webc',
class extends HTMLElement {
connectedCallback() {
const name = this.getAttribute('tag');
if (loadableComponents[name]) {
loadableComponents[name]().finally(() => {
replaceTag(this, name);
});
} else {
console.error('lazy-webc: unknown webcomponent:', name);
replaceTag(this, name); // still replace it, maybe it was eagerly defined
}
}
},
);
});