be252e49e2
Migrate legacy ajax/JS to external services and AMD, enable TLS verification, scope admin CSS with RTLCSS-safe rules, and fix README/lang/boilerplate gaps. Co-authored-by: Cursor <cursoragent@cursor.com>
337 lines
12 KiB
JavaScript
337 lines
12 KiB
JavaScript
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* @module mod_meetletacbfree/settings_registration
|
|
* @copyright 2026 MeetLet <info@meetlet.net>
|
|
* @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};
|
|
});
|