UNPKG

@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.

209 lines (208 loc) 7.44 kB
/*! * * 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. * */ const WRAPPER_CLASS = 'pid-auto-detect-wrapper'; const WRAPPER_ATTR = 'data-pid-auto-detected'; export function replaceMatches(textNode, matches, config) { var _a; const records = []; const parent = textNode.parentNode; if (!parent) return records; const fullText = textNode.textContent || ''; const sortedMatches = [...matches] .sort((a, b) => a.start - b.start) .filter((match, i, arr) => i === 0 || match.start >= arr[i - 1].end); const fragment = document.createDocumentFragment(); let lastIndex = 0; for (const match of sortedMatches) { if (match.start > lastIndex) { fragment.appendChild(document.createTextNode(fullText.substring(lastIndex, match.start))); } const wrapper = document.createElement('span'); wrapper.className = WRAPPER_CLASS; wrapper.setAttribute(WRAPPER_ATTR, 'true'); wrapper.style.display = 'inline'; const originalSpan = document.createElement('span'); originalSpan.textContent = match.value; wrapper.appendChild(originalSpan); const pidComponent = document.createElement('pid-component'); pidComponent.setAttribute('value', match.value); if (config.renderers && config.renderers.length > 0) { pidComponent.setAttribute('renderers', JSON.stringify(config.renderers)); } pidComponent.setAttribute('fallback-to-all', String((_a = config.fallbackToAll) !== null && _a !== void 0 ? _a : true)); pidComponent.style.cssText = 'visibility:hidden;position:absolute;width:0;height:0;overflow:hidden;pointer-events:none;'; pidComponent.setAttribute('aria-hidden', 'true'); applyConfig(pidComponent, config); wrapper.appendChild(pidComponent); const observer = createSwapObserver(originalSpan, pidComponent, wrapper); fragment.appendChild(wrapper); records.push({ wrapper, originalText: match.value, precedingTextNode: null, followingTextNode: null, pidComponent, observer, originalSpan, }); lastIndex = match.end; } if (lastIndex < fullText.length) { fragment.appendChild(document.createTextNode(fullText.substring(lastIndex))); } parent.replaceChild(fragment, textNode); return records; } function applyConfig(pidComponent, config) { var _a; if (config.settings) { const settingsStr = typeof config.settings === 'string' ? config.settings : JSON.stringify(config.settings); pidComponent.setAttribute('settings', settingsStr); } if (config.darkMode) { pidComponent.setAttribute('dark-mode', config.darkMode); } if (config.levelOfSubcomponents !== undefined) { pidComponent.setAttribute('level-of-subcomponents', String(config.levelOfSubcomponents)); } if (config.itemsPerPage !== undefined) { pidComponent.setAttribute('items-per-page', String(config.itemsPerPage)); } pidComponent.setAttribute('emphasize-component', String((_a = config.emphasizeComponent) !== null && _a !== void 0 ? _a : false)); if (config.showTopLevelCopy !== undefined) { pidComponent.setAttribute('show-top-level-copy', String(config.showTopLevelCopy)); } if (config.defaultTTL !== undefined) { pidComponent.setAttribute('default-t-t-l', String(config.defaultTTL)); } } function createSwapObserver(originalSpan, pidComponent, wrapper) { let swapped = false; let pollTimer = null; let safetyTimer = null; function cleanup() { if (pollTimer) { clearInterval(pollTimer); pollTimer = null; } if (safetyTimer) { clearTimeout(safetyTimer); safetyTimer = null; } observer.disconnect(); } function handleError() { swapped = true; cleanup(); pidComponent.remove(); unwrapToText(wrapper, originalSpan.textContent || ''); } function handleSuccess() { swapped = true; cleanup(); originalSpan.style.display = 'none'; originalSpan.setAttribute('aria-hidden', 'true'); pidComponent.style.cssText = ''; pidComponent.removeAttribute('aria-hidden'); } function trySwap() { if (swapped) return; const shadowRoot = pidComponent.shadowRoot; if (!shadowRoot) return; const allElements = shadowRoot.querySelectorAll('*'); if (allElements.length === 0) return; const hostInShadow = shadowRoot.querySelector('[class*="relative"]'); if (hostInShadow) { const hostStyle = hostInShadow.style; if (hostStyle && hostStyle.display === 'none') { handleError(); return; } } const errorEl = shadowRoot.querySelector('[role="alert"]'); if (errorEl) { handleError(); return; } const spinner = shadowRoot.querySelector('.animate-spin'); if (spinner) return; const preview = shadowRoot.querySelector('[role="button"], pid-collapsible, a[href], copy-button, color-highlight, locale-visualization'); if (preview) { handleSuccess(); return; } if (allElements.length > 2 && !spinner && !errorEl) { handleSuccess(); return; } } const observer = new MutationObserver(trySwap); pollTimer = setInterval(() => { if (swapped) { cleanup(); return; } if (pidComponent.shadowRoot) { try { observer.observe(pidComponent.shadowRoot, { childList: true, subtree: true, attributes: true, }); } catch (_a) { } trySwap(); } }, 100); safetyTimer = setTimeout(() => { if (!swapped) { trySwap(); if (!swapped) { handleError(); } } }, 15000); observer.observe(pidComponent, { attributes: true, childList: true, }); return observer; } function unwrapToText(wrapper, text) { const parent = wrapper.parentNode; if (!parent) return; const textNode = document.createTextNode(text); parent.replaceChild(textNode, wrapper); parent.normalize(); } export function restoreOriginalText(records) { for (const record of records) { record.observer.disconnect(); unwrapToText(record.wrapper, record.originalText); } } //# sourceMappingURL=TextReplacer.js.map