import JoomlaDialog from 'joomla.dialog'; /** * @copyright (C) 2022 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ if (!window.Joomla) { throw new Error('Joomla API is not properly initialised'); } /* global hotkeys */ Joomla.addShortcut = (hotkey, callback) => { hotkeys(hotkey, 'joomla', event => { event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); callback.call(); }); }; Joomla.addClickShortcut = (hotkey, selector) => { Joomla.addShortcut(hotkey, () => { const element = document.querySelector(selector); if (element) { element.click(); } }); }; Joomla.addFocusShortcut = (hotkey, selector) => { Joomla.addShortcut(hotkey, () => { const element = document.querySelector(selector); if (element) { element.focus(); } }); }; Joomla.addLinkShortcut = (hotkey, selector) => { Joomla.addShortcut(hotkey, () => { window.location.href = selector; }); }; const setShortcutFilter = () => { hotkeys.filter = event => { const target = event.target || event.srcElement; const { tagName } = target; // Checkboxes should not block a shortcut event if (target.type === 'checkbox') { return true; } // Ignore TinyMCE joomlaHighlighter plugin, // @TODO: remove this when the joomlaHighlighter plugin will use JoomlaDialog if (target.classList.contains('tox-textarea-wrap') && target.closest('.joomla-highlighter-dialog')) { return false; } // Default hotkeys filter behavior return !(target.isContentEditable || tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA'); }; }; const startupShortcuts = () => { hotkeys('J', event => { // If we're already in the scope, it's a normal shortkey if (hotkeys.getScope() === 'joomla') { return; } event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); hotkeys.setScope('joomla'); // Leave the scope after x milliseconds setTimeout(() => { hotkeys.setScope(false); }, Joomla.getOptions('plg_system_shortcut.timeout', 2000)); }); }; const addOverviewHint = () => { const mainContainer = document.querySelector('.com_cpanel .container-main'); if (mainContainer) { const containerElement = document.createElement('section'); containerElement.className = 'content pt-4'; containerElement.insertAdjacentHTML('beforeend', Joomla.Text._('PLG_SYSTEM_SHORTCUT_OVERVIEW_HINT')); mainContainer.appendChild(containerElement); } }; /** * Helper to create an element * @param {String} nodeName * @param {String} text * @param {Array} classList * @returns {HTMLElement} */ const createEl = (nodeName, text = '', classList = []) => { const el = document.createElement(nodeName); el.textContent = text; if (classList && classList.length) { el.classList.add(...classList); } return el; }; let overviewDialog; const initOverviewModal = options => { if (overviewDialog) { return overviewDialog; } const dlItems = new Map(); Object.values(options).forEach(value => { if (!value.shortcut || !value.title) { return; } let titles = []; if (dlItems.has(value.shortcut)) { titles = dlItems.get(value.shortcut); titles.push(value.title); } else { titles = [value.title]; } dlItems.set(value.shortcut, titles); }); // Render: //
//
Jthen...
....
//
Jthen...
....
// ... //
const dl = createEl('dl'); dlItems.forEach((titles, shortcut) => { const row = createEl('div'); const dt = createEl('dt', '', ['d-inline-block']); row.appendChild(dt); dt.appendChild(createEl('kbd', 'J')); shortcut.split('+').forEach(key => { dt.appendChild(createEl('span', Joomla.Text._('PLG_SYSTEM_SHORTCUT_THEN'), ['px-1'])); dt.appendChild(createEl('kbd', key)); }); titles.forEach(title => { const dd = createEl('dd', '', ['d-inline-block', 'ps-1']); dd.innerHTML = Joomla.sanitizeHtml(title); row.appendChild(dd); }); dl.appendChild(row); }); // Create the content for the dialog const intro = createEl('p'); intro.innerHTML = Joomla.sanitizeHtml(Joomla.Text._('PLG_SYSTEM_SHORTCUT_OVERVIEW_DESC'), { kbd: '*' }); const info = createEl('div'); info.appendChild(dl); const content = createEl('div', '', ['p-3']); content.appendChild(intro); content.appendChild(info); overviewDialog = new JoomlaDialog({ textHeader: Joomla.Text._('PLG_SYSTEM_SHORTCUT_OVERVIEW_TITLE'), textClose: Joomla.Text._('JCLOSE'), popupContent: content, width: '600px', height: 'fit-content' }); return overviewDialog; }; const showOverviewModal = options => { initOverviewModal(options).show(); }; document.addEventListener('DOMContentLoaded', () => { const options = Joomla.getOptions('plg_system_shortcut.shortcuts'); Object.values(options).forEach(value => { if (!value.shortcut || !value.selector) { return; } if (value.selector.startsWith('/') || value.selector.startsWith('http://') || value.selector.startsWith('www.')) { Joomla.addLinkShortcut(value.shortcut, value.selector); } else if (value.selector.includes('input')) { Joomla.addFocusShortcut(value.shortcut, value.selector); } else { Joomla.addClickShortcut(value.shortcut, value.selector); } }); // Show hint and overview on logged in backend only (not login page) if (document.querySelector('nav')) { hotkeys('X', 'joomla', () => { showOverviewModal(options); }); addOverviewHint(); } setShortcutFilter(); startupShortcuts(); });