147 lines
4.4 KiB
JavaScript
147 lines
4.4 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
// Set to true to see debug output in the browser console
|
|
var DEBUG = false;
|
|
|
|
var usageCache = {};
|
|
var pendingRequests = {};
|
|
var debounceTimer = null;
|
|
|
|
function log() {
|
|
if (DEBUG) console.log.apply(console, ['[image-usage]'].concat(Array.prototype.slice.call(arguments)));
|
|
}
|
|
|
|
/**
|
|
* Fetch usage data for a Kirby page ID (slug format, e.g. "community-led/inside").
|
|
* Returns a promise resolving to { filename: boolean }.
|
|
*/
|
|
function fetchUsage(pageId) {
|
|
if (pageId in usageCache) return Promise.resolve(usageCache[pageId]);
|
|
if (pageId in pendingRequests) return pendingRequests[pageId];
|
|
|
|
// Kirby panel encodes / as + in URLs
|
|
var encoded = encodeURIComponent(pageId.replace(/\//g, '+'));
|
|
log('Fetching usage for page:', pageId, '→', '/api/smart-forests/image-usage/' + encoded);
|
|
|
|
var csrf = (window.panel && window.panel.system && window.panel.system.csrf) ? window.panel.system.csrf : false;
|
|
|
|
var promise = fetch('/api/smart-forests/image-usage/' + encoded, {
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
'x-csrf': csrf,
|
|
'x-fiber': 'true'
|
|
}
|
|
})
|
|
.then(function (r) {
|
|
if (!r.ok) {
|
|
log('API error', r.status, r.statusText);
|
|
return {};
|
|
}
|
|
return r.json();
|
|
})
|
|
.then(function (data) {
|
|
log('Usage data for', pageId, data);
|
|
usageCache[pageId] = data;
|
|
delete pendingRequests[pageId];
|
|
return data;
|
|
})
|
|
.catch(function (err) {
|
|
log('Fetch failed:', err);
|
|
usageCache[pageId] = {};
|
|
delete pendingRequests[pageId];
|
|
return {};
|
|
});
|
|
|
|
pendingRequests[pageId] = promise;
|
|
return promise;
|
|
}
|
|
|
|
/**
|
|
* Apply (or refresh) a usage badge on a file item element.
|
|
* Skips DOM writes if the element is already in the correct state,
|
|
* which prevents the MutationObserver from re-triggering indefinitely.
|
|
*/
|
|
function applyBadge(item, used) {
|
|
var wantedState = used === true ? 'used' : used === false ? 'unused' : null;
|
|
var currentState = item.dataset.sfUsage || null;
|
|
|
|
// Already correct — skip to avoid triggering MutationObserver
|
|
if (currentState === wantedState) return;
|
|
|
|
// Remove existing badge
|
|
item.querySelectorAll('.sf-usage-dot').forEach(function (el) { el.remove(); });
|
|
item.classList.remove('sf-is-used', 'sf-is-unused');
|
|
delete item.dataset.sfUsage;
|
|
|
|
if (!wantedState) return;
|
|
|
|
item.dataset.sfUsage = wantedState;
|
|
item.classList.add('sf-is-' + wantedState);
|
|
|
|
var dot = document.createElement('span');
|
|
dot.className = 'sf-usage-dot sf-usage-dot--' + wantedState;
|
|
dot.setAttribute('title', used ? 'Utilisée dans le contenu' : 'Non utilisée dans le contenu');
|
|
|
|
var imageArea = item.querySelector('.k-item-image, .k-item-icon');
|
|
if (imageArea) {
|
|
imageArea.appendChild(dot);
|
|
} else {
|
|
item.prepend(dot);
|
|
}
|
|
}
|
|
|
|
var IMAGE_EXT = /\.(jpe?g|png|gif|webp|svg|avif)$/i;
|
|
|
|
/**
|
|
* Scan current DOM for file items, group by page, fetch usage, paint badges.
|
|
*
|
|
* File items in the panel have data-id = "{kirby-page-slug}/{filename}"
|
|
* e.g. "community-led-forest-technologies/inside/image.jpg"
|
|
*/
|
|
function run() {
|
|
// All k-item elements that have a data-id ending in an image extension
|
|
var allItems = document.querySelectorAll('.k-item[data-id]');
|
|
log('Total .k-item[data-id] found:', allItems.length);
|
|
|
|
var byPage = {};
|
|
allItems.forEach(function (item) {
|
|
var dataId = item.getAttribute('data-id') || '';
|
|
if (!IMAGE_EXT.test(dataId)) return; // skip non-image items
|
|
|
|
var parts = dataId.split('/');
|
|
if (parts.length < 2) return;
|
|
|
|
var filename = parts[parts.length - 1];
|
|
var pageId = parts.slice(0, -1).join('/');
|
|
|
|
if (!byPage[pageId]) byPage[pageId] = [];
|
|
byPage[pageId].push({ item: item, filename: filename });
|
|
});
|
|
|
|
var pageCount = Object.keys(byPage).length;
|
|
log('Pages with image items:', pageCount, byPage);
|
|
|
|
if (!pageCount) return;
|
|
|
|
Object.keys(byPage).forEach(function (pageId) {
|
|
fetchUsage(pageId).then(function (usage) {
|
|
byPage[pageId].forEach(function (entry) {
|
|
applyBadge(entry.item, usage[entry.filename]);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function schedule() {
|
|
clearTimeout(debounceTimer);
|
|
debounceTimer = setTimeout(run, 450);
|
|
}
|
|
|
|
new MutationObserver(schedule).observe(document.body, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
|
|
schedule();
|
|
})();
|