Skip to content

Commit

Permalink
Merge branch '4.2-dev' into replace_factory_getapplication_in_control…
Browse files Browse the repository at this point in the history
…lers
  • Loading branch information
Quy committed Jun 22, 2022
2 parents 83e9eae + febdab6 commit 094660f
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 0 deletions.
@@ -0,0 +1,3 @@
-- See https://github.com/joomla/joomla-cms/pull/38092
INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `custom_data`, `ordering`, `state`) VALUES
(0, 'plg_system_shortcut', 'plugin', 'shortcut', 'system', 0, 1, 1, 0, 1, '', '', '', 0, 0);
@@ -0,0 +1,3 @@
-- See https://github.com/joomla/joomla-cms/pull/38092
INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "custom_data", "ordering", "state") VALUES
(0, 'plg_system_shortcut', 'plugin', 'shortcut', 'system', 0, 1, 1, 0, 1, '', '', '', 0, 0);
12 changes: 12 additions & 0 deletions administrator/language/en-GB/plg_system_shortcut.ini
@@ -0,0 +1,12 @@
; Joomla! Project
; (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_SHORTCUT="System - Keyboard Shortcuts"
PLG_SYSTEM_SHORTCUT_OVERVIEW_DESC="Press <kbd>J</kbd> to access the shortcut mode followed by the shortcut."
PLG_SYSTEM_SHORTCUT_OVERVIEW_HINT="<span class=\"icon-keyboard fa-keyboard me-2\" aria-hidden=\"true\"></span> <kbd>J</kbd> + <kbd>X</kbd> <small>Keyboard Shortcuts</small>"
PLG_SYSTEM_SHORTCUT_OVERVIEW_TITLE="Joomla Keyboard Shortcuts"
PLG_SYSTEM_SHORTCUT_TIMEOUT_DESC="Maximum time that a shortcut can be pressed after pressing <kbd>J</kbd>."
PLG_SYSTEM_SHORTCUT_TIMEOUT_LABEL="Timeout (in milliseconds)"
PLG_SYSTEM_SHORTCUT_XML_DESCRIPTION="<p>Enables keyboard shortcuts on the administrator site, which can be provided by other plugins and includes directly the following list of shortcuts:</p><ul class=\"list-unstyled\"><li><kbd>J</kbd> <kbd>A</kbd> Save</li><li><kbd>J</kbd> <kbd>S</kbd> Save & Close</li><li><kbd>J</kbd> <kbd>Q</kbd> Cancel</li><li><kbd>J</kbd> <kbd>N</kbd> New</li><li><kbd>J</kbd> <kbd>F</kbd> Search</li><li><kbd>J</kbd> <kbd>O</kbd> Options</li><li><kbd>J</kbd> <kbd>H</kbd> Help</li><li><kbd>J</kbd> <kbd>X</kbd> Overview</li><li><kbd>J</kbd> <kbd>D</kbd> Home Dashboard</li></ul>"
7 changes: 7 additions & 0 deletions administrator/language/en-GB/plg_system_shortcut.sys.ini
@@ -0,0 +1,7 @@
; Joomla! Project
; (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_SHORTCUT="System - Keyboard Shortcuts"
PLG_SYSTEM_SHORTCUT_XML_DESCRIPTION="<p>Enables keyboard shortcuts on the administrator site, which can be provided by other plugins and includes directly the following list of shortcuts:</p><ul class=\"list-unstyled\"><li><kbd>J</kbd> <kbd>A</kbd> Save</li><li><kbd>J</kbd> <kbd>S</kbd> Save & Close</li><li><kbd>J</kbd> <kbd>Q</kbd> Cancel</li><li><kbd>J</kbd> <kbd>N</kbd> New</li><li><kbd>J</kbd> <kbd>F</kbd> Search</li><li><kbd>J</kbd> <kbd>O</kbd> Options</li><li><kbd>J</kbd> <kbd>H</kbd> Help</li><li><kbd>J</kbd> <kbd>X</kbd> Overview</li><li><kbd>J</kbd> <kbd>D</kbd> Home Dashboard</li></ul>"
18 changes: 18 additions & 0 deletions build/build-modules-js/settings.json
Expand Up @@ -386,6 +386,24 @@
"dependencies": [],
"licenseFilename": "LICENSE.txt"
},
"hotkeys-js": {
"name": "hotkeys.js",
"licenseFilename": "LICENSE",
"js" : {
"dist/hotkeys.js": "js/hotkeys.js",
"dist/hotkeys.min.js": "js/hotkeys.min.js"
},
"provideAssets": [
{
"name": "hotkeys.js",
"type": "script",
"uri": "hotkeys.min.js",
"attributes": {
"defer": true
}
}
]
},
"jquery": {
"name": "jquery",
"js": {
Expand Down
168 changes: 168 additions & 0 deletions build/media_source/plg_system_shortcut/js/shortcut.es6.js
@@ -0,0 +1,168 @@
((document, Joomla) => {
'use strict';

if (!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;
}
// 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);
}
};

const initOverviewModal = (options) => {
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);
});

let dl = '<dl>';
dlItems.forEach((titles, shortcut) => {
dl += '<dt><kbd>J</kbd>';
shortcut.split('+').forEach((key) => {
dl += ` <kbd>${key.trim()}</kbd>`;
});
dl += '</dt>';
titles.forEach((title) => {
dl += `<dd>${title}</dd>`;
});
});
dl += '</dl>';

const modal = `
<div class="modal fade" id="shortcutOverviewModal" tabindex="-1" role="dialog" data-bs-backdrop="static" aria-labelledby="shortcutOverviewModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h3 id="shortcutOverviewModalLabel" class="modal-title">
${Joomla.Text._('PLG_SYSTEM_SHORTCUT_OVERVIEW_TITLE')}
</h3>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${Joomla.Text._('JCLOSE')}"></button>
</div>
<div class="modal-body p-3">
<p>${Joomla.Text._('PLG_SYSTEM_SHORTCUT_OVERVIEW_DESC')}</p>
<div class="mb-3">
${dl}
</div>
</div>
</div>
</div>
</div>
`;

document.body.insertAdjacentHTML('beforeend', modal);

const bootstrapModal = new bootstrap.Modal(document.getElementById('shortcutOverviewModal'), {
keyboard: true,
backdrop: true,
});
hotkeys('X', 'joomla', () => bootstrapModal.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')) {
initOverviewModal(options);
addOverviewHint();
}
setShortcutFilter();
startupShortcuts();
});
})(document, Joomla);
1 change: 1 addition & 0 deletions installation/sql/mysql/base.sql
Expand Up @@ -341,6 +341,7 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`,
(0, 'plg_system_schedulerunner', 'plugin', 'schedulerunner', 'system', 0, 1, 1, 0, 0, '', '{}', '', 17, 0),
(0, 'plg_system_sef', 'plugin', 'sef', 'system', 0, 1, 1, 0, 1, '', '', '', 18, 0),
(0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, 1, '', '', '', 19, 0),
(0, 'plg_system_shortcut', 'plugin', 'shortcut', 'system', 0, 1, 1, 0, 1, '', '{}', '', 0, 0),
(0, 'plg_system_skipto', 'plugin', 'skipto', 'system', 0, 1, 1, 0, 1, '', '{}', '', 20, 0),
(0, 'plg_system_stats', 'plugin', 'stats', 'system', 0, 1, 1, 0, 1, '', '', '', 21, 0),
(0, 'plg_system_tasknotification', 'plugin', 'tasknotification', 'system', 0, 1, 1, 0, 1, '', '', '', 22, 0),
Expand Down
1 change: 1 addition & 0 deletions installation/sql/postgresql/base.sql
Expand Up @@ -347,6 +347,7 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder",
(0, 'plg_system_schedulerunner', 'plugin', 'schedulerunner', 'system', 0, 1, 1, 0, 0, '', '{}', '', 17, 0),
(0, 'plg_system_sef', 'plugin', 'sef', 'system', 0, 1, 1, 0, 1, '', '', '', 18, 0),
(0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, 1, '', '', '', 19, 0),
(0, 'plg_system_shortcut', 'plugin', 'shortcut', 'system', 0, 1, 1, 0, 1, '', '{}', '', 0, 0),
(0, 'plg_system_skipto', 'plugin', 'skipto', 'system', 0, 1, 1, 0, 1, '', '{}', '', 20, 0),
(0, 'plg_system_stats', 'plugin', 'stats', 'system', 0, 1, 1, 0, 1, '', '', '', 21, 0),
(0, 'plg_system_tasknotification', 'plugin', 'tasknotification', 'system', 0, 1, 1, 0, 1, '', '', '', 22, 0),
Expand Down
1 change: 1 addition & 0 deletions libraries/src/Extension/ExtensionHelper.php
Expand Up @@ -295,6 +295,7 @@ class ExtensionHelper
array('plugin', 'schedulerunner', 'system', 0),
array('plugin', 'sef', 'system', 0),
array('plugin', 'sessiongc', 'system', 0),
array('plugin', 'shortcut', 'system', 0),
array('plugin', 'skipto', 'system', 0),
array('plugin', 'stats', 'system', 0),
array('plugin', 'tasknotification', 'system', 0),
Expand Down
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -47,6 +47,7 @@
"diff": "^5.0.0",
"dragula": "^3.7.3",
"focus-visible": "^5.2.0",
"hotkeys-js": "^3.9.3",
"joomla-ui-custom-elements": "^0.2.0",
"jquery": "^3.6.0",
"jquery-migrate": "^3.3.2",
Expand Down
48 changes: 48 additions & 0 deletions plugins/system/shortcut/services/provider.php
@@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.shortcut
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

defined('_JEXEC') or die;

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Shortcut\Extension\Shortcut;

return new class implements ServiceProviderInterface
{
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since __DEPLOY_VERSION__
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container)
{
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Shortcut(
$dispatcher,
(array) PluginHelper::getPlugin('system', 'shortcut')
);
$plugin->setApplication(Factory::getApplication());

return $plugin;
}
);
}
};
40 changes: 40 additions & 0 deletions plugins/system/shortcut/shortcut.xml
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_shortcut</name>
<author>Joomla! Project</author>
<creationDate>2022-06</creationDate>
<copyright>(C) 2022 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>__DEPLOY_VERSION__</version>
<description>PLG_SYSTEM_SHORTCUT_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Shortcut</namespace>
<media destination="plg_system_shortcut" folder="media">
<folder>js</folder>
</media>
<files>
<folder plugin="shortcut">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_shortcut.ini</language>
<language tag="en-GB">language/en-GB/plg_system_shortcut.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="timeout"
type="number"
label="PLG_SYSTEM_SHORTCUT_TIMEOUT_LABEL"
description="PLG_SYSTEM_SHORTCUT_TIMEOUT_DESC"
required="true"
start="1"
step="1"
default="2000"
/>
</fieldset>
</fields>
</config>
</extension>

0 comments on commit 094660f

Please sign in to comment.