(function () { var favoriteCodes = []; var codeLinks = {}; function getPageId(root) { var value = root && root.getAttribute ? root.getAttribute('data-page-id') : ''; var pageId = parseInt(value || '0', 10); if (!Number.isFinite(pageId) || pageId <= 0) { var stateNode = root ? root.querySelector('.ansico-diagnosekoder__page-state') : null; if (stateNode) { try { var state = JSON.parse(stateNode.textContent || '{}'); pageId = parseInt(state.pageId || '0', 10); } catch (error) {} } } if ((!Number.isFinite(pageId) || pageId <= 0) && typeof AnsicoDiagnosekoderConfig.resultsPageId !== 'undefined') { pageId = parseInt(AnsicoDiagnosekoderConfig.resultsPageId || '0', 10); } if ((!Number.isFinite(pageId) || pageId <= 0) && document.body) { var match = (document.body.className || '').match(/(?:^|\s)page-id-(\d+)(?:\s|$)/); if (match) { pageId = parseInt(match[1], 10); } } return Number.isFinite(pageId) && pageId > 0 ? pageId : 0; } function preloadPageState(root) { if (!root || !root.getAttribute) { return; } var stateNode = root.querySelector('.ansico-diagnosekoder__page-state'); if (stateNode) { try { var state = JSON.parse(stateNode.textContent || '{}'); if (Array.isArray(state.favorites)) { favoriteCodes = state.favorites.map(normalizeCode); } if (state.links && typeof state.links === 'object') { codeLinks = {}; Object.keys(state.links).forEach(function (code) { codeLinks[normalizeCode(code)] = state.links[code]; }); } if (state.pageId && root.getAttribute('data-page-id') !== String(state.pageId)) { root.setAttribute('data-page-id', String(state.pageId)); } return; } catch (error) {} } var favoritesRaw = root.getAttribute('data-page-favorites') || '[]'; var linksRaw = root.getAttribute('data-page-links') || '{}'; try { var parsedFavorites = JSON.parse(favoritesRaw); if (Array.isArray(parsedFavorites)) { favoriteCodes = parsedFavorites.map(normalizeCode); } } catch (error) {} try { var parsedLinks = JSON.parse(linksRaw); if (parsedLinks && typeof parsedLinks === 'object') { codeLinks = {}; Object.keys(parsedLinks).forEach(function (code) { codeLinks[normalizeCode(code)] = parsedLinks[code]; }); } } catch (error) {} } function debounce(fn, delay) { var timer; return function () { var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); }; } function escapeHtml(str) { return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function escapeRegExp(str) { return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } function normalizeCode(code) { return String(code || '').replace(/\s+/g, '').toUpperCase(); } function highlightText(text, query) { var safeText = escapeHtml(text); var trimmedQuery = String(query || '').trim(); if (!trimmedQuery) { return safeText; } var parts = trimmedQuery.split(/\s+/).filter(Boolean); if (!parts.length) { return safeText; } var pattern = parts.map(escapeRegExp).join('|'); return safeText.replace(new RegExp('(' + pattern + ')', 'gi'), '$1'); } function getCopyIcon() { return ''; } function getStarIcon(isActive) { if (isActive) { return ''; } return ''; } function getPlusIcon() { return ''; } function getMinusIcon() { return ''; } function isFavorite(code) { return favoriteCodes.indexOf(normalizeCode(code)) !== -1; } function getLinkedUrl(code, fallback) { var normalized = normalizeCode(code); if (normalized && typeof codeLinks[normalized] === 'string' && codeLinks[normalized]) { return codeLinks[normalized]; } return fallback || ''; } function setTemporaryLabel(button, label, duration) { var originalLabel = button.getAttribute('data-label-default') || button.getAttribute('aria-label') || ''; button.setAttribute('aria-label', label); button.classList.add('is-feedback-visible'); window.setTimeout(function () { button.setAttribute('aria-label', originalLabel); button.classList.remove('is-feedback-visible'); }, duration || 1400); } function pulseButton(button) { button.classList.remove('is-pressed'); void button.offsetWidth; button.classList.add('is-pressed'); window.setTimeout(function () { button.classList.remove('is-pressed'); }, 220); } function copyText(value, button) { var successLabel = button.getAttribute('data-label-success') || button.getAttribute('aria-label') || ''; var errorLabel = button.getAttribute('data-label-error') || button.getAttribute('aria-label') || ''; pulseButton(button); if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(value).then(function () { setTemporaryLabel(button, successLabel, 1400); }).catch(function () { setTemporaryLabel(button, errorLabel, 1400); }); return; } try { var temp = document.createElement('textarea'); temp.value = value; temp.setAttribute('readonly', 'readonly'); temp.style.position = 'absolute'; temp.style.left = '-9999px'; document.body.appendChild(temp); temp.select(); document.execCommand('copy'); document.body.removeChild(temp); setTemporaryLabel(button, successLabel, 1400); } catch (error) { setTemporaryLabel(button, errorLabel, 1400); } } function searchInternalContent(query) { if (!AnsicoDiagnosekoderConfig.contentSearchUrl) { return Promise.resolve([]); } var url = AnsicoDiagnosekoderConfig.contentSearchUrl + '?q=' + encodeURIComponent(query) + '&limit=8'; return fetch(url, { credentials: 'same-origin', headers: { 'X-WP-Nonce': AnsicoDiagnosekoderConfig.nonce }, cache: 'no-store' }).then(function (response) { if (!response.ok) { throw new Error('Internal content search failed'); } return response.json(); }).then(function (data) { return Array.isArray(data.results) ? data.results : []; }); } function ensureLinkModal() { var existing = document.getElementById('ansico-diagnosekoder-link-modal'); if (existing) { return existing; } var wrapper = document.createElement('div'); wrapper.id = 'ansico-diagnosekoder-link-modal'; wrapper.className = 'ansico-diagnosekoder__modal'; wrapper.setAttribute('hidden', 'hidden'); wrapper.innerHTML = '' + '
' + ''; document.body.appendChild(wrapper); return wrapper; } function openLinkModal(code, currentUrl) { var modal = ensureLinkModal(); var titleNode = modal.querySelector('.ansico-diagnosekoder__modal-title'); var labels = modal.querySelectorAll('.ansico-diagnosekoder__modal-label'); var hintNode = modal.querySelector('.ansico-diagnosekoder__modal-hint'); var codeInput = modal.querySelector('#ansico-diagnosekoder-link-modal-code'); var urlInput = modal.querySelector('#ansico-diagnosekoder-link-modal-url'); var searchInput = modal.querySelector('#ansico-diagnosekoder-link-modal-search'); var resultsNode = modal.querySelector('.ansico-diagnosekoder__modal-search-results'); var cancelButton = modal.querySelector('[data-modal-cancel="1"]'); var saveButton = modal.querySelector('[data-modal-save="1"]'); var closeButtons = modal.querySelectorAll('[data-modal-close="1"]'); var activeSearchToken = 0; titleNode.textContent = currentUrl ? AnsicoDiagnosekoderConfig.strings.linkModalTitleEdit : AnsicoDiagnosekoderConfig.strings.linkModalTitleAdd; labels[0].textContent = AnsicoDiagnosekoderConfig.strings.linkModalCodeLabel; labels[1].textContent = AnsicoDiagnosekoderConfig.strings.linkModalUrlLabel; labels[2].textContent = AnsicoDiagnosekoderConfig.strings.linkModalSearchLabel; hintNode.textContent = AnsicoDiagnosekoderConfig.strings.linkModalHint; cancelButton.textContent = AnsicoDiagnosekoderConfig.strings.linkModalCancel; saveButton.textContent = AnsicoDiagnosekoderConfig.strings.linkModalSave; codeInput.value = code || ''; urlInput.value = currentUrl || ''; urlInput.placeholder = AnsicoDiagnosekoderConfig.strings.linkPromptDefault || 'https://'; searchInput.value = ''; searchInput.placeholder = AnsicoDiagnosekoderConfig.strings.linkModalSearchPlaceholder; resultsNode.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.linkModalSearchEmpty) + '

'; modal.removeAttribute('hidden'); document.body.classList.add('ansico-diagnosekoder-modal-open'); function closeModal() { modal.setAttribute('hidden', 'hidden'); document.body.classList.remove('ansico-diagnosekoder-modal-open'); saveButton.onclick = null; cancelButton.onclick = null; closeButtons.forEach(function (button) { button.onclick = null; }); searchInput.oninput = null; document.removeEventListener('keydown', onKeyDown); } function onKeyDown(event) { if (event.key === 'Escape') { closeModal(); } } function renderSearchResults(items) { if (!items.length) { resultsNode.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.linkModalSearchNone) + '

'; return; } var html = ''; resultsNode.innerHTML = html; resultsNode.querySelectorAll('.ansico-diagnosekoder__modal-result-button').forEach(function (button) { button.addEventListener('click', function () { urlInput.value = button.getAttribute('data-url') || ''; }); }); } searchInput.oninput = debounce(function () { var query = searchInput.value.trim(); activeSearchToken += 1; var token = activeSearchToken; if (!query) { resultsNode.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.linkModalSearchEmpty) + '

'; return; } resultsNode.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.loading) + '

'; searchInternalContent(query).then(function (items) { if (token !== activeSearchToken) { return; } renderSearchResults(items); }).catch(function () { resultsNode.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.linkSearchError) + '

'; }); }, 180); var resolver; var promise = new Promise(function (resolve) { resolver = resolve; }); saveButton.onclick = function () { resolver(String(urlInput.value || '').trim()); closeModal(); }; cancelButton.onclick = function () { resolver(null); closeModal(); }; closeButtons.forEach(function (button) { button.onclick = function () { resolver(null); closeModal(); }; }); document.addEventListener('keydown', onKeyDown); window.setTimeout(function () { urlInput.focus(); urlInput.select(); }, 0); return promise; } function fetchPageState(pageId) { if (!pageId || !AnsicoDiagnosekoderConfig.pageStateUrl) { return Promise.resolve({ favorites: favoriteCodes, links: codeLinks, page_id: pageId || 0 }); } var url = AnsicoDiagnosekoderConfig.pageStateUrl + '?page_id=' + encodeURIComponent(pageId) + '&_ansico_ts=' + Date.now(); return fetch(url, { credentials: 'same-origin', cache: 'no-store' }).then(function (response) { if (!response.ok) { throw new Error('Page state failed'); } return response.json(); }).then(function (data) { syncClientCollections(data || {}); return data || {}; }).catch(function () { return { favorites: favoriteCodes, links: codeLinks, page_id: pageId || 0 }; }); } function mergeAndSortResults(results) { var merged = (Array.isArray(results) ? results : []).map(function (item, index) { var normalizedCode = normalizeCode(item.code); var favorite = isFavorite(normalizedCode) || !!item.is_favorite; var linkedUrl = getLinkedUrl(normalizedCode, item.linked_url || ''); return Object.assign({}, item, { is_favorite: favorite, linked_url: linkedUrl, _normalized_code: normalizedCode, _render_index: index }); }); merged.sort(function (a, b) { if (!!a.is_favorite !== !!b.is_favorite) { return a.is_favorite ? -1 : 1; } return a._render_index - b._render_index; }); return merged; } function renderResults(container, results, query) { if (!results.length) { container.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.noResults) + '

'; return; } var sortedResults = mergeAndSortResults(results); var html = ''; container.innerHTML = html; } function getQueryParam(name) { var params = new URLSearchParams(window.location.search); return params.get(name) || ''; } function getSelectorEscaped(value) { if (window.CSS && typeof window.CSS.escape === 'function') { return window.CSS.escape(value); } return String(value).replace(/"/g, '\\"'); } function updateFavoriteButtons(code, isFav, pageId) { var normalizedCode = normalizeCode(code); var selector = '.ansico-diagnosekoder__favorite-button[data-code="' + getSelectorEscaped(normalizedCode) + '"]'; if (pageId) { selector = '.ansico-diagnosekoder[data-page-id="' + getSelectorEscaped(String(pageId)) + '"] ' + selector; } var buttons = document.querySelectorAll(selector); buttons.forEach(function (button) { var label = isFav ? AnsicoDiagnosekoderConfig.strings.removeFavorite : AnsicoDiagnosekoderConfig.strings.addFavorite; button.classList.toggle('is-active', isFav); button.setAttribute('aria-pressed', isFav ? 'true' : 'false'); button.setAttribute('aria-label', label); button.setAttribute('data-label-default', label); button.innerHTML = getStarIcon(isFav); var item = button.closest('.ansico-diagnosekoder__item'); if (item) { item.classList.toggle('is-favorite', isFav); item.setAttribute('data-is-favorite', isFav ? '1' : '0'); } }); } function updateLinkButtons(code, url) { var normalizedCode = normalizeCode(code); var buttons = document.querySelectorAll('.ansico-diagnosekoder__link-button[data-code="' + getSelectorEscaped(normalizedCode) + '"]'); var hasLink = !!url; buttons.forEach(function (button) { var label = hasLink ? AnsicoDiagnosekoderConfig.strings.removeLink : AnsicoDiagnosekoderConfig.strings.addLink; button.classList.toggle('is-active', hasLink); button.setAttribute('aria-label', label); button.setAttribute('data-label-default', label); button.setAttribute('data-current-url', url || ''); button.setAttribute('title', hasLink ? AnsicoDiagnosekoderConfig.strings.removeLinkIcon : AnsicoDiagnosekoderConfig.strings.addLinkIcon); button.innerHTML = hasLink ? getMinusIcon() : getPlusIcon(); var item = button.closest('.ansico-diagnosekoder__item'); if (item) { item.classList.toggle('has-link', hasLink); item.setAttribute('data-has-link', hasLink ? '1' : '0'); } }); } function syncClientCollections(data) { if (Array.isArray(data.favorites)) { favoriteCodes = data.favorites.map(normalizeCode); } if (data.links && typeof data.links === 'object') { codeLinks = {}; Object.keys(data.links).forEach(function (code) { codeLinks[normalizeCode(code)] = data.links[code]; }); } } function toggleFavorite(code, button, refreshCallback, pageId) { fetch(AnsicoDiagnosekoderConfig.favoritesUrl, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': AnsicoDiagnosekoderConfig.nonce }, body: JSON.stringify({ code: normalizeCode(code), page_id: pageId || 0 }) }).then(function (response) { if (!response.ok) { throw new Error('Favorite toggle failed'); } return response.json(); }).then(function (data) { syncClientCollections(data); pulseButton(button); updateFavoriteButtons(code, !!data.is_favorite, pageId || 0); if (typeof refreshCallback === 'function') { refreshCallback(); } }).catch(function () { setTemporaryLabel(button, AnsicoDiagnosekoderConfig.strings.favoriteError, 1400); }); } function saveCodeLink(code, url, button, refreshCallback, pageId) { fetch(AnsicoDiagnosekoderConfig.linksUrl, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': AnsicoDiagnosekoderConfig.nonce }, body: JSON.stringify({ code: normalizeCode(code), url: url, page_id: pageId || 0 }) }).then(function (response) { if (!response.ok) { throw new Error('Link save failed'); } return response.json(); }).then(function (data) { syncClientCollections(data); pulseButton(button); updateLinkButtons(code, data.url || ''); setTemporaryLabel(button, AnsicoDiagnosekoderConfig.strings.linkSaved, 1200); if (typeof refreshCallback === 'function') { refreshCallback(); } }).catch(function () { setTemporaryLabel(button, AnsicoDiagnosekoderConfig.strings.linkError, 1400); }); } function removeCodeLink(code, button, refreshCallback, pageId) { var url = AnsicoDiagnosekoderConfig.linksUrl + '?code=' + encodeURIComponent(normalizeCode(code)) + '&page_id=' + encodeURIComponent(pageId || 0); fetch(url, { method: 'DELETE', credentials: 'same-origin', headers: { 'X-WP-Nonce': AnsicoDiagnosekoderConfig.nonce } }).then(function (response) { if (!response.ok) { throw new Error('Link removal failed'); } return response.json(); }).then(function (data) { syncClientCollections(data); pulseButton(button); updateLinkButtons(code, ''); setTemporaryLabel(button, AnsicoDiagnosekoderConfig.strings.linkRemoved, 1200); if (typeof refreshCallback === 'function') { refreshCallback(); } }).catch(function () { setTemporaryLabel(button, AnsicoDiagnosekoderConfig.strings.linkError, 1400); }); } function initResultsBlock(root) { preloadPageState(root); var input = root.querySelector('.ansico-diagnosekoder__input'); var results = root.querySelector('.ansico-diagnosekoder__results'); var hasData = root.getAttribute('data-has-data') === '1'; if (!input || !results || !hasData) { return; } var runSearch = function () { var query = input.value.trim(); if (!query) { results.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.empty) + '

'; return; } results.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.loading) + '

'; var pageId = getPageId(root); var url = AnsicoDiagnosekoderConfig.restUrl + '?q=' + encodeURIComponent(query) + '&limit=50&page_id=' + encodeURIComponent(pageId) + '&_ansico_ts=' + Date.now(); fetchPageState(pageId).then(function () { return fetch(url, { credentials: 'same-origin', cache: 'no-store' }); }) .then(function (response) { if (!response.ok) { throw new Error('Request failed'); } return response.json(); }) .then(function (data) { syncClientCollections(data); if ( (!Array.isArray(data.favorites) || !data.favorites.length) && (!data.links || !Object.keys(data.links).length) && (!favoriteCodes.length && !Object.keys(codeLinks).length) ) { preloadPageState(root); } renderResults(results, data.results || [], query); }) .catch(function () { results.innerHTML = '

' + escapeHtml(AnsicoDiagnosekoderConfig.strings.error) + '

'; }); }; var debouncedSearch = debounce(runSearch, 200); input.addEventListener('input', debouncedSearch); results.addEventListener('click', function (event) { var copyButton = event.target.closest('.ansico-diagnosekoder__copy-button'); if (copyButton) { copyText(copyButton.getAttribute('data-copy-value') || '', copyButton); return; } var favoriteButton = event.target.closest('.ansico-diagnosekoder__favorite-button'); if (favoriteButton) { toggleFavorite(favoriteButton.getAttribute('data-code') || '', favoriteButton, runSearch, getPageId(root)); return; } var linkButton = event.target.closest('.ansico-diagnosekoder__link-button'); if (linkButton) { var code = linkButton.getAttribute('data-code') || ''; var currentUrl = linkButton.getAttribute('data-current-url') || ''; if (currentUrl) { removeCodeLink(code, linkButton, runSearch, getPageId(root)); return; } openLinkModal(code, currentUrl).then(function (enteredUrl) { if (enteredUrl === null) { return; } enteredUrl = String(enteredUrl).trim(); if (!enteredUrl) { return; } saveCodeLink(code, enteredUrl, linkButton, runSearch, getPageId(root)); }); } }); var stateNode = root.querySelector('.ansico-diagnosekoder__page-state'); var hasServerRenderedResults = false; if (stateNode) { try { var initialState = JSON.parse(stateNode.textContent || '{}'); hasServerRenderedResults = !!(initialState && initialState.hasInitialResults); } catch (error) {} } fetchPageState(getPageId(root)).then(function () { var presetQuery = getQueryParam('q'); if (presetQuery) { input.value = presetQuery; if (!hasServerRenderedResults) { runSearch(); } } }); } function initSearchOnlyBlock(form) { form.addEventListener('submit', function (event) { var input = form.querySelector('.ansico-diagnosekoder__input'); var query = input ? input.value.trim() : ''; var resultsUrl = form.getAttribute('data-results-url') || AnsicoDiagnosekoderConfig.resultsUrl || ''; if (!resultsUrl) { event.preventDefault(); var message = form.querySelector('.ansico-diagnosekoder__message'); if (message) { message.textContent = AnsicoDiagnosekoderConfig.strings.missingResultsUrl; } return; } if (!query) { event.preventDefault(); return; } event.preventDefault(); var url = new URL(resultsUrl, window.location.origin); url.searchParams.set('q', query); window.location.href = url.toString(); }); } document.addEventListener('DOMContentLoaded', function () { var resultsBlocks = document.querySelectorAll('.wp-block-ansico-diagnosekoder.ansico-diagnosekoder'); resultsBlocks.forEach(initResultsBlock); var searchOnlyBlocks = document.querySelectorAll('.wp-block-ansico-diagnosekoder-soegefelt.ansico-diagnosekoder--search-only'); searchOnlyBlocks.forEach(initSearchOnlyBlock); }); })();