// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * @module mod_meetletacbfree/settings_registration * @copyright 2026 MeetLet * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ define(['core/ajax', 'mod_meetletacbfree/meetlet_modal_scroll'], function(Ajax, MeetletModalScroll) { 'use strict'; function byId(id) { return document.getElementById(id); } function setFlash(el, ok, message) { if (!el) { return; } el.className = 'alert mt-3 ' + (ok ? 'alert-success' : 'alert-danger'); el.textContent = message || ''; el.classList.toggle('d-none', !message); } function setActiveUi(active) { var inactive = byId('meetlet-registration-actions-inactive'); var activeEl = byId('meetlet-registration-actions-active'); var product = byId('meetlet-registration-product'); if (inactive) { inactive.classList.toggle('d-none', !!active); } if (activeEl) { activeEl.classList.toggle('d-none', !active); } if (product) { product.classList.toggle('d-none', !active); } } function renderSummary(summary) { if (!summary) { return; } var badge = byId('meetlet-registration-status-badge'); var cfg = byId('meetlet-registration-config'); if (badge) { badge.className = 'badge meetlet-license-badge ' + (summary.active ? 'meetlet-license-badge--active' : 'meetlet-license-badge--inactive'); badge.textContent = summary.status_label || (summary.active ? (cfg && cfg.dataset.labelActive) || 'Active' : (cfg && cfg.dataset.labelInactive) || 'Inactive'); } var domain = byId('meetlet-registration-domain'); if (domain && cfg && cfg.dataset.labelDomain) { domain.textContent = cfg.dataset.labelDomain.replace('__V__', summary.domain || '—'); } var installation = byId('meetlet-registration-installation'); if (installation && cfg && cfg.dataset.labelInstallation) { installation.textContent = cfg.dataset.labelInstallation.replace('__V__', summary.installation_id || '—'); } var product = byId('meetlet-registration-product'); if (product) { product.textContent = summary.product_label || ''; } var err = byId('meetlet-registration-error'); if (err) { if (summary.error) { err.textContent = summary.error; err.classList.remove('d-none'); } else { err.textContent = ''; err.classList.add('d-none'); } } setActiveUi(!!summary.active); } function currentApiUrl(cfg) { var input = cfg && cfg.dataset.apiInput ? document.getElementById(cfg.dataset.apiInput) : null; if (input && input.value) { return input.value.trim(); } return ''; } var modalState = { open: false, resolve: null, lastFocus: null, onKey: null, }; function ensureModalOnBody(modal) { if (modal && modal.parentNode !== document.body) { document.body.appendChild(modal); } return modal; } function modalScroll() { return MeetletModalScroll; } function closeRegistrationModal(result) { var modal = byId('meetlet-registration-modal'); if (!modal) { return; } modal.setAttribute('hidden', 'hidden'); modal.style.display = 'none'; modalScroll().unlock(); if (modalState.onKey) { document.removeEventListener('keydown', modalState.onKey, true); modalState.onKey = null; } modalState.open = false; var resolve = modalState.resolve; modalState.resolve = null; if (modalState.lastFocus) { modalScroll().focusNoScroll(modalState.lastFocus); } modalState.lastFocus = null; if (typeof resolve === 'function') { resolve(!!result); } } function openRegistrationModal(opts) { var modal = ensureModalOnBody(byId('meetlet-registration-modal')); var cfg = byId('meetlet-registration-config'); if (!modal) { return Promise.resolve(false); } if (modalState.open) { closeRegistrationModal(false); } var title = byId('meetlet-registration-modal-title'); var body = byId('meetlet-registration-modal-body'); var confirmBtn = byId('meetlet-registration-modal-confirm'); var tpl = opts.templateId ? document.getElementById(opts.templateId) : null; if (!title || !body || !confirmBtn) { return Promise.resolve(false); } title.textContent = opts.title || ''; if (tpl) { body.innerHTML = ''; if (tpl.content && tpl.content.cloneNode) { body.appendChild(tpl.content.cloneNode(true)); } else { body.innerHTML = tpl.innerHTML; } } else { body.innerHTML = ''; } confirmBtn.textContent = opts.confirmLabel || ''; confirmBtn.className = 'btn ' + (opts.danger ? 'btn-outline-danger' : 'btn-primary'); modalState.lastFocus = document.activeElement; modalScroll().lock(); modal.removeAttribute('hidden'); modal.style.display = 'flex'; modalState.open = true; modalState.onKey = function (e) { if (!modalState.open) { return; } if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); closeRegistrationModal(false); return; } if (e.key !== 'Tab') { return; } var focusable = modal.querySelectorAll( 'button:not([disabled]), [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ); if (!focusable.length) { return; } var first = focusable[0]; var last = focusable[focusable.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); modalScroll().focusNoScroll(last); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); modalScroll().focusNoScroll(first); } }; document.addEventListener('keydown', modalState.onKey, true); window.setTimeout(function () { modalScroll().focusNoScroll(confirmBtn); }, 20); return new Promise(function (resolve) { modalState.resolve = resolve; }); } function postAction(action) { var cfg = byId('meetlet-registration-config'); var flash = byId('meetlet-registration-flash'); if (!cfg) { return; } setFlash(flash, true, '…'); Ajax.call([{ methodname: 'mod_meetletacbfree_registration_action', args: { action: action, registration_api_url: currentApiUrl(cfg) } }])[0].then(function(data) { data.summary = { active: !!data.active, status: data.status, status_label: data.status_label, product_label: data.product_label, domain: data.domain, installation_id: data.installation_id, can_deactivate: !!data.can_deactivate }; if (data.summary) { renderSummary(data.summary); } if (data.success) { setFlash(flash, true, data.message); if (action === 'activate' || action === 'deactivate') { window.setTimeout(function() { window.location.reload(); }, 600); } } else { setFlash(flash, false, data.error || 'Request failed'); } }).catch(function(err) { setFlash(flash, false, err && err.message ? err.message : 'Request failed'); }); } function bindModalChrome() { var modal = byId('meetlet-registration-modal'); if (!modal || modal.dataset.bound === '1') { return; } modal.dataset.bound = '1'; modal.addEventListener('click', function (e) { if (e.target.closest('[data-meetlet-modal-dismiss]')) { e.preventDefault(); closeRegistrationModal(false); } }); var confirmBtn = byId('meetlet-registration-modal-confirm'); if (confirmBtn) { confirmBtn.addEventListener('click', function (e) { e.preventDefault(); closeRegistrationModal(true); }); } } function bindDeactivateButton(btn) { if (!btn || btn.dataset.bound === '1') { return; } var cfg = byId('meetlet-registration-config'); btn.dataset.bound = '1'; btn.addEventListener('click', function () { openRegistrationModal({ title: (cfg && cfg.dataset.confirmDeactivateTitle) || '', templateId: 'meetlet-registration-tpl-deactivate', confirmLabel: (cfg && cfg.dataset.confirmDeactivateOk) || '', danger: true, }).then(function (ok) { if (ok) { postAction('deactivate'); } }); }); } function bind() { var activate = byId('meetlet-registration-activate'); var recheck = byId('meetlet-registration-recheck'); var deactivate = byId('meetlet-registration-deactivate'); var cfg = byId('meetlet-registration-config'); if ((!activate && !recheck) || (activate && activate.dataset.bound === '1')) { return; } bindModalChrome(); if (activate) { activate.dataset.bound = '1'; activate.addEventListener('click', function () { openRegistrationModal({ title: (cfg && cfg.dataset.confirmActivateTitle) || '', templateId: 'meetlet-registration-tpl-activate', confirmLabel: (cfg && cfg.dataset.confirmActivateOk) || '', danger: false, }).then(function (ok) { if (ok) { postAction('activate'); } }); }); } if (recheck) { recheck.dataset.bound = '1'; recheck.addEventListener('click', function () { postAction('recheck'); }); } bindDeactivateButton(deactivate); } return {init: bind}; });