Release v2.18.0: template default content
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 2m2s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 31s

This commit is contained in:
lzstealth committed 2026-10-24 18:03:38 +01:00
1 parent 48e8f3eb4b
commit 24f1603b43
54 files changed
+1421 -151

No files matched your search

+50
View File
@@ -105,6 +105,56 @@ test('playlist group colours differ, survive reorder, and clear on ungrouped sli
assert.equal(firstMember.style['--playlist-group-bg'], undefined);
});
test('schedule rules use the same native AdminLTE icons as slide regions', () => {
const root = path.join(__dirname, '..', 'src', 'web');
const sources = [
fs.readFileSync(path.join(root, 'views', 'signage', 'playlists', 'schedule-rule-card.hbs'), 'utf8'),
fs.readFileSync(path.join(root, 'public', 'js', 'playlists', 'playlist-schedule.js'), 'utf8'),
fs.readFileSync(path.join(root, 'public', 'js', 'slides', 'slide-form-regions.js'), 'utf8')
];
for (const source of sources) {
assert.match(source, /<i class="bi bi-dash-lg" aria-hidden="true" data-lte-icon="collapse"><\/i>/);
assert.match(source, /<i class="bi bi-plus-lg" aria-hidden="true" data-lte-icon="expand"><\/i>/);
assert.doesNotMatch(source, /data-schedule-rule-collapse-icon|getCollapseRuleIcon/);
}
});
test('schedule rule accessibility and drafts follow completed collapse and expand events', () => {
const source = fs.readFileSync(path.join(__dirname, '..', 'src', 'web', 'public', 'js', 'playlists', 'playlist-schedule.js'), 'utf8');
const syncSource = source.match(/function syncRuleCollapseButtonState\(card\) \{[\s\S]*?\n \}/)[0];
const handlerSource = source.match(/function handleRuleCollapseComplete\(event\) \{[\s\S]*?\n \}/)[0];
const listeners = {};
const attributes = {};
const label = { textContent: '' };
const button = {
setAttribute(name, value) { attributes[name] = value; },
querySelector() { return label; }
};
let collapsed = false;
let persisted = 0;
const card = {
classList: { contains() { return collapsed; } },
closest() { return card; }
};
const sandbox = {
getCollapseRuleButton() { return button; },
getRuleNumberNode() { return { textContent: '1' }; },
persistScheduleDraft() { persisted += 1; },
scheduleRuleList: { addEventListener(name, handler) { listeners[name] = handler; } }
};
const registrations = source.match(/ scheduleRuleList.addEventListener\('collapsed\.lte\.card-widget'[^\n]+\n scheduleRuleList.addEventListener\('expanded\.lte\.card-widget'[^\n]+/)[0];
require('node:vm').runInNewContext(syncSource + '\n' + handlerSource + '\n' + registrations, sandbox);
for (const isCollapsed of [true, false, true]) {
collapsed = isCollapsed;
listeners[isCollapsed ? 'collapsed.lte.card-widget' : 'expanded.lte.card-widget']({ target: card });
assert.equal(attributes['aria-expanded'], String(!isCollapsed));
assert.equal(attributes['aria-label'], (isCollapsed ? 'Expand' : 'Collapse') + ' rule 1');
assert.equal(label.textContent, attributes['aria-label']);
}
assert.equal(persisted, 3);
});
test('removing a playlist group removes all of its member rows', () => {
const source = fs.readFileSync(path.join(__dirname, '..', 'src', 'web', 'public', 'js', 'playlists', 'playlist-schedule.js'), 'utf8');
const functionSource = source.match(/function removePlaylistGroup\(header\) \{[\s\S]*?\n \}/)[0];