import JoomlaDialog from 'joomla.dialog'; /** * @copyright (C) 2023 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ /** * Helper method to set values on the fields, and trigger "change" event * * @param {object} data * @param {HTMLInputElement} inputValue * @param {HTMLInputElement} inputTitle */ const setValues = (data, inputValue, inputTitle) => { const value = `${data.id || data.value || ''}`; const isChanged = inputValue.value !== value; inputValue.value = value; if (inputTitle) { inputTitle.value = data.title || inputValue.value; } if (isChanged) { inputValue.dispatchEvent(new CustomEvent('change', { bubbles: true, cancelable: true })); } }; /** * Show Select dialog * * @param {HTMLInputElement} inputValue * @param {HTMLInputElement} inputTitle * @param {Object} dialogConfig * @returns {Promise} */ const doSelect = (inputValue, inputTitle, dialogConfig) => { // Use a JoomlaExpectingPostMessage flag to be able to distinct legacy methods // @TODO: This should be removed after full transition to postMessage() window.JoomlaExpectingPostMessage = true; // Create and show the dialog const dialog = new JoomlaDialog(dialogConfig); dialog.classList.add('joomla-dialog-content-select-field'); dialog.show(); return new Promise(resolve => { const msgListener = event => { // Avoid cross origins if (event.origin !== window.location.origin) return; // Check message type if (event.data.messageType === 'joomla:content-select') { setValues(event.data, inputValue, inputTitle); dialog.close(); } else if (event.data.messageType === 'joomla:cancel') { dialog.close(); } }; // Clear all when dialog is closed dialog.addEventListener('joomla-dialog:close', () => { delete window.JoomlaExpectingPostMessage; window.removeEventListener('message', msgListener); dialog.destroy(); resolve(); }); // Wait for message window.addEventListener('message', msgListener); }); }; /** * Update view, depending if value is selected or not * * @param {HTMLInputElement} inputValue * @param {HTMLElement} container */ const updateView = (inputValue, container) => { const hasValue = !!inputValue.value; container.querySelectorAll('[data-show-when-value]').forEach(el => { if (el.dataset.showWhenValue) { // eslint-disable-next-line no-unused-expressions hasValue ? el.removeAttribute('hidden') : el.setAttribute('hidden', ''); } else { // eslint-disable-next-line no-unused-expressions hasValue ? el.setAttribute('hidden', '') : el.removeAttribute('hidden'); } }); }; /** * Initialise the field * @param {HTMLElement} container */ const setupField = container => { const inputValue = container ? container.querySelector('.js-input-value') : null; const inputTitle = container ? container.querySelector('.js-input-title') : null; if (!container || !inputValue) { throw new Error('Incomplete markup of Content dialog field'); } container.addEventListener('change', () => { updateView(inputValue, container); }); // Bind the buttons container.addEventListener('click', event => { const button = event.target.closest('[data-button-action]'); if (!button) return; event.preventDefault(); // Extract the data const action = button.dataset.buttonAction; const dialogConfig = button.dataset.modalConfig ? JSON.parse(button.dataset.modalConfig) : {}; // Handle requested action let handle; switch (action) { case 'select': case 'create': handle = doSelect(inputValue, inputTitle, dialogConfig); break; case 'edit': { // Update current value in the URL const url = dialogConfig.src.indexOf('http') === 0 ? new URL(dialogConfig.src) : new URL(dialogConfig.src, window.location.origin); url.searchParams.set('id', inputValue.value); dialogConfig.src = url.toString(); handle = doSelect(inputValue, inputTitle, dialogConfig); break; } case 'clear': handle = (async () => setValues({ id: '', title: '' }, inputValue, inputTitle))(); break; default: throw new Error(`Unknown action ${action} for Modal select field`); } handle.then(() => { // Perform checkin when needed if (button.dataset.checkinUrl) { const chckUrl = button.dataset.checkinUrl; const url = chckUrl.indexOf('http') === 0 ? new URL(chckUrl) : new URL(chckUrl, window.location.origin); // Add value to request url.searchParams.set('id', inputValue.value); url.searchParams.set('cid[]', inputValue.value); // Also add value to POST, because Controller may expect it from there const data = new FormData(); data.append('id', inputValue.value); data.append('cid[]', inputValue.value); Joomla.request({ url: url.toString(), method: 'POST', promise: true, data }); } }); }); }; const setup = container => { container.querySelectorAll('.js-modal-content-select-field').forEach(el => setupField(el)); }; document.addEventListener('DOMContentLoaded', () => setup(document)); document.addEventListener('joomla:updated', event => setup(event.target));