Mojolicious-Plugin-Fondation-Setup
view release on metacpan or search on metacpan
share/templates/setup/plugins.html.ep view on Meta::CPAN
<div class="alert alert-info"><%= l('No Fondation plugins found on MetaCPAN.') %></div>
% } else {
<p class="text-muted text-center py-5"><%= l('Fetching plugin list from MetaCPAN...') %></p>
% }
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var cbs = document.querySelectorAll('.plugin-cb');
var all = {};
cbs.forEach(function(cb) { all[cb.value] = cb; });
function depsOf(cb) {
return (cb.getAttribute('data-deps') || '').split(',').filter(Boolean);
}
function dependants(mod) {
var d = [];
cbs.forEach(function(cb) {
if (depsOf(cb).indexOf(mod) !== -1 && cb.checked) d.push(cb.value);
});
return d;
}
// Color-code plugin items: green = directly selected, blue = dependency, yellow = required
function updateHighlights() {
cbs.forEach(function(cb) {
var label = cb.closest('.plugin-item');
if (!label) return;
label.classList.remove('plugin-selected', 'plugin-dependency', 'plugin-required-notice');
if (cb.checked) {
var reqBy = dependants(cb.value);
var isDep = reqBy.length > 0 && !cb.hasAttribute('data-user-selected');
if (isDep || reqBy.length > 0) {
label.classList.add(cb.hasAttribute('data-user-selected') ? 'plugin-selected' : 'plugin-dependency');
} else {
label.classList.add('plugin-selected');
}
}
});
}
// Mark checkboxes clicked directly by the user
cbs.forEach(function(cb) {
cb.addEventListener('click', function(e) {
if (e.target === cb) {
if (cb.checked) cb.setAttribute('data-user-selected', '1');
else cb.removeAttribute('data-user-selected');
}
});
cb.addEventListener('change', function() {
if (cb.checked) {
depsOf(cb).forEach(function(d) {
var el = all[d];
if (el && !el.checked) { el.checked = true; el.removeAttribute('data-user-selected'); }
});
} else {
cb.removeAttribute('data-user-selected');
// Uncheck all transitive dependencies (updateLocks will re-check any still needed)
var cascade = [cb.value];
var visited = {};
while (cascade.length) {
var v = cascade.shift(), el = all[v];
if (!el || visited[v]) continue;
visited[v] = true;
depsOf(el).forEach(function(d) {
var de = all[d];
if (de && de.checked) { de.checked = false; de.removeAttribute('data-user-selected'); }
cascade.push(d);
});
}
}
updateAll();
});
cb.addEventListener('click', function(e) {
if (!cb.checked) return;
var req = dependants(cb.value);
if (req.length) { e.preventDefault(); alert('Required by: ' + req.join(', ')); }
});
});
function updateAll() {
updateLocks();
updateHighlights();
}
function updateLocks() {
cbs.forEach(function(cb) {
var req = dependants(cb.value);
if (req.length && !cb.checked) cb.checked = true;
});
}
// Init: mark preselected as user-selected
cbs.forEach(function(cb) {
if (cb.checked) cb.setAttribute('data-user-selected', '1');
});
updateAll();
});
</script>
( run in 1.622 second using v1.01-cache-2.11-cpan-e7c6538aa59 )