const fs = require('fs'); const path = require('path'); // General-purpose helpers used across the admin UI. function registerGeneralHelpers(Handlebars) { Handlebars.registerHelper('eq', function (left, right) { return left === right; }); Handlebars.registerHelper('gt', function (left, right) { return left > right; }); Handlebars.registerHelper('lt', function (left, right) { return left < right; }); Handlebars.registerHelper('json', function (value) { return new Handlebars.SafeString(JSON.stringify(value).replace(/', ``, hasSecondaryActions ? `` : '', hasSecondaryActions ? '
' : '', ]; if (cancel.url) { parts.push(`${escape(cancel.label)}`); } if (showDelete && (deleteAction.disabled || resolvedDeleteUrl)) { const deleteActionAttr = resolvedDeleteUrl && !resolvedDeleteFormId ? ` data-delete-action-url="${escape(resolvedDeleteUrl)}"` : ''; const deleteFormAttr = resolvedDeleteFormId ? ` form="${escape(resolvedDeleteFormId)}"` : ''; const confirmAttr = deleteAction.confirmMessage ? ` data-confirm-message="${escape(deleteAction.confirmMessage)}"` : ''; const titleAttr = deleteAction.disabled && deleteAction.title ? ` title="${escape(deleteAction.title)}"` : ''; parts.push(``); } parts.push(''); return new Handlebars.SafeString(parts.join('')); }); } // Shared partials are registered once at startup. function registerPartials(Handlebars, viewsRoot) { Handlebars.registerPartial('modal-shell', fs.readFileSync(path.join(viewsRoot, 'shared', 'modal-shell.hbs'), 'utf8')); Handlebars.registerPartial('media-picker-modal', fs.readFileSync(path.join(viewsRoot, 'shared', 'media-picker-modal.hbs'), 'utf8')); Handlebars.registerPartial('table-pagination', fs.readFileSync(path.join(viewsRoot, 'shared', 'table', 'table-pagination.hbs'), 'utf8')); Handlebars.registerPartial('playlists/form', fs.readFileSync(path.join(viewsRoot, 'signage', 'playlists', 'form.hbs'), 'utf8')); Handlebars.registerPartial('signage/playlists/slide-row', fs.readFileSync(path.join(viewsRoot, 'signage', 'playlists', 'slide-row.hbs'), 'utf8')); Handlebars.registerPartial('signage/playlists/schedule-rule-card', fs.readFileSync(path.join(viewsRoot, 'signage', 'playlists', 'schedule-rule-card.hbs'), 'utf8')); Handlebars.registerPartial('signage/templates/animation-advanced-modal', fs.readFileSync(path.join(viewsRoot, 'signage', 'templates', 'animation-advanced-modal.hbs'), 'utf8')); Handlebars.registerPartial('data-sources/api-sources/form', fs.readFileSync(path.join(viewsRoot, 'data-sources', 'api-sources', 'form.hbs'), 'utf8')); Handlebars.registerPartial('data-sources/rss-feeds/form', fs.readFileSync(path.join(viewsRoot, 'data-sources', 'rss-feeds', 'form.hbs'), 'utf8')); Handlebars.registerPartial('data-sources/weather/preview', fs.readFileSync(path.join(viewsRoot, 'data-sources', 'weather', 'preview.hbs'), 'utf8')); Handlebars.registerPartial('data-sources/weather/forecast-preview', fs.readFileSync(path.join(viewsRoot, 'data-sources', 'weather', 'forecast-preview.hbs'), 'utf8')); } // One entry point keeps Handlebars bootstrap centralized. function registerHandlebars(Handlebars, deps) { const viewsRoot = String(deps && deps.viewsRoot || '').trim(); const hasPermission = deps && deps.hasPermission; const hasAnyPermission = deps && deps.hasAnyPermission; if (!Handlebars || !viewsRoot || typeof hasPermission !== 'function' || typeof hasAnyPermission !== 'function') { throw new Error('registerHandlebars requires Handlebars, viewsRoot, hasPermission, and hasAnyPermission.'); } registerGeneralHelpers(Handlebars); registerUrlHelpers(Handlebars); registerPermissionHelpers(Handlebars, { hasPermission: hasPermission, hasAnyPermission: hasAnyPermission }); registerUserHelpers(Handlebars); registerActionHelpers(Handlebars); registerPartials(Handlebars, viewsRoot); } module.exports = { registerHandlebars: registerHandlebars };