item->title; ?>

diff --git a/administrator/components/com_finder/tmpl/maps/default.php b/administrator/components/com_finder/tmpl/maps/default.php index ae9563c287cb7..b24d64cacabfc 100644 --- a/administrator/components/com_finder/tmpl/maps/default.php +++ b/administrator/components/com_finder/tmpl/maps/default.php @@ -18,6 +18,8 @@ use Joomla\CMS\Router\Route; use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; +/** @var \Joomla\Component\Finder\Administrator\View\Maps\HtmlView $this */ + $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $lang = Factory::getLanguage(); diff --git a/administrator/components/com_finder/tmpl/searches/default.php b/administrator/components/com_finder/tmpl/searches/default.php index 40c0ec041460f..29244ad7da9f5 100644 --- a/administrator/components/com_finder/tmpl/searches/default.php +++ b/administrator/components/com_finder/tmpl/searches/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Finder\Administrator\View\Searches\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('multiselect'); diff --git a/administrator/components/com_finder/tmpl/statistics/default.php b/administrator/components/com_finder/tmpl/statistics/default.php index 4c2e2444c3cff..57f118e58e30f 100644 --- a/administrator/components/com_finder/tmpl/statistics/default.php +++ b/administrator/components/com_finder/tmpl/statistics/default.php @@ -12,6 +12,7 @@ use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Finder\Administrator\View\Statistics\HtmlView $this */ ?>
diff --git a/administrator/components/com_guidedtours/forms/step.xml b/administrator/components/com_guidedtours/forms/step.xml index e0d1ba212d012..69d9b6cf31968 100644 --- a/administrator/components/com_guidedtours/forms/step.xml +++ b/administrator/components/com_guidedtours/forms/step.xml @@ -120,6 +120,8 @@ > + + @@ -189,4 +191,47 @@ maxlength="255" /> + + +
+ +
+ + + + + + + + + +
+
+
+ diff --git a/administrator/components/com_guidedtours/src/Extension/GuidedtoursComponent.php b/administrator/components/com_guidedtours/src/Extension/GuidedtoursComponent.php index 19703055ae07c..088246bc28d48 100644 --- a/administrator/components/com_guidedtours/src/Extension/GuidedtoursComponent.php +++ b/administrator/components/com_guidedtours/src/Extension/GuidedtoursComponent.php @@ -100,6 +100,20 @@ class GuidedtoursComponent extends MVCComponent implements BootableExtensionInte */ public const STEP_INTERACTIVETYPE_OTHER = 3; + /** + * An interactive step for checkbox/radio fields + * + * @since 5.1.0 + */ + public const STEP_INTERACTIVETYPE_CHECKBOX_RADIO = 5; + + /** + * An interactive step for select element fields + * + * @since 5.1.0 + */ + public const STEP_INTERACTIVETYPE_SELECT = 6; + /** * Booting the extension. This is the function to set up the environment of the extension like * registering new class loaders, etc. diff --git a/administrator/components/com_guidedtours/src/Model/StepModel.php b/administrator/components/com_guidedtours/src/Model/StepModel.php index 6129b2fbbd3eb..3f784fc389117 100644 --- a/administrator/components/com_guidedtours/src/Model/StepModel.php +++ b/administrator/components/com_guidedtours/src/Model/StepModel.php @@ -13,7 +13,6 @@ use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\AdminModel; -use Joomla\CMS\Object\CMSObject; use Joomla\CMS\Table\Table; use Joomla\Component\Guidedtours\Administrator\Helper\GuidedtoursHelper; @@ -232,7 +231,7 @@ protected function loadFormData() * * @param integer $pk The id of the primary key. * - * @return CMSObject|boolean Object on success, false on failure. + * @return \stdClass|boolean Object on success, false on failure. * * @since 4.3.0 */ diff --git a/administrator/components/com_guidedtours/src/Model/StepsModel.php b/administrator/components/com_guidedtours/src/Model/StepsModel.php index e81680b990f7b..acf733565fec2 100644 --- a/administrator/components/com_guidedtours/src/Model/StepsModel.php +++ b/administrator/components/com_guidedtours/src/Model/StepsModel.php @@ -16,6 +16,7 @@ use Joomla\Component\Guidedtours\Administrator\Helper\GuidedtoursHelper; use Joomla\Database\DatabaseQuery; use Joomla\Database\ParameterType; +use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects @@ -248,6 +249,13 @@ public function getItems() $item->title = Text::_($item->title); $item->description = Text::_($item->description); + + if (isset($item->params)) { + $params = new Registry($item->params); + if (!empty($item->params->requiredvalue)) { + $item->params->requiredvalue = Text::_($item->params->requiredvalue); + } + } } return $items; diff --git a/administrator/components/com_guidedtours/src/Model/TourModel.php b/administrator/components/com_guidedtours/src/Model/TourModel.php index 12ff03e0f585a..8bfca6bfdf760 100644 --- a/administrator/components/com_guidedtours/src/Model/TourModel.php +++ b/administrator/components/com_guidedtours/src/Model/TourModel.php @@ -191,7 +191,7 @@ protected function loadFormData() * * @param integer|string $pk The id or uid of the tour. * - * @return CMSObject|boolean Object on success, false on failure. + * @return \stdClass|boolean Object on success, false on failure. * * @since 4.3.0 */ @@ -371,6 +371,7 @@ public function duplicate(&$pks) 'checked_out_time', 'checked_out', 'language', + 'params', 'note', ] ) @@ -400,6 +401,7 @@ public function duplicate(&$pks) $db->quoteName('modified'), $db->quoteName('modified_by'), $db->quoteName('language'), + $db->quoteName('params'), $db->quoteName('note'), ] ); @@ -421,6 +423,7 @@ public function duplicate(&$pks) ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, + ParameterType::STRING, ]; $query->values( @@ -442,6 +445,7 @@ public function duplicate(&$pks) $date, $user->id, $step->language, + $step->params, $step->note, ], $dataTypes diff --git a/administrator/components/com_guidedtours/src/Table/StepTable.php b/administrator/components/com_guidedtours/src/Table/StepTable.php index b856b75a8dd13..0af696921e63c 100644 --- a/administrator/components/com_guidedtours/src/Table/StepTable.php +++ b/administrator/components/com_guidedtours/src/Table/StepTable.php @@ -16,6 +16,7 @@ use Joomla\CMS\User\CurrentUserTrait; use Joomla\Database\DatabaseDriver; use Joomla\Event\DispatcherInterface; +use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; @@ -51,6 +52,28 @@ public function __construct(DatabaseDriver $db, DispatcherInterface $dispatcher parent::__construct('#__guidedtour_steps', 'id', $db, $dispatcher); } + /** + * Overloaded bind function. + * + * @param array $array named array + * @param string $ignore An optional array or space separated list of properties + * to ignore while binding. + * + * @return mixed Null if operation was satisfactory, otherwise returns an error + * + * @see Table::bind() + * @since 5.1.0 + */ + public function bind($array, $ignore = '') + { + if (isset($array['params']) && \is_array($array['params'])) { + $registry = new Registry($array['params']); + $array['params'] = (string) $registry; + } + + return parent::bind($array, $ignore); + } + /** * Stores a step. * diff --git a/administrator/components/com_guidedtours/src/View/Tour/HtmlView.php b/administrator/components/com_guidedtours/src/View/Tour/HtmlView.php index 58c42776ea419..8a5f7e62452bf 100644 --- a/administrator/components/com_guidedtours/src/View/Tour/HtmlView.php +++ b/administrator/components/com_guidedtours/src/View/Tour/HtmlView.php @@ -15,7 +15,6 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; -use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects diff --git a/administrator/components/com_guidedtours/tmpl/step/edit.php b/administrator/components/com_guidedtours/tmpl/step/edit.php index a17b46147074b..6b67e6d289fde 100644 --- a/administrator/components/com_guidedtours/tmpl/step/edit.php +++ b/administrator/components/com_guidedtours/tmpl/step/edit.php @@ -16,16 +16,21 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\MVC\View\GenericDataException; +/** @var \Joomla\Component\Guidedtours\Administrator\View\Step\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') - ->useScript('form.validate'); + ->useScript('form.validate') + ->useScript('com_guidedtours.tour-edit'); if (empty($this->item->tour_id)) { throw new GenericDataException("\nThe Tour id was not set!\n", 500); } $lang = $this->getLanguage()->getTag(); + +$this->useCoreUI = true; ?>
@@ -86,7 +93,7 @@
fields = []; + $this->fields = []; $this->hidden_fields = []; echo LayoutHelper::render('joomla.edit.publishingdata', $this); ?>
diff --git a/administrator/components/com_guidedtours/tmpl/steps/emptystate.php b/administrator/components/com_guidedtours/tmpl/steps/emptystate.php index a3ce66a9cb0bc..15474137a05b3 100644 --- a/administrator/components/com_guidedtours/tmpl/steps/emptystate.php +++ b/administrator/components/com_guidedtours/tmpl/steps/emptystate.php @@ -12,6 +12,8 @@ use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Guidedtours\Administrator\View\Steps\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_GUIDEDTOURS_STEPS', 'formURL' => 'index.php?option=com_guidedtours&view=steps', diff --git a/administrator/components/com_guidedtours/tmpl/tour/edit.php b/administrator/components/com_guidedtours/tmpl/tour/edit.php index dce454a24da0c..942dfee5a40ad 100644 --- a/administrator/components/com_guidedtours/tmpl/tour/edit.php +++ b/administrator/components/com_guidedtours/tmpl/tour/edit.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Guidedtours\Administrator\View\Tour\HtmlView $this */ + $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); diff --git a/administrator/components/com_guidedtours/tmpl/tours/emptystate.php b/administrator/components/com_guidedtours/tmpl/tours/emptystate.php index 26de064d68c0d..0462defb278ed 100644 --- a/administrator/components/com_guidedtours/tmpl/tours/emptystate.php +++ b/administrator/components/com_guidedtours/tmpl/tours/emptystate.php @@ -12,6 +12,8 @@ use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Guidedtours\Administrator\View\Tours\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_GUIDEDTOURS_TOURS_LIST', 'formURL' => 'index.php?option=com_guidedtours&view=tours', diff --git a/administrator/components/com_installer/src/Controller/ManageController.php b/administrator/components/com_installer/src/Controller/ManageController.php index f305381a30f8f..bfbc9c1895378 100644 --- a/administrator/components/com_installer/src/Controller/ManageController.php +++ b/administrator/components/com_installer/src/Controller/ManageController.php @@ -153,7 +153,7 @@ public function refresh() } /** - * Load the changelog for a given extension. + * Load the changelog for a given extension. Outputs HTML encoded in JSON. * * @return void * @@ -175,4 +175,26 @@ public function loadChangelog() echo (new JsonResponse($output)); } + + /** + * Load the changelog for a given extension. Outputs HTML. + * + * @return void + * + * @since 5.1.0 + */ + public function loadChangelogRaw() + { + /** @var ManageModel $model */ + $model = $this->getModel('manage'); + + $eid = $this->input->get('eid', 0, 'int'); + $source = $this->input->get('source', 'manage', 'string'); + + if (!$eid) { + return; + } + + echo $model->loadChangelog($eid, $source); + } } diff --git a/administrator/components/com_installer/src/Model/InstallModel.php b/administrator/components/com_installer/src/Model/InstallModel.php index 370341810d3bb..6ad08571ad286 100644 --- a/administrator/components/com_installer/src/Model/InstallModel.php +++ b/administrator/components/com_installer/src/Model/InstallModel.php @@ -274,7 +274,7 @@ protected function _getPackageFromUpload() $userfile = $input->files->get('install_package', null, 'raw'); // Make sure that file uploads are enabled in php. - if (!(bool) ini_get('file_uploads')) { + if (!(bool) \ini_get('file_uploads')) { Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLFILE'), 'error'); return false; diff --git a/administrator/components/com_installer/src/Model/InstallerModel.php b/administrator/components/com_installer/src/Model/InstallerModel.php index cf641cc4d15d2..e57297043d0f2 100644 --- a/administrator/components/com_installer/src/Model/InstallerModel.php +++ b/administrator/components/com_installer/src/Model/InstallerModel.php @@ -176,7 +176,7 @@ protected function translate(&$items) break; case 'file': $extension = 'files_' . $item->element; - $lang->load("$extension.sys", JPATH_SITE); + $lang->load("$extension.sys", JPATH_SITE); break; case 'library': $parts = explode('/', $item->element); diff --git a/administrator/components/com_installer/src/Model/UpdateModel.php b/administrator/components/com_installer/src/Model/UpdateModel.php index fdb7932df5125..17431af5ed004 100644 --- a/administrator/components/com_installer/src/Model/UpdateModel.php +++ b/administrator/components/com_installer/src/Model/UpdateModel.php @@ -336,6 +336,23 @@ public function update($uids, $minimumStability = Updater::STABILITY_STABLE) continue; } + $app = Factory::getApplication(); + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->select('type') + ->from('#__update_sites') + ->where($db->quoteName('update_site_id') . ' = :id') + ->bind(':id', $instance->update_site_id, ParameterType::INTEGER); + + $updateSiteType = (string) $db->setQuery($query)->loadResult(); + + // TUF is currently only supported for Joomla core + if ($updateSiteType === 'tuf') { + $app->enqueueMessage(Text::_('JLIB_INSTALLER_TUF_NOT_AVAILABLE'), 'error'); + + return; + } + $update->loadFromXml($instance->detailsurl, $minimumStability); // Find and use extra_query from update_site if available @@ -552,8 +569,8 @@ protected function loadFormData() protected function preparePreUpdate($update, $table) { switch ($table->type) { - // Components could have a helper which adds additional data case 'component': + // Components could have a helper which adds additional data $ename = str_replace('com_', '', $table->element); $fname = $ename . '.php'; $cname = ucfirst($ename) . 'Helper'; @@ -570,8 +587,8 @@ protected function preparePreUpdate($update, $table) break; - // Modules could have a helper which adds additional data case 'module': + // Modules could have a helper which adds additional data $cname = str_replace('_', '', $table->element) . 'Helper'; $path = ($table->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $table->element . '/helper.php'; @@ -585,9 +602,9 @@ protected function preparePreUpdate($update, $table) break; - // If we have a plugin, we can use the plugin trigger "onInstallerBeforePackageDownload" - // But we should make sure, that our plugin is loaded, so we don't need a second "installer" plugin case 'plugin': + // If we have a plugin, we can use the plugin trigger "onInstallerBeforePackageDownload" + // But we should make sure, that our plugin is loaded, so we don't need a second "installer" plugin $cname = str_replace('plg_', '', $table->element); PluginHelper::importPlugin($table->folder, $cname); break; diff --git a/administrator/components/com_installer/src/Model/UpdatesiteModel.php b/administrator/components/com_installer/src/Model/UpdatesiteModel.php index 4972c47f7558b..cdb5f0528eaaa 100644 --- a/administrator/components/com_installer/src/Model/UpdatesiteModel.php +++ b/administrator/components/com_installer/src/Model/UpdatesiteModel.php @@ -78,7 +78,7 @@ protected function loadFormData() * * @param integer $pk The id of the primary key. * - * @return CMSObject|boolean Object on success, false on failure. + * @return \stdClass|boolean Object on success, false on failure. * * @since 4.0.0 */ diff --git a/administrator/components/com_installer/src/Model/UpdatesitesModel.php b/administrator/components/com_installer/src/Model/UpdatesitesModel.php index 16b14f57618e5..0ade2440207dd 100644 --- a/administrator/components/com_installer/src/Model/UpdatesitesModel.php +++ b/administrator/components/com_installer/src/Model/UpdatesitesModel.php @@ -626,18 +626,18 @@ protected function getListQuery() if (is_numeric($supported)) { switch ($supported) { - // Show Update Sites which support Download Keys case 1: + // Show Update Sites which support Download Keys $supportedIDs = InstallerHelper::getDownloadKeySupportedSites($enabled); break; - // Show Update Sites which are missing Download Keys case -1: + // Show Update Sites which are missing Download Keys $supportedIDs = InstallerHelper::getDownloadKeyExistsSites(false, $enabled); break; - // Show Update Sites which have valid Download Keys case 2: + // Show Update Sites which have valid Download Keys $supportedIDs = InstallerHelper::getDownloadKeyExistsSites(true, $enabled); break; } diff --git a/administrator/components/com_installer/src/Model/WarningsModel.php b/administrator/components/com_installer/src/Model/WarningsModel.php index 5c5796ec4cb8a..1c596941b65b1 100644 --- a/administrator/components/com_installer/src/Model/WarningsModel.php +++ b/administrator/components/com_installer/src/Model/WarningsModel.php @@ -98,7 +98,7 @@ public function getItems() // 16MB $minLimit = 16 * 1024 * 1024; - $file_uploads = ini_get('file_uploads'); + $file_uploads = \ini_get('file_uploads'); if (!$file_uploads) { $messages[] = [ @@ -107,7 +107,7 @@ public function getItems() ]; } - $upload_dir = ini_get('upload_tmp_dir'); + $upload_dir = \ini_get('upload_tmp_dir'); if (!$upload_dir) { $messages[] = [ @@ -135,7 +135,7 @@ public function getItems() ]; } - $memory_limit = $this->return_bytes(ini_get('memory_limit')); + $memory_limit = $this->return_bytes(\ini_get('memory_limit')); if ($memory_limit > -1) { if ($memory_limit < $minLimit) { @@ -153,8 +153,8 @@ public function getItems() } } - $post_max_size = $this->return_bytes(ini_get('post_max_size')); - $upload_max_filesize = $this->return_bytes(ini_get('upload_max_filesize')); + $post_max_size = $this->return_bytes(\ini_get('post_max_size')); + $upload_max_filesize = $this->return_bytes(\ini_get('upload_max_filesize')); if ($post_max_size > 0 && $post_max_size < $upload_max_filesize) { $messages[] = [ diff --git a/administrator/components/com_installer/src/View/Languages/HtmlView.php b/administrator/components/com_installer/src/View/Languages/HtmlView.php index 4cd75a8a0c5ae..2adafb0e006b6 100644 --- a/administrator/components/com_installer/src/View/Languages/HtmlView.php +++ b/administrator/components/com_installer/src/View/Languages/HtmlView.php @@ -16,7 +16,6 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\Toolbar\Toolbar; -use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Installer\Administrator\View\Installer\HtmlView as InstallerViewDefault; // phpcs:disable PSR1.Files.SideEffects @@ -75,15 +74,19 @@ public function display($tpl = null) */ protected function addToolbar() { - $canDo = ContentHelper::getActions('com_installer'); + $canDo = ContentHelper::getActions('com_languages'); $toolbar = Toolbar::getInstance(); - ToolbarHelper::title(Text::_('COM_INSTALLER_HEADER_' . $this->getName()), 'puzzle-piece install'); + if ($canDo->get('core.manage')) { + $toolbar->linkButton('list', 'COM_INSTALLER_TOOLBAR_MANAGE_LANGUAGES') + ->url('index.php?option=com_languages&view=installed'); + $toolbar->linkButton('comments', 'COM_INSTALLER_TOOLBAR_MANAGE_LANGUAGES_CONTENT') + ->url('index.php?option=com_languages&view=languages'); + $toolbar->divider(); + } - if ($canDo->get('core.admin')) { - parent::addToolbar(); + parent::addToolbar(); - $toolbar->help('Extensions:_Languages'); - } + $toolbar->help('Extensions:_Languages'); } } diff --git a/administrator/components/com_installer/tmpl/database/default.php b/administrator/components/com_installer/tmpl/database/default.php index c755148e68155..0ca12209d62c2 100644 --- a/administrator/components/com_installer/tmpl/database/default.php +++ b/administrator/components/com_installer/tmpl/database/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Database\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_installer/tmpl/discover/default.php b/administrator/components/com_installer/tmpl/discover/default.php index a8be818c2fcc2..c59ca27aa433c 100644 --- a/administrator/components/com_installer/tmpl/discover/default.php +++ b/administrator/components/com_installer/tmpl/discover/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Discover\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_installer/tmpl/discover/emptystate.php b/administrator/components/com_installer/tmpl/discover/emptystate.php index 3572ff0c98867..fc32b7c0cff23 100644 --- a/administrator/components/com_installer/tmpl/discover/emptystate.php +++ b/administrator/components/com_installer/tmpl/discover/emptystate.php @@ -14,6 +14,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Installer\Administrator\View\Discover\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_INSTALLER', 'formURL' => 'index.php?option=com_installer&task=discover.refresh', diff --git a/administrator/components/com_installer/tmpl/install/default.php b/administrator/components/com_installer/tmpl/install/default.php index 965be5cd1a8ce..61775cf2efc93 100644 --- a/administrator/components/com_installer/tmpl/install/default.php +++ b/administrator/components/com_installer/tmpl/install/default.php @@ -16,6 +16,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Install\HtmlView $this */ + // Load JavaScript message titles Text::script('ERROR'); Text::script('WARNING'); diff --git a/administrator/components/com_installer/tmpl/installer/default_message.php b/administrator/components/com_installer/tmpl/installer/default_message.php index 3d1c78d6aa87b..87ac7477e3ea5 100644 --- a/administrator/components/com_installer/tmpl/installer/default_message.php +++ b/administrator/components/com_installer/tmpl/installer/default_message.php @@ -10,6 +10,8 @@ defined('_JEXEC') or die; +/** @var \Joomla\Component\Installer\Administrator\View\Installer\HtmlView $this */ + $state = $this->get('State'); $message1 = $state->get('message'); $message2 = $state->get('extension_message'); diff --git a/administrator/components/com_installer/tmpl/languages/default.php b/administrator/components/com_installer/tmpl/languages/default.php index f4d88ec2a47d6..0f616c1120b5b 100644 --- a/administrator/components/com_installer/tmpl/languages/default.php +++ b/administrator/components/com_installer/tmpl/languages/default.php @@ -16,10 +16,13 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Version; +/** @var \Joomla\Component\Installer\Administrator\View\Languages\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') - ->useScript('multiselect'); + ->useScript('multiselect') + ->useScript('webcomponent.core-loader'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); @@ -72,7 +75,7 @@
- modules as $i => &$module) : ?> + modules as $i => $module) : ?> menuid)) : ?> except || $module->menuid < 0) : ?> @@ -92,12 +87,14 @@
installedLang[0][$language->code]) || isset($this->installedLang[1][$language->code])) ? 'REINSTALL' : 'INSTALL'; ?> installedLang[0][$language->code]) || isset($this->installedLang[1][$language->code])) ? 'btn btn-success btn-sm' : 'btn btn-primary btn-sm'; ?> - detailsurl . '\'; Joomla.submitbutton(\'install.install\');'; ?> + detailsurl . '\'; Joomla.submitbutton(\'install.install\'); document.body.appendChild(document.createElement(\'joomla-core-loader\'));'; ?> document->getWebAssetManager(); -$wa->useScript('com_installer.changelog') - ->useScript('table.columns') - ->useScript('multiselect'); +$wa->useScript('table.columns') + ->useScript('multiselect') + ->useScript('joomla.dialog-autocreate'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); @@ -118,20 +120,18 @@ version)) : ?> - changelogurl)) : ?> - - version?> - - extension_id, - [ - 'title' => Text::sprintf('COM_INSTALLER_CHANGELOG_TITLE', $item->name, $item->version), - ], - '' - ); + changelogurl)) : + $popupOptions = [ + 'popupType' => 'ajax', + 'textHeader' => Text::sprintf('COM_INSTALLER_CHANGELOG_TITLE', $item->name, $item->version), + 'src' => Route::_('index.php?option=com_installer&task=manage.loadChangelogRaw&eid=' . $item->extension_id . '&source=manage&format=raw', false), + 'width' => '800px', + 'height' => 'fit-content', + ]; ?> + version; ?> diff --git a/administrator/components/com_installer/tmpl/update/default.php b/administrator/components/com_installer/tmpl/update/default.php index 8739374e6d6da..aeb8102ad9f0b 100644 --- a/administrator/components/com_installer/tmpl/update/default.php +++ b/administrator/components/com_installer/tmpl/update/default.php @@ -15,11 +15,13 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Update\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('multiselect') ->useScript('table.columns') - ->useScript('com_installer.changelog'); + ->useScript('joomla.dialog-autocreate'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); @@ -117,20 +119,18 @@ version; ?> - changelogurl)) : ?> - - - - extension_id, - [ - 'title' => Text::sprintf('COM_INSTALLER_CHANGELOG_TITLE', $item->name, $item->version), - ], - '' - ); + changelogurl)) : + $popupOptions = [ + 'popupType' => 'ajax', + 'textHeader' => Text::sprintf('COM_INSTALLER_CHANGELOG_TITLE', $item->name, $item->version), + 'src' => Route::_('index.php?option=com_installer&task=manage.loadChangelogRaw&eid=' . $item->extension_id . '&source=update&format=raw', false), + 'width' => '800px', + 'height' => 'fit-content', + ]; ?> + diff --git a/administrator/components/com_installer/tmpl/update/emptystate.php b/administrator/components/com_installer/tmpl/update/emptystate.php index a38e217eed776..a155e283171cd 100644 --- a/administrator/components/com_installer/tmpl/update/emptystate.php +++ b/administrator/components/com_installer/tmpl/update/emptystate.php @@ -13,6 +13,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Installer\Administrator\View\Update\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_INSTALLER', 'formURL' => 'index.php?option=com_installer&view=update', diff --git a/administrator/components/com_installer/tmpl/updatesite/edit.php b/administrator/components/com_installer/tmpl/updatesite/edit.php index 0c252686195b4..be0c2ce5c365a 100644 --- a/administrator/components/com_installer/tmpl/updatesite/edit.php +++ b/administrator/components/com_installer/tmpl/updatesite/edit.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Updatesite\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('form.validate'); diff --git a/administrator/components/com_installer/tmpl/updatesites/default.php b/administrator/components/com_installer/tmpl/updatesites/default.php index 545dd3b6120bf..17e68a5a9e136 100644 --- a/administrator/components/com_installer/tmpl/updatesites/default.php +++ b/administrator/components/com_installer/tmpl/updatesites/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Updatesites\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_installer/tmpl/warnings/default.php b/administrator/components/com_installer/tmpl/warnings/default.php index 8bd5bc8a8d52f..95c6ab8123892 100644 --- a/administrator/components/com_installer/tmpl/warnings/default.php +++ b/administrator/components/com_installer/tmpl/warnings/default.php @@ -14,6 +14,7 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Installer\Administrator\View\Warnings\HtmlView $this */ ?>
diff --git a/administrator/components/com_joomlaupdate/config.xml b/administrator/components/com_joomlaupdate/config.xml index 4aa5f5697c699..9259b7156e533 100644 --- a/administrator/components/com_joomlaupdate/config.xml +++ b/administrator/components/com_joomlaupdate/config.xml @@ -16,7 +16,6 @@ validate="options" > - diff --git a/administrator/components/com_joomlaupdate/extract.php b/administrator/components/com_joomlaupdate/extract.php index 9e113573f1cfa..98c33cd1f0197 100644 --- a/administrator/components/com_joomlaupdate/extract.php +++ b/administrator/components/com_joomlaupdate/extract.php @@ -1603,7 +1603,7 @@ private function getPhpMaxExecTime(): int return 10; } - $phpMaxTime = @ini_get("maximum_execution_time"); + $phpMaxTime = @\ini_get("maximum_execution_time"); $phpMaxTime = (!is_numeric($phpMaxTime) ? 10 : @\intval($phpMaxTime)) ?: 10; return max(1, $phpMaxTime); @@ -1694,9 +1694,9 @@ function clearFileInOPCache(string $file): bool static $hasOpCache = null; if (\is_null($hasOpCache)) { - $hasOpCache = ini_get('opcache.enable') + $hasOpCache = \ini_get('opcache.enable') && \function_exists('opcache_invalidate') - && (!ini_get('opcache.restrict_api') || stripos(realpath($_SERVER['SCRIPT_FILENAME']), ini_get('opcache.restrict_api')) === 0); + && (!\ini_get('opcache.restrict_api') || stripos(realpath($_SERVER['SCRIPT_FILENAME']), \ini_get('opcache.restrict_api')) === 0); } if ($hasOpCache && (strtolower(substr($file, -4)) === '.php')) { diff --git a/administrator/components/com_joomlaupdate/src/Controller/UpdateController.php b/administrator/components/com_joomlaupdate/src/Controller/UpdateController.php index 5e4f544bec9bb..c48e950643451 100644 --- a/administrator/components/com_joomlaupdate/src/Controller/UpdateController.php +++ b/administrator/components/com_joomlaupdate/src/Controller/UpdateController.php @@ -62,6 +62,20 @@ public function download() $message = null; $messageType = null; + // The versions mismatch + if ($result['version'] !== $this->input->get('targetVersion')) { + $message = Text::_('COM_JOOMLAUPDATE_VIEW_UPDATE_VERSION_WRONG'); + $messageType = 'error'; + $url = 'index.php?option=com_joomlaupdate'; + + $this->app->setUserState('com_joomlaupdate.file', null); + $this->setRedirect($url, $message, $messageType); + + Log::add($message, Log::ERROR, 'Update'); + + return; + } + // The validation was not successful so stop. if ($result['check'] === false) { $message = Text::_('COM_JOOMLAUPDATE_VIEW_UPDATE_CHECKSUM_WRONG'); @@ -71,11 +85,7 @@ public function download() $this->app->setUserState('com_joomlaupdate.file', null); $this->setRedirect($url, $message, $messageType); - try { - Log::add($message, Log::ERROR, 'Update'); - } catch (\RuntimeException $exception) { - // Informational log only - } + Log::add($message, Log::ERROR, 'Update'); return; } diff --git a/administrator/components/com_joomlaupdate/src/Model/UpdateModel.php b/administrator/components/com_joomlaupdate/src/Model/UpdateModel.php index 977531e1347fe..9291cd9d14d2d 100644 --- a/administrator/components/com_joomlaupdate/src/Model/UpdateModel.php +++ b/administrator/components/com_joomlaupdate/src/Model/UpdateModel.php @@ -24,6 +24,7 @@ use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\CMS\Plugin\PluginHelper; +use Joomla\CMS\Table\Tuf as TufMetadata; use Joomla\CMS\Updater\Update; use Joomla\CMS\Updater\Updater; use Joomla\CMS\User\UserHelper; @@ -87,20 +88,15 @@ public function applyUpdateSite() // Determine the intended update URL. $params = ComponentHelper::getParams('com_joomlaupdate'); - switch ($params->get('updatesource', 'nochange')) { - // "Minor & Patch Release for Current version AND Next Major Release". - case 'next': - $updateURL = 'https://update.joomla.org/core/sts/list_sts.xml'; - break; - - // "Testing" + switch ($params->get('updatesource', 'default')) { case 'testing': + // "Testing" $updateURL = 'https://update.joomla.org/core/test/list_test.xml'; break; + case 'custom': // "Custom" // @todo: check if the customurl is valid and not just "not empty". - case 'custom': if (trim($params->get('customurl', '')) != '') { $updateURL = trim($params->get('customurl', '')); } else { @@ -110,18 +106,21 @@ public function applyUpdateSite() } break; + default: /** - * "Minor & Patch Release for Current version (recommended and default)". + * All "non-testing" releases of the official project hosted in Joomla's TUF-based update repo. * The commented "case" below are for documenting where 'default' and legacy options falls * case 'default': + * case 'next': * case 'lts': * case 'sts': (It's shown as "Default" because that option does not exist any more) * case 'nochange': */ - default: - $updateURL = 'https://update.joomla.org/core/list.xml'; + $updateURL = 'https://update.joomla.org/cms/'; } + $updateType = (pathinfo($updateURL, PATHINFO_EXTENSION) === 'xml') ? 'collection' : 'tuf'; + $id = ExtensionHelper::getExtensionRecord('joomla', 'file')->extension_id; $db = version_compare(JVERSION, '4.2.0', 'lt') ? $this->getDbo() : $this->getDatabase(); $query = $db->getQuery(true) @@ -137,10 +136,11 @@ public function applyUpdateSite() $db->setQuery($query); $update_site = $db->loadObject(); - if ($update_site->location != $updateURL) { + if ($update_site->location !== $updateURL || $update_site->type !== $updateType) { // Modify the database record. $update_site->last_check_timestamp = 0; $update_site->location = $updateURL; + $update_site->type = $updateType; $db->updateObject('#__update_sites', $update_site, 'update_site_id'); // Remove cached updates. @@ -176,7 +176,7 @@ public function refreshUpdates($force = false) $minimumStability = Updater::STABILITY_STABLE; $comJoomlaupdateParams = ComponentHelper::getParams('com_joomlaupdate'); - if (\in_array($comJoomlaupdateParams->get('updatesource', 'nochange'), ['testing', 'custom'])) { + if (\in_array($comJoomlaupdateParams->get('updatesource', 'default'), ['testing', 'custom'])) { $minimumStability = $comJoomlaupdateParams->get('minimum_stability', Updater::STABILITY_STABLE); } @@ -298,14 +298,34 @@ public function getUpdateInformation() $minimumStability = Updater::STABILITY_STABLE; $comJoomlaupdateParams = ComponentHelper::getParams('com_joomlaupdate'); + $channel = $comJoomlaupdateParams->get('updatesource', 'default'); - if (\in_array($comJoomlaupdateParams->get('updatesource', 'nochange'), ['testing', 'custom'])) { + if (\in_array($channel, ['testing', 'custom'])) { $minimumStability = $comJoomlaupdateParams->get('minimum_stability', Updater::STABILITY_STABLE); } - // Fetch the full update details from the update details URL. $update = new Update(); - $update->loadFromXml($updateObject->detailsurl, $minimumStability); + + $updateType = (pathinfo($updateObject->detailsurl, PATHINFO_EXTENSION) === 'xml') ? 'collection' : 'tuf'; + + // Check if we have a local JSON string with update metadata + if ($updateType === 'tuf') { + // Use the correct identifier for the update channel + $updateChannel = Version::MAJOR_VERSION . '.x'; + + if ($channel === 'next') { + $updateChannel = (Version::MAJOR_VERSION + 1) . '.x'; + } + + $metadata = new TufMetadata($this->getDatabase()); + $metadata->load(['update_site_id' => $updateObject->update_site_id]); + + // Fetch update data from TUF repo + $update->loadFromTuf($metadata, $updateObject->detailsurl, $minimumStability, $updateChannel); + } else { + // We are using the legacy XML method + $update->loadFromXml($updateObject->detailsurl, $minimumStability, $channel); + } // Make sure we use the current information we got from the detailsurl $this->updateInformation['object'] = $update; @@ -370,12 +390,12 @@ public function download() $httpOptions = new Registry(); $httpOptions->set('follow_location', false); + $response = ['basename' => false, 'check' => null, 'version' => $updateInfo['latest']]; + try { $head = HttpFactory::getHttp($httpOptions)->head($packageURL); } catch (\RuntimeException $e) { // Passing false here -> download failed message - $response['basename'] = false; - return $response; } @@ -387,8 +407,6 @@ public function download() $head = HttpFactory::getHttp($httpOptions)->head($packageURL); } catch (\RuntimeException $e) { // Passing false here -> download failed message - $response['basename'] = false; - return $response; } } @@ -409,7 +427,6 @@ public function download() ) ->clean(Factory::getApplication()->get('tmp_path'), 'path'); $target = $tempdir . '/' . $basename; - $response = []; // Do we have a cached file? $exists = is_file($target); @@ -930,7 +947,7 @@ public function upload() $userfile = $input->files->get('install_package', null, 'raw'); // Make sure that file uploads are enabled in php. - if (!(bool) ini_get('file_uploads')) { + if (!(bool) \ini_get('file_uploads')) { throw new \RuntimeException(Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLFILE'), 500); } @@ -1103,7 +1120,7 @@ public function getPhpOptions() // Check for default MB language. $option = new \stdClass(); $option->label = Text::_('INSTL_MB_LANGUAGE_IS_DEFAULT'); - $option->state = strtolower(ini_get('mbstring.language')) === 'neutral'; + $option->state = strtolower(\ini_get('mbstring.language')) === 'neutral'; $option->notice = $option->state ? null : Text::_('INSTL_NOTICEMBLANGNOTDEFAULT'); $options[] = $option; } @@ -1159,28 +1176,28 @@ public function getPhpSettings() // Check for display errors. $setting = new \stdClass(); $setting->label = Text::_('INSTL_DISPLAY_ERRORS'); - $setting->state = (bool) ini_get('display_errors'); + $setting->state = (bool) \ini_get('display_errors'); $setting->recommended = false; $settings[] = $setting; // Check for file uploads. $setting = new \stdClass(); $setting->label = Text::_('INSTL_FILE_UPLOADS'); - $setting->state = (bool) ini_get('file_uploads'); + $setting->state = (bool) \ini_get('file_uploads'); $setting->recommended = true; $settings[] = $setting; // Check for output buffering. $setting = new \stdClass(); $setting->label = Text::_('INSTL_OUTPUT_BUFFERING'); - $setting->state = (int) ini_get('output_buffering') !== 0; + $setting->state = (int) \ini_get('output_buffering') !== 0; $setting->recommended = false; $settings[] = $setting; // Check for session auto-start. $setting = new \stdClass(); $setting->label = Text::_('INSTL_SESSION_AUTO_START'); - $setting->state = (bool) ini_get('session.auto_start'); + $setting->state = (bool) \ini_get('session.auto_start'); $setting->recommended = false; $settings[] = $setting; @@ -1291,7 +1308,7 @@ private function getTargetMinimumPHPVersion() */ public function getIniParserAvailability() { - $disabledFunctions = ini_get('disable_functions'); + $disabledFunctions = \ini_get('disable_functions'); if (!empty($disabledFunctions)) { // Attempt to detect them in the PHP INI disable_functions variable. diff --git a/administrator/components/com_joomlaupdate/src/View/Joomlaupdate/HtmlView.php b/administrator/components/com_joomlaupdate/src/View/Joomlaupdate/HtmlView.php index d42590fca16d7..5147b60e20b6d 100644 --- a/administrator/components/com_joomlaupdate/src/View/Joomlaupdate/HtmlView.php +++ b/administrator/components/com_joomlaupdate/src/View/Joomlaupdate/HtmlView.php @@ -233,33 +233,33 @@ public function display($tpl = null) $params = ComponentHelper::getParams('com_joomlaupdate'); switch ($params->get('updatesource', 'default')) { - // "Minor & Patch Release for Current version AND Next Major Release". case 'next': + // "Minor & Patch Release for Current version AND Next Major Release". $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_NEXT'; $this->updateSourceKey = Text::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_NEXT'); break; - // "Testing" case 'testing': + // "Testing" $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_TESTING'; $this->updateSourceKey = Text::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_TESTING'); break; - // "Custom" case 'custom': + // "Custom" $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_CUSTOM'; $this->updateSourceKey = Text::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_CUSTOM'); break; - /** - * "Minor & Patch Release for Current version (recommended and default)". - * The commented "case" below are for documenting where 'default' and legacy options falls - * case 'default': - * case 'sts': - * case 'lts': - * case 'nochange': - */ default: + /** + * "Minor & Patch Release for Current version (recommended and default)". + * The commented "case" below are for documenting where 'default' and legacy options falls + * case 'default': + * case 'sts': + * case 'lts': + * case 'nochange': + */ $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_DEFAULT'; $this->updateSourceKey = Text::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_DEFAULT'); } diff --git a/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/complete.php b/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/complete.php index cf2d9268d73d7..53b17ccf0fc6c 100644 --- a/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/complete.php +++ b/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/complete.php @@ -15,6 +15,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Uri\Uri; +/** @var \Joomla\Component\Joomlaupdate\Administrator\View\Joomlaupdate\HtmlView $this */ + $hadErrors = $this->state->get('update_finished_with_error'); $errors = $this->state->get('update_errors'); $logFile = $this->state->get('log_file'); diff --git a/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/noupdate.php b/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/noupdate.php index 5a4c9bc3d552a..5f7bcef919994 100644 --- a/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/noupdate.php +++ b/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/noupdate.php @@ -15,18 +15,20 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Joomlaupdate\Administrator\View\Joomlaupdate\HtmlView $this */ + $uploadLink = 'index.php?option=com_joomlaupdate&view=upload'; $reasonNoDownload = ''; if (!empty($this->reasonNoDownload)) { - $reasonNoDownload = Text::_($this->reasonNoDownload); + $reasonNoDownload = Text::_($this->reasonNoDownload) . '
'; if (isset($this->detailsNoDownload->php)) { $reasonNoDownload .= Text::sprintf( 'COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_PHP', $this->detailsNoDownload->php->used, $this->detailsNoDownload->php->required - ); + ) . '
'; } if (isset($this->detailsNoDownload->db)) { @@ -35,10 +37,10 @@ Text::_('JLIB_DB_SERVER_TYPE_' . $this->detailsNoDownload->db->type), $this->detailsNoDownload->db->used, $this->detailsNoDownload->db->required - ); + ) . '
'; } - $reasonNoDownload .= Text::_('COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_ACTION'); + $reasonNoDownload .= Text::_('COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_ACTION') . '
'; } $displayData = [ diff --git a/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/update.php b/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/update.php index e33840295094c..d644542c4e02d 100644 --- a/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/update.php +++ b/administrator/components/com_joomlaupdate/tmpl/joomlaupdate/update.php @@ -58,7 +58,10 @@
'; if ($this->getCurrentUser()->authorise('core.admin', 'com_joomlaupdate')) : - $displayData['formAppend'] = ''; + $displayData['formAppend'] = ' + + + '; endif; echo '
'; diff --git a/administrator/components/com_joomlaupdate/tmpl/update/default.php b/administrator/components/com_joomlaupdate/tmpl/update/default.php index f084dbdd3d127..e741ccdddec68 100644 --- a/administrator/components/com_joomlaupdate/tmpl/update/default.php +++ b/administrator/components/com_joomlaupdate/tmpl/update/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Uri\Uri; +/** @var \Joomla\Component\Joomlaupdate\Administrator\View\Update\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('core') diff --git a/administrator/components/com_joomlaupdate/tmpl/update/finaliseconfirm.php b/administrator/components/com_joomlaupdate/tmpl/update/finaliseconfirm.php index 3b9c42204b090..3c9454ad97bc1 100644 --- a/administrator/components/com_joomlaupdate/tmpl/update/finaliseconfirm.php +++ b/administrator/components/com_joomlaupdate/tmpl/update/finaliseconfirm.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Joomlaupdate\Administrator\View\Update\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive'); diff --git a/administrator/components/com_joomlaupdate/tmpl/upload/captive.php b/administrator/components/com_joomlaupdate/tmpl/upload/captive.php index b6b30e4c482bc..f5d4d61aa21b1 100644 --- a/administrator/components/com_joomlaupdate/tmpl/upload/captive.php +++ b/administrator/components/com_joomlaupdate/tmpl/upload/captive.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Joomlaupdate\Administrator\View\Upload\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('core') diff --git a/administrator/components/com_languages/src/Model/StringsModel.php b/administrator/components/com_languages/src/Model/StringsModel.php index b805f406630d0..aa1fb53b7315a 100644 --- a/administrator/components/com_languages/src/Model/StringsModel.php +++ b/administrator/components/com_languages/src/Model/StringsModel.php @@ -11,11 +11,11 @@ namespace Joomla\Component\Languages\Administrator\Model; use Joomla\CMS\Factory; -use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Language\LanguageHelper; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\Database\ParameterType; +use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; // phpcs:disable PSR1.Files.SideEffects diff --git a/administrator/components/com_languages/tmpl/installed/default.php b/administrator/components/com_languages/tmpl/installed/default.php index ec095ad9251b7..d25f390048672 100644 --- a/administrator/components/com_languages/tmpl/installed/default.php +++ b/administrator/components/com_languages/tmpl/installed/default.php @@ -17,6 +17,8 @@ use Joomla\CMS\String\PunycodeHelper; use Joomla\CMS\Version; +/** @var \Joomla\Component\Languages\Administrator\View\Installed\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns'); @@ -119,7 +121,7 @@ escape($row->author); ?>
- escape($row->authorEmail)); ?> + escape(PunycodeHelper::emailToUTF8($row->authorEmail)); ?> escape($row->extension_id); ?> diff --git a/administrator/components/com_languages/tmpl/language/edit.php b/administrator/components/com_languages/tmpl/language/edit.php index 9544fd550c1d7..0c0e5661d2502 100644 --- a/administrator/components/com_languages/tmpl/language/edit.php +++ b/administrator/components/com_languages/tmpl/language/edit.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Languages\Administrator\View\Language\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_languages/tmpl/languages/default.php b/administrator/components/com_languages/tmpl/languages/default.php index de0c97154ad95..f095c30cee57f 100644 --- a/administrator/components/com_languages/tmpl/languages/default.php +++ b/administrator/components/com_languages/tmpl/languages/default.php @@ -16,6 +16,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Languages\Administrator\View\Languages\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_languages/tmpl/multilangstatus/default.php b/administrator/components/com_languages/tmpl/multilangstatus/default.php index 00ab90ae7648b..58734a05f8965 100644 --- a/administrator/components/com_languages/tmpl/multilangstatus/default.php +++ b/administrator/components/com_languages/tmpl/multilangstatus/default.php @@ -12,6 +12,8 @@ use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Languages\Administrator\View\Multilangstatus\HtmlView $this */ + $notice_disabled = !$this->language_filter && ($this->homes > 1 || $this->switchers != 0); $notice_switchers = !$this->switchers && ($this->homes > 1 || $this->language_filter); diff --git a/administrator/components/com_languages/tmpl/override/edit.php b/administrator/components/com_languages/tmpl/override/edit.php index 81219a070469b..cea4d169c51e5 100644 --- a/administrator/components/com_languages/tmpl/override/edit.php +++ b/administrator/components/com_languages/tmpl/override/edit.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Languages\Administrator\View\Override\HtmlView $this */ + $expired = ($this->state->get('cache_expired') == 1 ) ? '1' : ''; /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ diff --git a/administrator/components/com_languages/tmpl/overrides/default.php b/administrator/components/com_languages/tmpl/overrides/default.php index 01b56bcb82919..cfba4e38e1d64 100644 --- a/administrator/components/com_languages/tmpl/overrides/default.php +++ b/administrator/components/com_languages/tmpl/overrides/default.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Languages\Administrator\View\Overrides\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_mails/src/Model/TemplateModel.php b/administrator/components/com_mails/src/Model/TemplateModel.php index 3c79464970a7e..3009be1f6c000 100644 --- a/administrator/components/com_mails/src/Model/TemplateModel.php +++ b/administrator/components/com_mails/src/Model/TemplateModel.php @@ -148,7 +148,7 @@ public function getForm($data = [], $loadData = true) * * @param integer $pk The id of the primary key. * - * @return CMSObject|boolean Object on success, false on failure. + * @return \stdClass|boolean Object on success, false on failure. * * @since 4.0.0 */ @@ -195,7 +195,7 @@ public function getItem($pk = null) * * @param integer $pk The id of the primary key. * - * @return CMSObject|boolean Object on success, false on failure. + * @return \stdClass|boolean Object on success, false on failure. * * @since 4.0.0 */ diff --git a/administrator/components/com_mails/tmpl/template/edit.php b/administrator/components/com_mails/tmpl/template/edit.php index b5ae34d6d156d..5693ef8e66ad3 100644 --- a/administrator/components/com_mails/tmpl/template/edit.php +++ b/administrator/components/com_mails/tmpl/template/edit.php @@ -18,6 +18,8 @@ use Joomla\CMS\Router\Route; use Joomla\Component\Mails\Administrator\Helper\MailsHelper; +/** @var \Joomla\Component\Mails\Administrator\View\Template\HtmlView $this */ + $app = Factory::getApplication(); /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ diff --git a/administrator/components/com_mails/tmpl/templates/default.php b/administrator/components/com_mails/tmpl/templates/default.php index aa5a86f422136..daa96aa87bf08 100644 --- a/administrator/components/com_mails/tmpl/templates/default.php +++ b/administrator/components/com_mails/tmpl/templates/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Mails\Administrator\View\Templates\HtmlView $this */ + HTMLHelper::_('bootstrap.dropdown', '.dropdown-toggle'); /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ diff --git a/administrator/components/com_media/src/Controller/ApiController.php b/administrator/components/com_media/src/Controller/ApiController.php index 6ee85b357b2b8..530f97a0db6cb 100644 --- a/administrator/components/com_media/src/Controller/ApiController.php +++ b/administrator/components/com_media/src/Controller/ApiController.php @@ -347,9 +347,9 @@ private function checkContent() $contentLength = $this->input->server->getInt('CONTENT_LENGTH'); $params = ComponentHelper::getParams('com_media'); $paramsUploadMaxsize = $params->get('upload_maxsize', 0) * 1024 * 1024; - $uploadMaxFilesize = $helper->toBytes(ini_get('upload_max_filesize')); - $postMaxSize = $helper->toBytes(ini_get('post_max_size')); - $memoryLimit = $helper->toBytes(ini_get('memory_limit')); + $uploadMaxFilesize = $helper->toBytes(\ini_get('upload_max_filesize')); + $postMaxSize = $helper->toBytes(\ini_get('post_max_size')); + $memoryLimit = $helper->toBytes(\ini_get('memory_limit')); if ( ($paramsUploadMaxsize > 0 && $contentLength > $paramsUploadMaxsize) diff --git a/administrator/components/com_media/src/Controller/PluginController.php b/administrator/components/com_media/src/Controller/PluginController.php index f9f6c4210a815..b97b636fdeb71 100644 --- a/administrator/components/com_media/src/Controller/PluginController.php +++ b/administrator/components/com_media/src/Controller/PluginController.php @@ -94,16 +94,16 @@ public function oauthcallback() * - control-panel : Redirect to Control Panel */ switch ($action) { - /** - * Close a window opened by developer - * Use this for close New Windows opened for OAuth Process - */ case 'close': + /** + * Close a window opened by developer + * Use this for close New Windows opened for OAuth Process + */ $this->setRedirect(Route::_('index.php?option=com_media&view=plugin&action=close', false)); break; - // Redirect browser to any page specified by the user case 'redirect': + // Redirect browser to any page specified by the user if (!isset($eventResults['redirect_uri'])) { throw new \Exception("Redirect URI must be set in the plugin"); } @@ -111,14 +111,14 @@ public function oauthcallback() $this->setRedirect($eventResults['redirect_uri']); break; - // Redirect browser to Control Panel case 'control-panel': + // Redirect browser to Control Panel $this->setRedirect(Route::_('index.php', false)); break; - // Redirect browser to Media Manager case 'media-manager': default: + // Redirect browser to Media Manager $this->setRedirect(Route::_('index.php?option=com_media&view=media', false)); } } catch (\Exception $e) { diff --git a/administrator/components/com_media/tmpl/file/default.php b/administrator/components/com_media/tmpl/file/default.php index cf16967e77cfe..fd3dc6accd914 100644 --- a/administrator/components/com_media/tmpl/file/default.php +++ b/administrator/components/com_media/tmpl/file/default.php @@ -17,6 +17,8 @@ use Joomla\CMS\Session\Session; use Joomla\CMS\Uri\Uri; +/** @var \Joomla\Component\Media\Administrator\View\File\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_media/tmpl/media/default.php b/administrator/components/com_media/tmpl/media/default.php index efb12c82bc261..1fbfb41333e94 100644 --- a/administrator/components/com_media/tmpl/media/default.php +++ b/administrator/components/com_media/tmpl/media/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Session\Session; use Joomla\CMS\Uri\Uri; +/** @var \Joomla\Component\Media\Administrator\View\Media\HtmlView $this */ + $app = Factory::getApplication(); $params = ComponentHelper::getParams('com_media'); $input = $app->getInput(); diff --git a/administrator/components/com_menus/forms/item_alias.xml b/administrator/components/com_menus/forms/item_alias.xml index cdb89b2be200c..6ef0572ada7d8 100644 --- a/administrator/components/com_menus/forms/item_alias.xml +++ b/administrator/components/com_menus/forms/item_alias.xml @@ -58,6 +58,9 @@ diff --git a/administrator/components/com_menus/forms/item_component.xml b/administrator/components/com_menus/forms/item_component.xml index 82bc08fef8af6..ca2cf0728aab1 100644 --- a/administrator/components/com_menus/forms/item_component.xml +++ b/administrator/components/com_menus/forms/item_component.xml @@ -27,6 +27,9 @@ diff --git a/administrator/components/com_menus/forms/item_heading.xml b/administrator/components/com_menus/forms/item_heading.xml index b4ce4ce2bf967..38b5b1ef87902 100644 --- a/administrator/components/com_menus/forms/item_heading.xml +++ b/administrator/components/com_menus/forms/item_heading.xml @@ -28,6 +28,9 @@ diff --git a/administrator/components/com_menus/forms/item_separator.xml b/administrator/components/com_menus/forms/item_separator.xml index 20f0544445275..63371c6845258 100644 --- a/administrator/components/com_menus/forms/item_separator.xml +++ b/administrator/components/com_menus/forms/item_separator.xml @@ -23,6 +23,9 @@ diff --git a/administrator/components/com_menus/forms/item_url.xml b/administrator/components/com_menus/forms/item_url.xml index 21850df4abb4f..7b58b121adfae 100644 --- a/administrator/components/com_menus/forms/item_url.xml +++ b/administrator/components/com_menus/forms/item_url.xml @@ -54,6 +54,9 @@ diff --git a/administrator/components/com_menus/forms/itemadmin_alias.xml b/administrator/components/com_menus/forms/itemadmin_alias.xml index 2e4077f90205f..714233ecc6966 100644 --- a/administrator/components/com_menus/forms/itemadmin_alias.xml +++ b/administrator/components/com_menus/forms/itemadmin_alias.xml @@ -38,6 +38,9 @@ diff --git a/administrator/components/com_menus/forms/itemadmin_component.xml b/administrator/components/com_menus/forms/itemadmin_component.xml index 8724d6401119f..c5196cfc77c3a 100644 --- a/administrator/components/com_menus/forms/itemadmin_component.xml +++ b/administrator/components/com_menus/forms/itemadmin_component.xml @@ -22,6 +22,9 @@ diff --git a/administrator/components/com_menus/forms/itemadmin_container.xml b/administrator/components/com_menus/forms/itemadmin_container.xml index d6c07c0cdd9ee..bbf75ff074e08 100644 --- a/administrator/components/com_menus/forms/itemadmin_container.xml +++ b/administrator/components/com_menus/forms/itemadmin_container.xml @@ -35,6 +35,9 @@ diff --git a/administrator/components/com_menus/forms/itemadmin_heading.xml b/administrator/components/com_menus/forms/itemadmin_heading.xml index 8aba60deaae8b..25181bcbb17de 100644 --- a/administrator/components/com_menus/forms/itemadmin_heading.xml +++ b/administrator/components/com_menus/forms/itemadmin_heading.xml @@ -35,6 +35,9 @@ diff --git a/administrator/components/com_menus/forms/itemadmin_url.xml b/administrator/components/com_menus/forms/itemadmin_url.xml index 3f2b932dc55d8..355cee6896b47 100644 --- a/administrator/components/com_menus/forms/itemadmin_url.xml +++ b/administrator/components/com_menus/forms/itemadmin_url.xml @@ -52,6 +52,9 @@ diff --git a/administrator/components/com_menus/layouts/joomla/form/field/modal-select/extra-buttons.php b/administrator/components/com_menus/layouts/joomla/form/field/modal-select/extra-buttons.php index 9be694b742ae9..6e80b7335a8ec 100644 --- a/administrator/components/com_menus/layouts/joomla/form/field/modal-select/extra-buttons.php +++ b/administrator/components/com_menus/layouts/joomla/form/field/modal-select/extra-buttons.php @@ -13,6 +13,8 @@ use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; +/** @var \Joomla\CMS\Layout\FileLayout $this */ + extract($displayData); /** diff --git a/administrator/components/com_menus/layouts/joomla/searchtools/default.php b/administrator/components/com_menus/layouts/joomla/searchtools/default.php index b9df8a0febc9d..3fdb3ef5c02d7 100644 --- a/administrator/components/com_menus/layouts/joomla/searchtools/default.php +++ b/administrator/components/com_menus/layouts/joomla/searchtools/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\CMS\Layout\FileLayout $this */ + $data = $displayData; // Receive overridable options diff --git a/administrator/components/com_menus/src/Controller/DisplayController.php b/administrator/components/com_menus/src/Controller/DisplayController.php index 5eba2c6ef97c5..a7b189860d64a 100644 --- a/administrator/components/com_menus/src/Controller/DisplayController.php +++ b/administrator/components/com_menus/src/Controller/DisplayController.php @@ -48,7 +48,7 @@ class DisplayController extends BaseController public function display($cachable = false, $urlparams = false) { // Verify menu - $menuType = $this->input->post->getCmd('menutype', ''); + $menuType = $this->input->post->getString('menutype', ''); if ($menuType !== '') { $uri = Uri::getInstance(); diff --git a/administrator/components/com_menus/src/Field/MenutypeField.php b/administrator/components/com_menus/src/Field/MenutypeField.php index 389b4291d4ece..a4cd9cb3d1601 100644 --- a/administrator/components/com_menus/src/Field/MenutypeField.php +++ b/administrator/components/com_menus/src/Field/MenutypeField.php @@ -13,7 +13,6 @@ use Joomla\CMS\Factory; use Joomla\CMS\Form\Field\ModalSelectField; use Joomla\CMS\Language\Text; -use Joomla\CMS\Router\Route; use Joomla\Component\Menus\Administrator\Helper\MenusHelper; use Joomla\Utilities\ArrayHelper; @@ -59,7 +58,7 @@ public function setup(\SimpleXMLElement $element, $value, $group = null) $recordId = (int) $this->form->getValue('id'); $clientId = (int) $this->element['clientid'] ?: 0; - $url = Route::_('index.php?option=com_menus&view=menutypes&tmpl=component&client_id=' . $clientId . '&recordId=' . $recordId, false); + $url = 'index.php?option=com_menus&view=menutypes&tmpl=component&client_id=' . $clientId . '&recordId=' . $recordId; $this->urls['select'] = $url; $this->canDo['clear'] = false; diff --git a/administrator/components/com_menus/src/Helper/MenusHelper.php b/administrator/components/com_menus/src/Helper/MenusHelper.php index 4ba123ed1f344..5accb07200ac1 100644 --- a/administrator/components/com_menus/src/Helper/MenusHelper.php +++ b/administrator/components/com_menus/src/Helper/MenusHelper.php @@ -14,7 +14,6 @@ use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Event\Menu\PreprocessMenuItemsEvent; use Joomla\CMS\Factory; -use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Associations; use Joomla\CMS\Language\Multilanguage; @@ -24,6 +23,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\ParameterType; use Joomla\Filesystem\File; +use Joomla\Filesystem\Folder; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects @@ -615,7 +615,7 @@ public static function getPresets() $folder = JPATH_ADMINISTRATOR . '/components/' . $component->option . '/presets/'; - if (!Folder::exists($folder)) { + if (!is_dir($folder)) { continue; } diff --git a/administrator/components/com_menus/src/View/Items/HtmlView.php b/administrator/components/com_menus/src/View/Items/HtmlView.php index 5f01072d44d69..6d30bff5426b2 100644 --- a/administrator/components/com_menus/src/View/Items/HtmlView.php +++ b/administrator/components/com_menus/src/View/Items/HtmlView.php @@ -141,7 +141,7 @@ public function display($tpl = null) case 'component': default: // Load language - $lang->load($item->componentname . '.sys', JPATH_ADMINISTRATOR) + $lang->load($item->componentname . '.sys', JPATH_ADMINISTRATOR) || $lang->load($item->componentname . '.sys', JPATH_ADMINISTRATOR . '/components/' . $item->componentname); if (!empty($item->componentname)) { diff --git a/administrator/components/com_menus/tmpl/item/edit.php b/administrator/components/com_menus/tmpl/item/edit.php index 112b5b53a5296..353b212586e84 100644 --- a/administrator/components/com_menus/tmpl/item/edit.php +++ b/administrator/components/com_menus/tmpl/item/edit.php @@ -17,6 +17,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Menus\Administrator\View\Item\HtmlView $this */ + $this->useCoreUI = true; Text::script('ERROR'); diff --git a/administrator/components/com_menus/tmpl/item/edit_container.php b/administrator/components/com_menus/tmpl/item/edit_container.php index 53f7d07060971..0d54be3df71b7 100644 --- a/administrator/components/com_menus/tmpl/item/edit_container.php +++ b/administrator/components/com_menus/tmpl/item/edit_container.php @@ -14,6 +14,8 @@ use Joomla\Component\Menus\Administrator\Helper\MenusHelper; use Joomla\Registry\Registry; +/** @var \Joomla\Component\Menus\Administrator\View\Item\HtmlView $this */ + // Initialise related data. $menuLinks = MenusHelper::getMenuLinks('main'); diff --git a/administrator/components/com_menus/tmpl/item/edit_modules.php b/administrator/components/com_menus/tmpl/item/edit_modules.php index 1c04727793f36..aff598b16a0eb 100644 --- a/administrator/components/com_menus/tmpl/item/edit_modules.php +++ b/administrator/components/com_menus/tmpl/item/edit_modules.php @@ -10,39 +10,34 @@ defined('_JEXEC') or die; -use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; +use Joomla\CMS\Router\Route; + +/** @var \Joomla\Component\Menus\Administrator\View\Item\HtmlView $this */ foreach ($this->levels as $key => $value) { $allLevels[$value->id] = $value->title; } -$this->document->addScriptOptions('menus-edit-modules', ['viewLevels' => $allLevels, 'itemId' => $this->item->id]); +$this->document->addScriptOptions('menus-edit-modules', ['viewLevels' => $allLevels, 'itemId' => (int) $this->item->id]); /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); -$wa->useScript('com_menus.admin-item-edit-modules'); +$wa->useScript('com_menus.admin-item-edit-modules') + ->useScript('joomla.dialog-autocreate'); + +// Set up the modal options that will be used for module editor +$popupOptions = [ + 'popupType' => 'iframe', + 'textHeader' => Text::_('COM_MENUS_EDIT_MODULE_SETTINGS'), + 'className' => 'menus-dialog-module-editing', +]; -// Set up the bootstrap modal that will be used for all module editors -echo HTMLHelper::_( - 'bootstrap.renderModal', - 'moduleEditModal', - [ - 'title' => Text::_('COM_MENUS_EDIT_MODULE_SETTINGS'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'bodyHeight' => '70', - 'modalWidth' => '80', - 'footer' => '' - . '' - . '', - ] -); +Text::script('JNO'); +Text::script('JYES'); +Text::script('JALL'); +Text::script('JTRASHED'); ?>
+ id, false); ?> diff --git a/administrator/components/com_menus/tmpl/item/modal.php b/administrator/components/com_menus/tmpl/item/modal.php index b7bbf2e26482a..91a77916d4071 100644 --- a/administrator/components/com_menus/tmpl/item/modal.php +++ b/administrator/components/com_menus/tmpl/item/modal.php @@ -10,6 +10,7 @@ defined('_JEXEC') or die; +/** @var \Joomla\Component\Menus\Administrator\View\Item\HtmlView $this */ ?>
document->getToolbar('toolbar')->render(); ?> diff --git a/administrator/components/com_menus/tmpl/item/modalreturn.php b/administrator/components/com_menus/tmpl/item/modalreturn.php index 19849246f275e..b3cbe7817dd2b 100644 --- a/administrator/components/com_menus/tmpl/item/modalreturn.php +++ b/administrator/components/com_menus/tmpl/item/modalreturn.php @@ -10,6 +10,8 @@ defined('_JEXEC') or die; +/** @var \Joomla\Component\Menus\Administrator\View\Item\HtmlView $this */ + $icon = 'icon-check'; $title = $this->item ? $this->item->title : ''; $content = $this->item ? $this->item->alias : ''; diff --git a/administrator/components/com_menus/tmpl/items/default.php b/administrator/components/com_menus/tmpl/items/default.php index 6e76fe5894fcb..bb7a075f2f6ae 100644 --- a/administrator/components/com_menus/tmpl/items/default.php +++ b/administrator/components/com_menus/tmpl/items/default.php @@ -19,6 +19,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Menus\Administrator\View\Items\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_menus/tmpl/items/default_batch_body.php b/administrator/components/com_menus/tmpl/items/default_batch_body.php index 7d0ee8fa7a24c..229931615f9d3 100644 --- a/administrator/components/com_menus/tmpl/items/default_batch_body.php +++ b/administrator/components/com_menus/tmpl/items/default_batch_body.php @@ -16,6 +16,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Menus\Administrator\View\Items\HtmlView $this */ + $options = [ HTMLHelper::_('select.option', 'c', Text::_('JLIB_HTML_BATCH_COPY')), HTMLHelper::_('select.option', 'm', Text::_('JLIB_HTML_BATCH_MOVE')) diff --git a/administrator/components/com_menus/tmpl/items/modal.php b/administrator/components/com_menus/tmpl/items/modal.php index 0943ac02a5fc2..70cae7c6e3228 100644 --- a/administrator/components/com_menus/tmpl/items/modal.php +++ b/administrator/components/com_menus/tmpl/items/modal.php @@ -18,6 +18,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Menus\Administrator\View\Items\HtmlView $this */ + $app = Factory::getApplication(); if ($app->isClient('site')) { @@ -33,14 +35,14 @@ $editor = $app->getInput()->getCmd('editor', ''); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); -$link = 'index.php?option=com_menus&view=items&layout=modal&tmpl=component&' . Session::getFormToken() . '=1'; +$link = 'index.php?option=com_menus&view=items&layout=modal&tmpl=component&' . Session::getFormToken() . '=1&function=' . $function; $multilang = Multilanguage::isEnabled(); if (!empty($editor)) { // This view is used also in com_menus. Load the xtd script only if the editor is set! $this->document->addScriptOptions('xtd-menus', ['editor' => $editor]); $onclick = "jSelectMenuItem"; - $link = 'index.php?option=com_menus&view=items&layout=modal&tmpl=component&editor=' . $editor . '&' . Session::getFormToken() . '=1'; + $link = 'index.php?option=com_menus&view=items&layout=modal&tmpl=component&editor=' . $editor . '&' . Session::getFormToken() . '=1&function=' . $function; } ?>
@@ -186,7 +188,6 @@ - diff --git a/administrator/components/com_menus/tmpl/menu/edit.php b/administrator/components/com_menus/tmpl/menu/edit.php index 186b659dce12b..85cc6ddaad905 100644 --- a/administrator/components/com_menus/tmpl/menu/edit.php +++ b/administrator/components/com_menus/tmpl/menu/edit.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Menus\Administrator\View\Menu\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('core') diff --git a/administrator/components/com_menus/tmpl/menus/default.php b/administrator/components/com_menus/tmpl/menus/default.php index 808a6a6661c4f..de22ecbcff54a 100644 --- a/administrator/components/com_menus/tmpl/menus/default.php +++ b/administrator/components/com_menus/tmpl/menus/default.php @@ -17,11 +17,14 @@ use Joomla\CMS\Session\Session; use Joomla\CMS\Uri\Uri; +/** @var \Joomla\Component\Menus\Administrator\View\Menus\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect') - ->useScript('com_menus.admin-menus'); + ->useScript('com_menus.admin-menus') + ->useScript('joomla.dialog-autocreate'); $uri = Uri::getInstance(); $return = base64_encode($uri); @@ -45,6 +48,17 @@ } $this->document->addScriptOptions('menus-default', ['items' => $itemIds]); + +// Set up the modal options that will be used for module editor +$popupOptionsEdit = [ + 'popupType' => 'iframe', + 'textHeader' => Text::_('COM_MENUS_EDIT_MODULE_SETTINGS'), +]; +$popupOptionsAdd = [ + 'popupType' => 'iframe', + 'textHeader' => Text::_('COM_MENUS_ADD_MENU_MODULE'), +]; + ?>
@@ -209,10 +223,13 @@
- modules[$item->menutype] as &$module) : ?> - authorise('core.edit', 'com_modules.module.' . (int) $module->id)) : ?> - id . '&return=' . $return . '&tmpl=component&layout=modal'); ?> - id . 'Modal', - [ - 'title' => Text::_('COM_MENUS_EDIT_MODULE_SETTINGS'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'url' => $link, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => 70, - 'modalWidth' => 80, - 'footer' => '' - . '' - . '', - ] - ); ?> - - - menutype . '&tmpl=component&layout=modal'); ?> - - Text::_('COM_MENUS_ADD_MENU_MODULE'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'url' => $link, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => 70, - 'modalWidth' => 80, - 'footer' => '' - . '' - . '', - ] - ); ?> + menutype, false); ?> +
diff --git a/administrator/components/com_menus/tmpl/menutypes/default.php b/administrator/components/com_menus/tmpl/menutypes/default.php index 9fd75139cc897..525ede44dec0a 100644 --- a/administrator/components/com_menus/tmpl/menutypes/default.php +++ b/administrator/components/com_menus/tmpl/menutypes/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Menus\Administrator\View\Menutypes\HtmlView $this */ + $input = Factory::getApplication()->getInput(); // Checking if loaded via index.php or component.php diff --git a/administrator/components/com_messages/tmpl/config/default.php b/administrator/components/com_messages/tmpl/config/default.php index 862c2a06f37d8..350bd8fea815b 100644 --- a/administrator/components/com_messages/tmpl/config/default.php +++ b/administrator/components/com_messages/tmpl/config/default.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Messages\Administrator\View\Config\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_messages/tmpl/message/default.php b/administrator/components/com_messages/tmpl/message/default.php index dde01606099ca..0bd7249090f09 100644 --- a/administrator/components/com_messages/tmpl/message/default.php +++ b/administrator/components/com_messages/tmpl/message/default.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Messages\Administrator\View\Message\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('core'); diff --git a/administrator/components/com_messages/tmpl/message/edit.php b/administrator/components/com_messages/tmpl/message/edit.php index 00b33c96a3702..33b0335f4ec32 100644 --- a/administrator/components/com_messages/tmpl/message/edit.php +++ b/administrator/components/com_messages/tmpl/message/edit.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Messages\Administrator\View\Message\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_messages/tmpl/messages/default.php b/administrator/components/com_messages/tmpl/messages/default.php index 9c3eae151b8ae..3dd9fc1c5b449 100644 --- a/administrator/components/com_messages/tmpl/messages/default.php +++ b/administrator/components/com_messages/tmpl/messages/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Messages\Administrator\View\Messages\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('multiselect'); diff --git a/administrator/components/com_messages/tmpl/messages/emptystate.php b/administrator/components/com_messages/tmpl/messages/emptystate.php index 957b2d88c32aa..1a81bdd7d8279 100644 --- a/administrator/components/com_messages/tmpl/messages/emptystate.php +++ b/administrator/components/com_messages/tmpl/messages/emptystate.php @@ -12,6 +12,8 @@ use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Messages\Administrator\View\Messages\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_MESSAGES', 'formURL' => 'index.php?option=com_messages&view=messages', diff --git a/administrator/components/com_modules/layouts/joomla/form/field/modulespositionedit.php b/administrator/components/com_modules/layouts/joomla/form/field/modulespositionedit.php index 0bca7122aa695..80fac83fdd7db 100644 --- a/administrator/components/com_modules/layouts/joomla/form/field/modulespositionedit.php +++ b/administrator/components/com_modules/layouts/joomla/form/field/modulespositionedit.php @@ -14,6 +14,8 @@ use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; +/** @var \Joomla\CMS\Layout\FileLayout $this */ + extract($displayData); /** diff --git a/administrator/components/com_modules/src/Controller/ModuleController.php b/administrator/components/com_modules/src/Controller/ModuleController.php index b60e88fbcbdde..ac3fbc7d544ec 100644 --- a/administrator/components/com_modules/src/Controller/ModuleController.php +++ b/administrator/components/com_modules/src/Controller/ModuleController.php @@ -92,6 +92,13 @@ public function cancel($key = null) } $this->app->redirect($return); + } elseif ($result && $this->input->get('layout') === 'modal') { + // When editing in modal then redirect to modalreturn layout + $id = $this->input->get('id'); + $return = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($id) + . '&layout=modalreturn&from-task=cancel'; + + $this->setRedirect(Route::_($return, false)); } return $result; @@ -193,6 +200,15 @@ protected function postSaveHook(BaseDatabaseModel $model, $validData = []) break; default: + if ($this->input->get('layout') === 'modal' && $this->task === 'save') { + // When editing in modal then redirect to modalreturn layout + $id = $model->getState('module.id', ''); + $return = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($id) + . '&layout=modalreturn&from-task=save'; + + $this->setRedirect(Route::_($return, false)); + } + $this->app->setUserState('com_modules.add.module.extension_id', null); break; } diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index a0500393df7fe..406b9949b6c3b 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -13,7 +13,6 @@ use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; -use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Form\Form; use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\Language\Text; @@ -24,6 +23,7 @@ use Joomla\CMS\Table\Table; use Joomla\Component\Modules\Administrator\Helper\ModulesHelper; use Joomla\Database\ParameterType; +use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; use Joomla\Registry\Registry; use Joomla\String\StringHelper; diff --git a/administrator/components/com_modules/src/View/Module/HtmlView.php b/administrator/components/com_modules/src/View/Module/HtmlView.php index d270bb8bccc6b..52c22cbe56b08 100644 --- a/administrator/components/com_modules/src/View/Module/HtmlView.php +++ b/administrator/components/com_modules/src/View/Module/HtmlView.php @@ -68,17 +68,36 @@ class HtmlView extends BaseHtmlView */ public function display($tpl = null) { + $this->state = $this->get('State'); + + // Have to stop it earlier, because on cancel task for a new module we do not have an ID, and Model doing redirect on getItem() + if ($this->getLayout() === 'modalreturn' && !$this->state->get('module.id')) { + parent::display($tpl); + + return; + } + $this->form = $this->get('Form'); $this->item = $this->get('Item'); - $this->state = $this->get('State'); $this->canDo = ContentHelper::getActions('com_modules', 'module', $this->item->id); + if ($this->getLayout() === 'modalreturn') { + parent::display($tpl); + + return; + } + // Check for errors. if (\count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } - $this->addToolbar(); + if ($this->getLayout() !== 'modal') { + $this->addToolbar(); + } else { + $this->addModalToolbar(); + } + parent::display($tpl); } @@ -161,4 +180,33 @@ function (Toolbar $childBar) use ($checkedOut, $canDo) { $toolbar->inlinehelp(); $toolbar->help($help->key, false, $url); } + + /** + * Add the modal toolbar. + * + * @return void + * + * @since 5.1.0 + * + * @throws \Exception + */ + protected function addModalToolbar() + { + $isNew = ($this->item->id == 0); + $toolbar = Toolbar::getInstance(); + $canDo = $this->canDo; + + ToolbarHelper::title(Text::sprintf('COM_MODULES_MANAGER_MODULE', Text::_($this->item->module)), 'cube module'); + + $canCreate = $isNew && $canDo->get('core.create'); + $canEdit = $canDo->get('core.edit'); + + // For new records, check the create permission. + if ($canCreate || $canEdit) { + $toolbar->apply('module.apply'); + $toolbar->save('module.save'); + } + + $toolbar->cancel('module.cancel'); + } } diff --git a/administrator/components/com_modules/tmpl/module/edit.php b/administrator/components/com_modules/tmpl/module/edit.php index 0f05e5bc929ae..a51a1f02bd9de 100644 --- a/administrator/components/com_modules/tmpl/module/edit.php +++ b/administrator/components/com_modules/tmpl/module/edit.php @@ -16,9 +16,11 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Modules\Administrator\View\Module\HtmlView $this */ + HTMLHelper::_('behavior.combobox'); -$hasContent = isset($this->item->xml->customContent); +$hasContent = isset($this->item->xml->customContent); $hasContentFieldName = 'content'; // For a later improvement @@ -40,8 +42,7 @@ /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') - ->useScript('form.validate') - ->useScript('com_modules.admin-module-edit'); + ->useScript('form.validate'); $input = Factory::getApplication()->getInput(); diff --git a/administrator/components/com_modules/tmpl/module/edit_assignment.php b/administrator/components/com_modules/tmpl/module/edit_assignment.php index e6591f7dd64f4..072844cd50d28 100644 --- a/administrator/components/com_modules/tmpl/module/edit_assignment.php +++ b/administrator/components/com_modules/tmpl/module/edit_assignment.php @@ -16,6 +16,8 @@ use Joomla\Component\Menus\Administrator\Helper\MenusHelper; use Joomla\Component\Modules\Administrator\Helper\ModulesHelper; +/** @var \Joomla\Component\Modules\Administrator\View\Module\HtmlView $this */ + // Initialise related data. $menuTypes = MenusHelper::getMenuLinks(); @@ -123,7 +125,7 @@ - + diff --git a/administrator/components/com_redirect/src/Controller/DisplayController.php b/administrator/components/com_redirect/src/Controller/DisplayController.php index f2caf776e10a9..7604209d1f427 100644 --- a/administrator/components/com_redirect/src/Controller/DisplayController.php +++ b/administrator/components/com_redirect/src/Controller/DisplayController.php @@ -10,12 +10,9 @@ namespace Joomla\Component\Redirect\Administrator\Controller; -use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\BaseController; -use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Router\Route; -use Joomla\Component\Redirect\Administrator\Helper\RedirectHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; @@ -51,33 +48,6 @@ public function display($cachable = false, $urlparams = false) $layout = $this->input->get('layout', 'default'); $id = $this->input->getInt('id'); - if ($view === 'links') { - $pluginEnabled = PluginHelper::isEnabled('system', 'redirect'); - $collectUrlsEnabled = RedirectHelper::collectUrlsEnabled(); - - // Show messages about the enabled plugin and if the plugin should collect URLs - if ($pluginEnabled && $collectUrlsEnabled) { - $this->app->enqueueMessage(Text::sprintf('COM_REDIRECT_COLLECT_URLS_ENABLED', Text::_('COM_REDIRECT_PLUGIN_ENABLED')), 'notice'); - } else { - $redirectPluginId = RedirectHelper::getRedirectPluginId(); - $link = HTMLHelper::_( - 'link', - '#plugin' . $redirectPluginId . 'Modal', - Text::_('COM_REDIRECT_SYSTEM_PLUGIN'), - 'class="alert-link" data-bs-toggle="modal" id="title-' . $redirectPluginId . '"' - ); - - if ($pluginEnabled && !$collectUrlsEnabled) { - $this->app->enqueueMessage( - Text::sprintf('COM_REDIRECT_COLLECT_MODAL_URLS_DISABLED', Text::_('COM_REDIRECT_PLUGIN_ENABLED'), $link), - 'notice' - ); - } else { - $this->app->enqueueMessage(Text::sprintf('COM_REDIRECT_PLUGIN_MODAL_DISABLED', $link), 'error'); - } - } - } - // Check for edit form. if ($view == 'link' && $layout == 'edit' && !$this->checkEditId('com_redirect.edit.link', $id)) { // Somehow the person just went to the form - we don't allow that. diff --git a/administrator/components/com_redirect/src/View/Links/HtmlView.php b/administrator/components/com_redirect/src/View/Links/HtmlView.php index 965dd89325410..1ec882441f11c 100644 --- a/administrator/components/com_redirect/src/View/Links/HtmlView.php +++ b/administrator/components/com_redirect/src/View/Links/HtmlView.php @@ -205,7 +205,11 @@ protected function addToolbar() if ($canDo->get('core.create')) { $toolbar->popupButton('batch', 'JTOOLBAR_BULK_IMPORT') - ->selector('collapseModal') + ->popupType('inline') + ->textHeader(Text::_('COM_REDIRECT_BATCH_OPTIONS')) + ->url('#joomla-dialog-batch') + ->modalWidth('800px') + ->modalHeight('fit-content') ->listCheck(false); } diff --git a/administrator/components/com_redirect/tmpl/link/edit.php b/administrator/components/com_redirect/tmpl/link/edit.php index 9117e79dbd40e..d41c724590ddf 100644 --- a/administrator/components/com_redirect/tmpl/link/edit.php +++ b/administrator/components/com_redirect/tmpl/link/edit.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Redirect\Administrator\View\Link\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_redirect/tmpl/links/default.php b/administrator/components/com_redirect/tmpl/links/default.php index 46f326d2951fb..e81aad36e1587 100644 --- a/administrator/components/com_redirect/tmpl/links/default.php +++ b/administrator/components/com_redirect/tmpl/links/default.php @@ -10,50 +10,66 @@ defined('_JEXEC') or die; +use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Uri\Uri; +use Joomla\Component\Redirect\Administrator\Helper\RedirectHelper; + +/** @var \Joomla\Component\Redirect\Administrator\View\Link\HtmlView $this */ /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') - ->useScript('multiselect'); + ->useScript('multiselect') + ->useScript('joomla.dialog-autocreate'); +$app = Factory::getApplication(); $user = $this->getCurrentUser(); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); + +$collectUrlsEnabled = RedirectHelper::collectUrlsEnabled(); +$redirectPluginId = $this->redirectPluginId; + +// Show messages about the enabled plugin and if the plugin should collect URLs +if (!$redirectPluginId && $collectUrlsEnabled) { + $app->enqueueMessage(Text::sprintf('COM_REDIRECT_COLLECT_URLS_ENABLED', Text::_('COM_REDIRECT_PLUGIN_ENABLED')), 'warning'); +} else { + $popupOptions = [ + 'popupType' => 'iframe', + 'textHeader' => Text::_('COM_REDIRECT_EDIT_PLUGIN_SETTINGS'), + 'src' => Route::_('index.php?option=com_plugins&client_id=0&task=plugin.edit&extension_id=' . $redirectPluginId . '&tmpl=component&layout=modal', false), + ]; + $link = HTMLHelper::_( + 'link', + '#', + Text::_('COM_REDIRECT_SYSTEM_PLUGIN'), + [ + 'class' => 'alert-link', + 'data-joomla-dialog' => $this->escape(json_encode($popupOptions, JSON_UNESCAPED_SLASHES)), + 'data-checkin-url' => Route::_('index.php?option=com_plugins&task=plugins.checkin&format=json&cid[]=' . $redirectPluginId), + 'data-close-on-message' => '', + 'data-reload-on-close' => '', + ], + ); + + if (!$redirectPluginId && !$collectUrlsEnabled) { + $app->enqueueMessage( + Text::sprintf('COM_REDIRECT_COLLECT_MODAL_URLS_DISABLED', Text::_('COM_REDIRECT_PLUGIN_ENABLED'), $link), + 'warning' + ); + } else { + $app->enqueueMessage(Text::sprintf('COM_REDIRECT_PLUGIN_MODAL_DISABLED', $link), 'error'); + } +} + ?>
$this]); ?> - redirectPluginId) : ?> - redirectPluginId . '&tmpl=component&layout=modal'); ?> - redirectPluginId . 'Modal', - [ - 'url' => $link, - 'title' => Text::_('COM_REDIRECT_EDIT_PLUGIN_SETTINGS'), - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => '70', - 'modalWidth' => '80', - 'closeButton' => false, - 'backdrop' => 'static', - 'keyboard' => false, - 'footer' => '' - . '' - . '' - ] - ); ?> - - items)) : ?>
@@ -156,15 +172,7 @@ && $user->authorise('core.edit', 'com_redirect') && $user->authorise('core.edit.state', 'com_redirect') ) : ?> - Text::_('COM_REDIRECT_BATCH_OPTIONS'), - 'footer' => $this->loadTemplate('batch_footer'), - ], - $this->loadTemplate('batch_body') - ); ?> + diff --git a/administrator/components/com_redirect/tmpl/links/default_batch_body.php b/administrator/components/com_redirect/tmpl/links/default_batch_body.php index 052eef41afe42..b90e0d675b3b2 100644 --- a/administrator/components/com_redirect/tmpl/links/default_batch_body.php +++ b/administrator/components/com_redirect/tmpl/links/default_batch_body.php @@ -12,6 +12,8 @@ use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Redirect\Administrator\View\Links\HtmlView $this */ + $published = $this->state->get('filter.published'); $params = $this->params; $separator = $params->get('separator', '|'); @@ -22,8 +24,13 @@
- +
+
+ + + +
diff --git a/administrator/components/com_redirect/tmpl/links/default_batch_footer.php b/administrator/components/com_redirect/tmpl/links/default_batch_footer.php deleted file mode 100644 index acd5826500778..0000000000000 --- a/administrator/components/com_redirect/tmpl/links/default_batch_footer.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -defined('_JEXEC') or die; - -use Joomla\CMS\Language\Text; - -?> - - diff --git a/administrator/components/com_redirect/tmpl/links/emptystate.php b/administrator/components/com_redirect/tmpl/links/emptystate.php index 36b8b04227e7e..f2e7ec1b4ace9 100644 --- a/administrator/components/com_redirect/tmpl/links/emptystate.php +++ b/administrator/components/com_redirect/tmpl/links/emptystate.php @@ -10,10 +10,14 @@ defined('_JEXEC') or die; +use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +use Joomla\Component\Redirect\Administrator\Helper\RedirectHelper; + +/** @var \Joomla\Component\Redirect\Administrator\View\Links\HtmlView $this */ $displayData = [ 'textPrefix' => 'COM_REDIRECT', @@ -22,6 +26,7 @@ 'icon' => 'icon-map-signs redirect', ]; +$app = Factory::getApplication(); $user = $this->getCurrentUser(); if ($user->authorise('core.create', 'com_redirect')) { @@ -33,39 +38,46 @@ && $user->authorise('core.edit', 'com_redirect') && $user->authorise('core.edit.state', 'com_redirect') ) { - $displayData['formAppend'] = HTMLHelper::_( - 'bootstrap.renderModal', - 'collapseModal', + $displayData['formAppend'] = ''; +} + +$collectUrlsEnabled = RedirectHelper::collectUrlsEnabled(); +$redirectPluginId = $this->redirectPluginId; + +// Show messages about the enabled plugin and if the plugin should collect URLs +if (!$redirectPluginId && $collectUrlsEnabled) { + $app->enqueueMessage(Text::sprintf('COM_REDIRECT_COLLECT_URLS_ENABLED', Text::_('COM_REDIRECT_PLUGIN_ENABLED')), 'warning'); +} else { + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = $this->document->getWebAssetManager(); + $wa->useScript('joomla.dialog-autocreate'); + + $popupOptions = [ + 'popupType' => 'iframe', + 'textHeader' => Text::_('COM_REDIRECT_EDIT_PLUGIN_SETTINGS'), + 'src' => Route::_('index.php?option=com_plugins&client_id=0&task=plugin.edit&extension_id=' . $redirectPluginId . '&tmpl=component&layout=modal', false), + ]; + $link = HTMLHelper::_( + 'link', + '#', + Text::_('COM_REDIRECT_SYSTEM_PLUGIN'), [ - 'title' => Text::_('COM_REDIRECT_BATCH_OPTIONS'), - 'footer' => $this->loadTemplate('batch_footer'), + 'class' => 'alert-link', + 'data-joomla-dialog' => $this->escape(json_encode($popupOptions, JSON_UNESCAPED_SLASHES)), + 'data-checkin-url' => Route::_('index.php?option=com_plugins&task=plugins.checkin&format=json&cid[]=' . $redirectPluginId), + 'data-close-on-message' => '', + 'data-reload-on-close' => '', ], - $this->loadTemplate('batch_body') ); -} ?> -redirectPluginId) : ?> - redirectPluginId . '&tmpl=component&layout=modal'); ?> - redirectPluginId . 'Modal', - [ - 'url' => $link, - 'title' => Text::_('COM_REDIRECT_EDIT_PLUGIN_SETTINGS'), - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => '70', - 'modalWidth' => '80', - 'closeButton' => false, - 'backdrop' => 'static', - 'keyboard' => false, - 'footer' => '' - . '' - . '' - ] - ); ?> - -enqueueMessage( + Text::sprintf('COM_REDIRECT_COLLECT_MODAL_URLS_DISABLED', Text::_('COM_REDIRECT_PLUGIN_ENABLED'), $link), + 'warning' + ); + } else { + $app->enqueueMessage(Text::sprintf('COM_REDIRECT_PLUGIN_MODAL_DISABLED', $link), 'error'); + } +} + +echo LayoutHelper::render('joomla.content.emptystate', $displayData); diff --git a/administrator/components/com_scheduler/tmpl/tasks/default.php b/administrator/components/com_scheduler/tmpl/tasks/default.php index 9a04f76691ff3..e2ecc581c7736 100644 --- a/administrator/components/com_scheduler/tmpl/tasks/default.php +++ b/administrator/components/com_scheduler/tmpl/tasks/default.php @@ -24,7 +24,7 @@ /** @var HtmlView $this*/ /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ -$wa = $this->document->getWebAssetManager(); +$wa = $this->getDocument()->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect') ->useScript('com_scheduler.test-task') @@ -42,6 +42,7 @@ Text::script('JLIB_JS_AJAX_ERROR_TIMEOUT'); Text::script('JLIB_JS_AJAX_ERROR_NO_CONTENT'); Text::script('JLIB_JS_AJAX_ERROR_PARSE'); +Text::script('JCLOSE'); try { /** @var CMSWebApplicationInterface $app */ @@ -62,8 +63,6 @@ $saveOrderingUrl = 'index.php?option=com_scheduler&task=tasks.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } - -$this->document->addScriptOptions('com_scheduler.test-task.token', Session::getFormToken()); ?> - @@ -268,20 +270,7 @@ class="js-draggable" data-url="" data-direction="
- pagination->getListFooter(); - - // Modal for test runs - $modalparams = [ - 'title' => '', - ]; - - $modalbody = '
'; - - echo HTMLHelper::_('bootstrap.renderModal', 'scheduler-test-modal', $modalparams, $modalbody); - - ?> + pagination->getListFooter(); ?> diff --git a/administrator/components/com_scheduler/tmpl/tasks/empty_state.php b/administrator/components/com_scheduler/tmpl/tasks/empty_state.php index faa671bbee7f4..0665fd68284d0 100644 --- a/administrator/components/com_scheduler/tmpl/tasks/empty_state.php +++ b/administrator/components/com_scheduler/tmpl/tasks/empty_state.php @@ -12,6 +12,8 @@ use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Scheduler\Administrator\View\Tasks\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_SCHEDULER', 'formURL' => 'index.php?option=com_scheduler&task=task.add', diff --git a/administrator/components/com_tags/config.xml b/administrator/components/com_tags/config.xml index 46d675c58f24b..516a73a1a2479 100644 --- a/administrator/components/com_tags/config.xml +++ b/administrator/components/com_tags/config.xml @@ -73,6 +73,9 @@ diff --git a/administrator/components/com_tags/forms/tag.xml b/administrator/components/com_tags/forms/tag.xml index cc27fb6f10586..08d282934c5fa 100644 --- a/administrator/components/com_tags/forms/tag.xml +++ b/administrator/components/com_tags/forms/tag.xml @@ -248,6 +248,9 @@ @@ -280,6 +283,9 @@ diff --git a/administrator/components/com_tags/src/View/Tags/HtmlView.php b/administrator/components/com_tags/src/View/Tags/HtmlView.php index a5bfc9040619f..3a1e0394cddae 100644 --- a/administrator/components/com_tags/src/View/Tags/HtmlView.php +++ b/administrator/components/com_tags/src/View/Tags/HtmlView.php @@ -184,6 +184,11 @@ protected function addToolbar() } } + if (!$this->isEmptyState && $canDo->get('core.admin')) { + $toolbar->standardButton('refresh', 'JTOOLBAR_REBUILD') + ->task('tags.rebuild'); + } + if (!$this->isEmptyState && $this->state->get('filter.published') == -2 && $canDo->get('core.delete')) { $toolbar->delete('tags.delete', 'JTOOLBAR_EMPTY_TRASH') ->message('JGLOBAL_CONFIRM_DELETE') diff --git a/administrator/components/com_tags/tmpl/tag/edit.php b/administrator/components/com_tags/tmpl/tag/edit.php index f451c3cb0f425..dcf272796b024 100644 --- a/administrator/components/com_tags/tmpl/tag/edit.php +++ b/administrator/components/com_tags/tmpl/tag/edit.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Tags\Administrator\View\Tag\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_tags/tmpl/tags/default.php b/administrator/components/com_tags/tmpl/tags/default.php index cc850a2cf85e0..f6f6dedaad08b 100644 --- a/administrator/components/com_tags/tmpl/tags/default.php +++ b/administrator/components/com_tags/tmpl/tags/default.php @@ -19,6 +19,8 @@ use Joomla\CMS\Session\Session; use Joomla\String\Inflector; +/** @var \Joomla\Component\Tags\Administrator\View\Tags\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_tags/tmpl/tags/emptystate.php b/administrator/components/com_tags/tmpl/tags/emptystate.php index b8348b5351bbd..ab70fe7c796d7 100644 --- a/administrator/components/com_tags/tmpl/tags/emptystate.php +++ b/administrator/components/com_tags/tmpl/tags/emptystate.php @@ -12,10 +12,12 @@ use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Tags\Administrator\View\Tags\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_TAGS', 'formURL' => 'index.php?option=com_tags&task=tag.add', - 'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/J3.x:How_To_Use_Content_Tags_in_Joomla!', + 'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/J4.x:How_To_Use_Content_Tags_in_Joomla', 'icon' => 'icon-tags tags', ]; diff --git a/administrator/components/com_templates/src/Model/TemplateModel.php b/administrator/components/com_templates/src/Model/TemplateModel.php index 0f2ef4130dd6e..91a505c25bd65 100644 --- a/administrator/components/com_templates/src/Model/TemplateModel.php +++ b/administrator/components/com_templates/src/Model/TemplateModel.php @@ -90,9 +90,9 @@ protected function getFile($path, $name) /** * Method to store file information. * - * @param string $path The base path. - * @param string $name The file name. - * @param stdClass $template The std class object of template. + * @param string $path The base path. + * @param string $name The file name. + * @param \stdClass $template The std class object of template. * * @return object stdClass object. * @@ -693,7 +693,7 @@ public function copy() // Delete new folder if it exists $toPath = $this->getState('to_path'); - if (Folder::exists($toPath)) { + if (is_dir(Path::clean($toPath))) { if (!Folder::delete($toPath)) { $app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_COULD_NOT_WRITE'), 'error'); @@ -886,8 +886,8 @@ public function &getSource() $fileName = str_replace('//', '/', $fileName); $isMedia = $input->getInt('isMedia', 0); - $fileName = $isMedia ? Path::clean(JPATH_ROOT . '/media/templates/' . ($this->template->client_id === 0 ? 'site' : 'administrator') . '/' . $this->template->element . $fileName) - : Path::clean(JPATH_ROOT . ($this->template->client_id === 0 ? '' : '/administrator') . '/templates/' . $this->template->element . $fileName); + $fileName = $isMedia ? Path::clean(JPATH_ROOT . '/media/templates/' . ((int) $this->template->client_id === 0 ? 'site' : 'administrator') . '/' . $this->template->element . $fileName) + : Path::clean(JPATH_ROOT . ((int) $this->template->client_id === 0 ? '' : '/administrator') . '/templates/' . $this->template->element . $fileName); try { $filePath = Path::check($fileName); @@ -1145,7 +1145,7 @@ public function createOverride($override) } // Check Html folder, create if not exist - if (!Folder::exists($htmlPath) && !Folder::create($htmlPath)) { + if (!is_dir(Path::clean($htmlPath)) && !Folder::create($htmlPath)) { $app->enqueueMessage(Text::_('COM_TEMPLATES_FOLDER_ERROR'), 'error'); return false; @@ -1203,7 +1203,7 @@ public function createTemplateOverride($overridePath, $htmlPath) foreach ($folders as $folder) { $htmlFolder = $htmlPath . str_replace($overridePath, '', $folder); - if (!Folder::exists($htmlFolder)) { + if (!is_dir(Path::clean($htmlFolder))) { Folder::create($htmlFolder); } } @@ -1864,7 +1864,7 @@ public function child() // Delete new folder if it exists $toPath = $this->getState('to_path'); - if (Folder::exists($toPath)) { + if (is_dir(Path::clean($toPath))) { if (!Folder::delete($toPath)) { $app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_COULD_NOT_WRITE'), 'error'); diff --git a/administrator/components/com_templates/tmpl/style/edit.php b/administrator/components/com_templates/tmpl/style/edit.php index b555515a6e5e4..557c70d56a2d7 100644 --- a/administrator/components/com_templates/tmpl/style/edit.php +++ b/administrator/components/com_templates/tmpl/style/edit.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Style\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') @@ -25,7 +27,9 @@ $user = $this->getCurrentUser(); ?> - + @@ -45,17 +49,31 @@
-

item->xml->description); ?>

fieldset = 'description'; - $description = LayoutHelper::render('joomla.edit.fieldset', $this); + $this->fieldset = 'description'; + $short_description = Text::_($this->item->xml->description); + $long_description = LayoutHelper::render('joomla.edit.fieldset', $this); + + if (!$long_description) { + $truncated = HTMLHelper::_('string.truncate', $short_description, 550, true, false); + + if (strlen($truncated) > 500) { + $long_description = $short_description; + $short_description = HTMLHelper::_('string.truncate', $truncated, 250); + + if ($short_description == $long_description) { + $long_description = ''; + } + } + } ?> - -

- - - -

+

+ +

+ + + +

- +
- +
@@ -93,18 +111,33 @@ fieldsets = []; - $this->ignore_fieldsets = ['basic', 'description']; + $this->ignore_fieldsets = ['basic', 'description', 'assigned']; echo LayoutHelper::render('joomla.edit.params', $this); ?> authorise('core.edit', 'com_menus') && $this->item->client_id == 0 && $this->canDo->get('core.edit.state')) : ?> -
- -
- loadTemplate('assignment'); ?> -
-
+ form->getGroup('assigned')) : ?> + ignore_fieldsets = ['basic']; + $this->fieldset = 'assigned'; + + foreach ($this->form->getFieldsets() as $fieldSet) { + if ($fieldSet->name !== 'assigned') { + $this->ignore_fieldsets[] = $fieldSet->name; + } + } + + echo LayoutHelper::render('joomla.edit.fieldset', $this); + ?> + +
+ +
+ loadTemplate('assignment'); ?> +
+
+ diff --git a/administrator/components/com_templates/tmpl/style/edit_assignment.php b/administrator/components/com_templates/tmpl/style/edit_assignment.php index 86742ae4c2678..0408cd0bf4a7f 100644 --- a/administrator/components/com_templates/tmpl/style/edit_assignment.php +++ b/administrator/components/com_templates/tmpl/style/edit_assignment.php @@ -14,6 +14,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\Component\Menus\Administrator\Helper\MenusHelper; +/** @var \Joomla\Component\Templates\Administrator\View\Style\HtmlView $this */ + // Initialise related data. $menuTypes = MenusHelper::getMenuLinks(); $user = $this->getCurrentUser(); diff --git a/administrator/components/com_templates/tmpl/styles/default.php b/administrator/components/com_templates/tmpl/styles/default.php index b8a9271536a2f..eca91de695938 100644 --- a/administrator/components/com_templates/tmpl/styles/default.php +++ b/administrator/components/com_templates/tmpl/styles/default.php @@ -16,6 +16,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Templates\Administrator\View\Styles\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_templates/tmpl/template/default.php b/administrator/components/com_templates/tmpl/template/default.php index c3a5c8582892d..a2f9fb95223f6 100644 --- a/administrator/components/com_templates/tmpl/template/default.php +++ b/administrator/components/com_templates/tmpl/template/default.php @@ -19,6 +19,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + HTMLHelper::_('behavior.multiselect', 'updateForm'); HTMLHelper::_('bootstrap.modal'); @@ -60,7 +62,7 @@
type != 'home') : ?> -

get('isMedia', 0) ? '/media/templates/' . ($this->template->client_id === 0 ? 'site' : 'administrator') . '/' . $this->template->element . str_replace('//', '/', base64_decode($this->file)) : '/' . ($this->template->client_id === 0 ? '' : 'administrator/') . 'templates/' . $this->template->element . str_replace('//', '/', base64_decode($this->file))), $this->template->element); ?>

+

get('isMedia', 0) ? '/media/templates/' . ((int) $this->template->client_id === 0 ? 'site' : 'administrator') . '/' . $this->template->element . str_replace('//', '/', base64_decode($this->file)) : '/' . ((int) $this->template->client_id === 0 ? '' : 'administrator/') . 'templates/' . $this->template->element . str_replace('//', '/', base64_decode($this->file))), $this->template->element); ?>

@@ -80,7 +82,7 @@
  • - template->client_id === 0 ? '/' : '/administrator/') . 'templates/' . $this->template->element; ?> + template->client_id === 0 ? '/' : '/administrator/') . 'templates/' . $this->template->element; ?> loadTemplate('tree'); ?>
  • @@ -90,7 +92,7 @@
  • - template->client_id === 0 ? 'site/' : 'administrator/') . $this->template->element; ?> + template->client_id === 0 ? 'site/' : 'administrator/') . $this->template->element; ?> loadTemplate('tree_media'); ?>
  • diff --git a/administrator/components/com_templates/tmpl/template/default_description.php b/administrator/components/com_templates/tmpl/template/default_description.php index 72afa2cbde22c..8d8f1ca2eb41c 100644 --- a/administrator/components/com_templates/tmpl/template/default_description.php +++ b/administrator/components/com_templates/tmpl/template/default_description.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\Component\Templates\Administrator\Helper\TemplatesHelper; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + ?>
    diff --git a/administrator/components/com_templates/tmpl/template/default_folders.php b/administrator/components/com_templates/tmpl/template/default_folders.php index 1675dab6e7b1f..7f6bb194900ed 100644 --- a/administrator/components/com_templates/tmpl/template/default_folders.php +++ b/administrator/components/com_templates/tmpl/template/default_folders.php @@ -10,6 +10,8 @@ defined('_JEXEC') or die; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + ksort($this->files, SORT_STRING); ?> diff --git a/administrator/components/com_templates/tmpl/template/default_media_folders.php b/administrator/components/com_templates/tmpl/template/default_media_folders.php index f3491ab3a8fa8..7e82f97ceb2e8 100644 --- a/administrator/components/com_templates/tmpl/template/default_media_folders.php +++ b/administrator/components/com_templates/tmpl/template/default_media_folders.php @@ -10,6 +10,8 @@ defined('_JEXEC') or die; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + // Legacy is the default if (!count($this->mediaFiles)) { return; diff --git a/administrator/components/com_templates/tmpl/template/default_modal_child_body.php b/administrator/components/com_templates/tmpl/template/default_modal_child_body.php index 507b0767372af..47f715e29e95b 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_child_body.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_child_body.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + Factory::getDocument()->getWebAssetManager()->usePreset('choicesjs'); // Generate a list of styles for the child creation modal diff --git a/administrator/components/com_templates/tmpl/template/default_modal_delete_body.php b/administrator/components/com_templates/tmpl/template/default_modal_delete_body.php index 886126e96b82f..d998408a28322 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_delete_body.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_delete_body.php @@ -12,6 +12,7 @@ use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ ?>
    diff --git a/administrator/components/com_templates/tmpl/template/default_modal_delete_footer.php b/administrator/components/com_templates/tmpl/template/default_modal_delete_footer.php index 55c342babc144..f9d93a4ebeb9a 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_delete_footer.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_delete_footer.php @@ -14,6 +14,8 @@ use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + $input = Factory::getApplication()->getInput(); ?> diff --git a/administrator/components/com_templates/tmpl/template/default_modal_file_body.php b/administrator/components/com_templates/tmpl/template/default_modal_file_body.php index a4724e3dc026e..54fa40b943e76 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_file_body.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_file_body.php @@ -16,6 +16,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Utility\Utility; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + $input = Factory::getApplication()->getInput(); ?>
    diff --git a/administrator/components/com_templates/tmpl/template/default_modal_folder_body.php b/administrator/components/com_templates/tmpl/template/default_modal_folder_body.php index 635d7cb66ecc8..53586a36e5359 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_folder_body.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_folder_body.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + $input = Factory::getApplication()->getInput(); ?>
    diff --git a/administrator/components/com_templates/tmpl/template/default_modal_folder_footer.php b/administrator/components/com_templates/tmpl/template/default_modal_folder_footer.php index aa17d5903521b..8a2baa657aa65 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_folder_footer.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_folder_footer.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + $input = Factory::getApplication()->getInput(); ?> diff --git a/administrator/components/com_templates/tmpl/template/default_modal_rename_body.php b/administrator/components/com_templates/tmpl/template/default_modal_rename_body.php index 531e6d7f49c57..20e4310cde350 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_rename_body.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_rename_body.php @@ -13,6 +13,7 @@ use Joomla\CMS\Filesystem\File; use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ ?>
    diff --git a/administrator/components/com_templates/tmpl/template/default_modal_resize_body.php b/administrator/components/com_templates/tmpl/template/default_modal_resize_body.php index 8b8a87a0b0f39..c4e4d9bd5e0d8 100644 --- a/administrator/components/com_templates/tmpl/template/default_modal_resize_body.php +++ b/administrator/components/com_templates/tmpl/template/default_modal_resize_body.php @@ -12,6 +12,7 @@ use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ ?>
    diff --git a/administrator/components/com_templates/tmpl/template/default_tree.php b/administrator/components/com_templates/tmpl/template/default_tree.php index 2fca01ac619da..dd59a25b6803f 100644 --- a/administrator/components/com_templates/tmpl/template/default_tree.php +++ b/administrator/components/com_templates/tmpl/template/default_tree.php @@ -12,6 +12,8 @@ use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + ksort($this->files, SORT_NATURAL); ?> diff --git a/administrator/components/com_templates/tmpl/template/default_tree_media.php b/administrator/components/com_templates/tmpl/template/default_tree_media.php index 32c014bda09fd..0701c7c0fcff1 100644 --- a/administrator/components/com_templates/tmpl/template/default_tree_media.php +++ b/administrator/components/com_templates/tmpl/template/default_tree_media.php @@ -12,6 +12,8 @@ use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + // Legacy is the default if (!count($this->mediaFiles)) { return; diff --git a/administrator/components/com_templates/tmpl/template/default_updated_files.php b/administrator/components/com_templates/tmpl/template/default_updated_files.php index 2e5d09c413642..3847d1841fcd0 100644 --- a/administrator/components/com_templates/tmpl/template/default_updated_files.php +++ b/administrator/components/com_templates/tmpl/template/default_updated_files.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + HTMLHelper::_('bootstrap.dropdown', '.dropdown-toggle'); /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ diff --git a/administrator/components/com_templates/tmpl/template/readonly.php b/administrator/components/com_templates/tmpl/template/readonly.php index b0fb791a23dee..3c0e6011b13e0 100644 --- a/administrator/components/com_templates/tmpl/template/readonly.php +++ b/administrator/components/com_templates/tmpl/template/readonly.php @@ -15,6 +15,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Template\HtmlView $this */ + $input = Factory::getApplication()->getInput(); ?> diff --git a/administrator/components/com_templates/tmpl/templates/default.php b/administrator/components/com_templates/tmpl/templates/default.php index 039d97c434dd5..08fe13f8a5a46 100644 --- a/administrator/components/com_templates/tmpl/templates/default.php +++ b/administrator/components/com_templates/tmpl/templates/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Templates\Administrator\View\Templates\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_users/src/Controller/DisplayController.php b/administrator/components/com_users/src/Controller/DisplayController.php index 864e6d23a483a..3530077485a9d 100644 --- a/administrator/components/com_users/src/Controller/DisplayController.php +++ b/administrator/components/com_users/src/Controller/DisplayController.php @@ -49,15 +49,15 @@ protected function canView($view) $canDo = ContentHelper::getActions('com_users'); switch ($view) { - // Special permissions. case 'groups': case 'group': case 'levels': case 'level': + // Special permissions. return $canDo->get('core.admin'); - // Default permissions. default: + // Default permissions. return true; } } diff --git a/administrator/components/com_users/src/Controller/MethodController.php b/administrator/components/com_users/src/Controller/MethodController.php index 66f921a8180fb..684a8b5483385 100644 --- a/administrator/components/com_users/src/Controller/MethodController.php +++ b/administrator/components/com_users/src/Controller/MethodController.php @@ -21,6 +21,7 @@ use Joomla\CMS\User\User; use Joomla\CMS\User\UserFactoryAwareInterface; use Joomla\CMS\User\UserFactoryAwareTrait; +use Joomla\CMS\User\UserHelper; use Joomla\Component\Users\Administrator\Helper\Mfa as MfaHelper; use Joomla\Component\Users\Administrator\Model\BackupcodesModel; use Joomla\Component\Users\Administrator\Model\MethodModel; @@ -387,6 +388,9 @@ public function save($cachable = false, $urlparams = []): void return; } + // Method updated, destroy other active sessions + UserHelper::destroyUserSessions($userId, true); + $this->setRedirect($url); } diff --git a/administrator/components/com_users/src/Controller/UserController.php b/administrator/components/com_users/src/Controller/UserController.php index 5be9cd63b4be0..390753331d231 100644 --- a/administrator/components/com_users/src/Controller/UserController.php +++ b/administrator/components/com_users/src/Controller/UserController.php @@ -118,8 +118,8 @@ public function save($key = null, $urlVar = null) } // If a user has to renew a password but has no permission for users - if (!$this->app->getIdentity()->authorise('core.admin', 'com_users')) { - $this->setRedirect('index.php'); + if ($task === 'save' && !$this->app->getIdentity()->authorise('core.manage', 'com_users')) { + $this->setRedirect(Uri::base()); } return $result; diff --git a/administrator/components/com_users/src/Helper/Mfa.php b/administrator/components/com_users/src/Helper/Mfa.php index 63286de7f5c79..64499ce5efe5a 100644 --- a/administrator/components/com_users/src/Helper/Mfa.php +++ b/administrator/components/com_users/src/Helper/Mfa.php @@ -10,7 +10,6 @@ namespace Joomla\Component\Users\Administrator\Helper; -use Exception; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Document\HtmlDocument; diff --git a/administrator/components/com_users/src/Model/UserModel.php b/administrator/components/com_users/src/Model/UserModel.php index 794b8731edab1..cdbbd8ed9baef 100644 --- a/administrator/components/com_users/src/Model/UserModel.php +++ b/administrator/components/com_users/src/Model/UserModel.php @@ -703,20 +703,20 @@ public function batchUser($groupId, $userIds, $action) $db = $this->getDatabase(); switch ($action) { - // Sets users to a selected group case 'set': + // Sets users to a selected group $doDelete = 'all'; $doAssign = true; break; - // Remove users from a selected group case 'del': + // Remove users from a selected group $doDelete = 'group'; break; - // Add users to a selected group case 'add': default: + // Add users to a selected group $doAssign = true; break; } diff --git a/administrator/components/com_users/tmpl/debuggroup/default.php b/administrator/components/com_users/tmpl/debuggroup/default.php index c893923a9f211..c7aa9914d5598 100644 --- a/administrator/components/com_users/tmpl/debuggroup/default.php +++ b/administrator/components/com_users/tmpl/debuggroup/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Debuggroup\HtmlView $this */ + $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); diff --git a/administrator/components/com_users/tmpl/debuguser/default.php b/administrator/components/com_users/tmpl/debuguser/default.php index 3e01c3bdeec85..1666ff52c9859 100644 --- a/administrator/components/com_users/tmpl/debuguser/default.php +++ b/administrator/components/com_users/tmpl/debuguser/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Debuguser\HtmlView $this */ + $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); diff --git a/administrator/components/com_users/tmpl/group/edit.php b/administrator/components/com_users/tmpl/group/edit.php index 1bcf28d6daf12..91c1b43304ea7 100644 --- a/administrator/components/com_users/tmpl/group/edit.php +++ b/administrator/components/com_users/tmpl/group/edit.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Group\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_users/tmpl/groups/default.php b/administrator/components/com_users/tmpl/groups/default.php index f6509ff90a80a..bbdef6670f873 100644 --- a/administrator/components/com_users/tmpl/groups/default.php +++ b/administrator/components/com_users/tmpl/groups/default.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Groups\HtmlView $this */ + $user = $this->getCurrentUser(); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); diff --git a/administrator/components/com_users/tmpl/level/edit.php b/administrator/components/com_users/tmpl/level/edit.php index e4985cc6a9043..51cf77f9be316 100644 --- a/administrator/components/com_users/tmpl/level/edit.php +++ b/administrator/components/com_users/tmpl/level/edit.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Level\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_users/tmpl/levels/default.php b/administrator/components/com_users/tmpl/levels/default.php index 79489280a4cb2..a1e93d98f4785 100644 --- a/administrator/components/com_users/tmpl/levels/default.php +++ b/administrator/components/com_users/tmpl/levels/default.php @@ -18,6 +18,8 @@ use Joomla\CMS\Session\Session; use Joomla\Component\Users\Administrator\Helper\UsersHelper; +/** @var \Joomla\Component\Users\Administrator\View\Levels\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_users/tmpl/note/edit.php b/administrator/components/com_users/tmpl/note/edit.php index 8fd2b6d215227..fd82b6009ecdd 100644 --- a/administrator/components/com_users/tmpl/note/edit.php +++ b/administrator/components/com_users/tmpl/note/edit.php @@ -14,6 +14,8 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Note\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_users/tmpl/notes/default.php b/administrator/components/com_users/tmpl/notes/default.php index 198ffc06a3deb..f2d3f32b6d4be 100644 --- a/administrator/components/com_users/tmpl/notes/default.php +++ b/administrator/components/com_users/tmpl/notes/default.php @@ -15,6 +15,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Notes\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_users/tmpl/notes/emptystate.php b/administrator/components/com_users/tmpl/notes/emptystate.php index 22d7d4b808ba3..a7db347d7b243 100644 --- a/administrator/components/com_users/tmpl/notes/emptystate.php +++ b/administrator/components/com_users/tmpl/notes/emptystate.php @@ -12,6 +12,8 @@ use Joomla\CMS\Layout\LayoutHelper; +/** @var \Joomla\Component\Users\Administrator\View\Notes\HtmlView $this */ + $displayData = [ 'textPrefix' => 'COM_USERS_NOTES', 'formURL' => 'index.php?option=com_users&view=notes', diff --git a/administrator/components/com_users/tmpl/notes/modal.php b/administrator/components/com_users/tmpl/notes/modal.php index 19b781d81d4da..3fb069ab508b6 100644 --- a/administrator/components/com_users/tmpl/notes/modal.php +++ b/administrator/components/com_users/tmpl/notes/modal.php @@ -13,6 +13,7 @@ use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Users\Administrator\View\Notes\HtmlView $this */ ?>

    user->name, $this->user->id); ?>

    diff --git a/administrator/components/com_users/tmpl/users/default.php b/administrator/components/com_users/tmpl/users/default.php index 291e9c2166c43..724bfd85d98ed 100644 --- a/administrator/components/com_users/tmpl/users/default.php +++ b/administrator/components/com_users/tmpl/users/default.php @@ -186,7 +186,7 @@ - escape($item->email)); ?> + escape(PunycodeHelper::emailToUTF8($item->email)); ?> lastvisitDate !== null) : ?> diff --git a/administrator/components/com_users/tmpl/users/default_batch_body.php b/administrator/components/com_users/tmpl/users/default_batch_body.php index c5b11db6cceea..ba517a899cd10 100644 --- a/administrator/components/com_users/tmpl/users/default_batch_body.php +++ b/administrator/components/com_users/tmpl/users/default_batch_body.php @@ -13,6 +13,8 @@ use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; +/** @var \Joomla\Component\Users\Administrator\View\Users\HtmlView $this */ + // Create the copy/move options. $options = [ HTMLHelper::_('select.option', 'add', Text::_('COM_USERS_BATCH_ADD')), diff --git a/administrator/components/com_users/tmpl/users/modal.php b/administrator/components/com_users/tmpl/users/modal.php index 799d9342b3b32..7073bc7b03444 100644 --- a/administrator/components/com_users/tmpl/users/modal.php +++ b/administrator/components/com_users/tmpl/users/modal.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Users\Administrator\View\Users\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('multiselect')->useScript('modal-content-select'); diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index 1816f9e7d767f..fdfeb49ace3dd 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -291,7 +291,7 @@ public function setDefault($pk, $value = 1) if ( $table->load( [ - 'default' => '1', + 'default' => '1', 'extension' => $table->get('extension'), ] ) diff --git a/administrator/components/com_workflow/src/Table/WorkflowTable.php b/administrator/components/com_workflow/src/Table/WorkflowTable.php index d0564f0d75c1c..ce6718394c3e5 100644 --- a/administrator/components/com_workflow/src/Table/WorkflowTable.php +++ b/administrator/components/com_workflow/src/Table/WorkflowTable.php @@ -212,7 +212,7 @@ public function store($updateNulls = true) if ( $table->load( [ - 'default' => '1', + 'default' => '1', 'extension' => $this->extension, ] ) diff --git a/administrator/components/com_workflow/tmpl/stage/edit.php b/administrator/components/com_workflow/tmpl/stage/edit.php index baece7842f702..0dc43595f1655 100644 --- a/administrator/components/com_workflow/tmpl/stage/edit.php +++ b/administrator/components/com_workflow/tmpl/stage/edit.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Workflow\Administrator\View\Stage\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_workflow/tmpl/stages/default.php b/administrator/components/com_workflow/tmpl/stages/default.php index 0ad92d3dc0b8b..922502cc65848 100644 --- a/administrator/components/com_workflow/tmpl/stages/default.php +++ b/administrator/components/com_workflow/tmpl/stages/default.php @@ -17,6 +17,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Workflow\Administrator\View\Stages\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_workflow/tmpl/transition/edit.php b/administrator/components/com_workflow/tmpl/transition/edit.php index ee1f49c0be8fe..a5f84ee79fd9f 100644 --- a/administrator/components/com_workflow/tmpl/transition/edit.php +++ b/administrator/components/com_workflow/tmpl/transition/edit.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Workflow\Administrator\View\Transition\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_workflow/tmpl/transitions/default.php b/administrator/components/com_workflow/tmpl/transitions/default.php index 1c56ee69f83ca..1a3d6d8eef1e7 100644 --- a/administrator/components/com_workflow/tmpl/transitions/default.php +++ b/administrator/components/com_workflow/tmpl/transitions/default.php @@ -17,6 +17,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Workflow\Administrator\View\Transitions\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/components/com_workflow/tmpl/workflow/edit.php b/administrator/components/com_workflow/tmpl/workflow/edit.php index b4ba5716cbecf..9472803db9b66 100644 --- a/administrator/components/com_workflow/tmpl/workflow/edit.php +++ b/administrator/components/com_workflow/tmpl/workflow/edit.php @@ -16,6 +16,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; +/** @var \Joomla\Component\Workflow\Administrator\View\Workflow\HtmlView $this */ + /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') diff --git a/administrator/components/com_workflow/tmpl/workflows/default.php b/administrator/components/com_workflow/tmpl/workflows/default.php index 184f972ea3c5b..b5270cbe06e4c 100644 --- a/administrator/components/com_workflow/tmpl/workflows/default.php +++ b/administrator/components/com_workflow/tmpl/workflows/default.php @@ -17,6 +17,8 @@ use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +/** @var \Joomla\Component\Workflow\Administrator\View\Workflows\HtmlView $this */ + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') diff --git a/administrator/language/en-GB/com_banners.ini b/administrator/language/en-GB/com_banners.ini index da671eb417c13..4bc287d64481d 100644 --- a/administrator/language/en-GB/com_banners.ini +++ b/administrator/language/en-GB/com_banners.ini @@ -59,10 +59,10 @@ COM_BANNERS_CLIENTS_N_ITEMS_UNPUBLISHED_1="Client unpublished." COM_BANNERS_CLIENTS_NO_ITEM_SELECTED="No clients selected." COM_BANNERS_CLIENTS_TABLE_CAPTION="Clients" COM_BANNERS_CONFIGURATION="Banners: Options" -COM_BANNERS_COUNT_ARCHIVED_ITEMS="Archived banners" -COM_BANNERS_COUNT_PUBLISHED_ITEMS="Published banners" -COM_BANNERS_COUNT_TRASHED_ITEMS="Trashed banners" -COM_BANNERS_COUNT_UNPUBLISHED_ITEMS="Unpublished banners" +COM_BANNERS_COUNT_ARCHIVED_ITEMS="Archived" +COM_BANNERS_COUNT_PUBLISHED_ITEMS="Published" +COM_BANNERS_COUNT_TRASHED_ITEMS="Trashed" +COM_BANNERS_COUNT_UNPUBLISHED_ITEMS="Unpublished" COM_BANNERS_DEFAULT="Default (%s)" COM_BANNERS_DELETE_MSG="Are you sure you want to delete all these tracks?" COM_BANNERS_EDIT_CLIENT="Details" diff --git a/administrator/language/en-GB/com_categories.ini b/administrator/language/en-GB/com_categories.ini index a0cc590ef8344..7febf190e9422 100644 --- a/administrator/language/en-GB/com_categories.ini +++ b/administrator/language/en-GB/com_categories.ini @@ -15,6 +15,10 @@ COM_CATEGORIES_CATEGORY_ADD_TITLE="%s: New Category" COM_CATEGORIES_CATEGORY_BASE_ADD_TITLE="New Category" COM_CATEGORIES_CATEGORY_BASE_EDIT_TITLE="Edit Category" COM_CATEGORIES_CATEGORY_EDIT_TITLE="%s: Edit Category" +COM_CATEGORIES_COUNT_ARCHIVED_ARTICLES="Archived Articles" +COM_CATEGORIES_COUNT_PUBLISHED_ARTICLES="Published Articles" +COM_CATEGORIES_COUNT_TRASHED_ARTICLES="Trashed Articles" +COM_CATEGORIES_COUNT_UNPUBLISHED_ARTICLES="Unpublished Articles" COM_CATEGORIES_DELETE_NOT_ALLOWED="Delete not allowed for category %s." COM_CATEGORIES_EDIT_CATEGORY="Edit Category" COM_CATEGORIES_EMPTYSTATE_BUTTON_ADD="Add a category" @@ -36,6 +40,11 @@ COM_CATEGORIES_FORM_TITLE_EDIT="Edit Category" COM_CATEGORIES_FORM_TITLE_NEW="New Category" COM_CATEGORIES_HAS_SUBCATEGORY_ITEMS="%d items are assigned to this category's subcategories." COM_CATEGORIES_HAS_SUBCATEGORY_ITEMS_1="One item is assigned to one of this category's subcategories." +COM_CATEGORIES_HEADING_ARCHIVED="Archived" +COM_CATEGORIES_HEADING_PUBLISHED="Published" +COM_CATEGORIES_HEADING_TRASHED="Trashed" +COM_CATEGORIES_HEADING_UNPUBLISHED="Unpublished" +COM_CATEGORIES_HEADING_ASSOCIATION="Association" COM_CATEGORIES_ITEMS_SEARCH_FILTER="Search" COM_CATEGORIES_N_ITEMS_ARCHIVED="%d categories archived." COM_CATEGORIES_N_ITEMS_ARCHIVED_1="Category archived." @@ -69,11 +78,6 @@ COM_CATEGORIES_SELECT_A_CATEGORY="Select a Category" COM_CATEGORIES_TABLE_CAPTION="Categories" COM_CATEGORIES_TIP_ASSOCIATION="Associated categories" COM_CATEGORIES_XML_DESCRIPTION="This component manages categories." -COM_CATEGORY_COUNT_ARCHIVED_ITEMS="Archived items" -COM_CATEGORY_COUNT_PUBLISHED_ITEMS="Published items" -COM_CATEGORY_COUNT_TRASHED_ITEMS="Trashed items" -COM_CATEGORY_COUNT_UNPUBLISHED_ITEMS="Unpublished items" -COM_CATEGORY_HEADING_ASSOCIATION="Association" JGLOBAL_NO_ITEM_SELECTED="No categories selected." JLIB_HTML_ACCESS_SUMMARY_DESC="Shown below is an overview of the permission settings for this category. Select the tabs above to customise these settings by action." JLIB_RULES_SETTING_NOTES_ITEM="Changes apply to this category and all child categories.
    Inherited - a Global Configuration setting or higher level setting is applied.
    Denied always wins - whatever is set at the Global or higher level and applies to all child elements.
    Allowed will enable the action for this component unless overruled by a Global Configuration setting." diff --git a/administrator/language/en-GB/com_config.ini b/administrator/language/en-GB/com_config.ini index c4c0b646d8268..5e3b1d1c1fc07 100644 --- a/administrator/language/en-GB/com_config.ini +++ b/administrator/language/en-GB/com_config.ini @@ -239,6 +239,7 @@ COM_CONFIG_SENDMAIL_METHOD_SMTP="SMTP" COM_CONFIG_SENDMAIL_SUBJECT="Test mail from {SITENAME}" COM_CONFIG_SENDMAIL_SUCCESS="The email was sent to %s using %s. You should check that you've received the test email." COM_CONFIG_SENDMAIL_SUCCESS_FALLBACK="The email was sent to %s but using %s as fallback. You should check that you've received the test email." +COM_CONFIG_SEO_SETTINGS_DESC="Additional settings can be found in the \"System - SEF\" plugin." COM_CONFIG_SEO_SETTINGS="SEO" COM_CONFIG_SERVER="Server" COM_CONFIG_SERVER_SETTINGS="Server" diff --git a/administrator/language/en-GB/com_fields.ini b/administrator/language/en-GB/com_fields.ini index d2f141ab70b13..1799bf0d9d165 100644 --- a/administrator/language/en-GB/com_fields.ini +++ b/administrator/language/en-GB/com_fields.ini @@ -21,6 +21,8 @@ COM_FIELDS_FIELD_EDITABLE_IN_BOTH="Both" COM_FIELDS_FIELD_EDITABLE_IN_LABEL="Editable In" COM_FIELDS_FIELD_EDITABLE_IN_SITE="Site" COM_FIELDS_FIELD_FORM_EDIT="Edit Field" +; The following string is deprecated and will be removed with 6.0 +COM_FIELDS_FIELD_FORM_LAYOUT_LABEL="Layout" COM_FIELDS_FIELD_FORM_NEW="New Field" COM_FIELDS_FIELD_FORMOPTIONS_HEADING="Form Options" COM_FIELDS_FIELD_GROUP_LABEL="Field Group" diff --git a/administrator/language/en-GB/com_guidedtours.ini b/administrator/language/en-GB/com_guidedtours.ini index 84b009fb525dc..f7e1789ed2171 100644 --- a/administrator/language/en-GB/com_guidedtours.ini +++ b/administrator/language/en-GB/com_guidedtours.ini @@ -13,8 +13,10 @@ COM_GUIDEDTOURS_EXTENSIONS_DESC="Restrict the tour to be displayed only when the COM_GUIDEDTOURS_EXTENSIONS_LABEL="Component Selector" COM_GUIDEDTOURS_FIELD_NOTE_LABEL="Note" COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_BUTTON="Button" +COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_CHECKBOX_RADIO_FIELD="Checkbox/Radio" COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_FORM_SUBMIT="Form Submit" COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_OTHER="Other" +COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_SELECT_LIST="Select List" COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_TEXT_FIELD="Text Field" COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_INTERACTIVE="Interactive" COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_NEXT="Next" @@ -49,6 +51,8 @@ COM_GUIDEDTOURS_STEP_FILTER_SEARCH_LABEL="Search Steps" COM_GUIDEDTOURS_STEP_NEW_STEP="New Step" COM_GUIDEDTOURS_STEP_POSITION_DESC="Select the position of the step popup, relative to the element it points to." COM_GUIDEDTOURS_STEP_POSITION_LABEL="Position" +COM_GUIDEDTOURS_STEP_TARGETNOTE_MESSAGE="When a step is identified as interactive, specific interactive options might carry extra parameters for the user's interaction with a target." +COM_GUIDEDTOURS_STEP_TARGETVALUES_HEADING="Target Value Options" COM_GUIDEDTOURS_STEP_TITLE="Title" COM_GUIDEDTOURS_STEP_TITLE_TRANSLATION="Title (%s)" COM_GUIDEDTOURS_STEP_TARGET_DESC="The target element the step will be attached to. Options: .classname, #id, any selector following the CSS syntax (make sure it is a focusable element if the step is interactive), or leave blank for a centered step." @@ -74,7 +78,11 @@ COM_GUIDEDTOURS_TOURS_LIST="Guided Tours" COM_GUIDEDTOURS_TOURS_LIST_EMPTYSTATE_BUTTON_ADD="Add your first tour" COM_GUIDEDTOURS_TOURS_LIST_EMPTYSTATE_CONTENT="Create a tour to make it functional." COM_GUIDEDTOURS_TOURS_LIST_EMPTYSTATE_TITLE="No tours have been created yet." -COM_GUIDEDTOURS_TYPE_INTERACTIVE_STEP_DESC="Select Form Submit to submit a form, Text Field for user input, Button for buttons, or Other for any other interaction." +COM_GUIDEDTOURS_TYPE_INPUT_REQUIRED_DESC="Enable if the user is required to provide a value, activate a radio button or check a box to move forward to the next step of the tour." +COM_GUIDEDTOURS_TYPE_INPUT_REQUIRED_LABEL="Required" +COM_GUIDEDTOURS_TYPE_INPUT_REQUIREDVALUE_DESC="The exact value to be entered, including case and punctuation, to move forward to the next step (if the target is a list of items, use the value of the select's option element)." +COM_GUIDEDTOURS_TYPE_INPUT_REQUIREDVALUE_LABEL="Required Value" +COM_GUIDEDTOURS_TYPE_INTERACTIVE_STEP_DESC="Select Form Submit to submit a form, Text Field for user input, Button for buttons, Checkbox/Radio or Select List for selection, or Other for any other interaction." COM_GUIDEDTOURS_TYPE_INTERACTIVE_STEP_LABEL="Interactive Type" COM_GUIDEDTOURS_TYPE_REDIRECT_URL_DESC="Enter the relative URL of the page you want the step to redirect to, eg administrator/index.php?option=com_guidedtours&view=tours for the tours' list page." COM_GUIDEDTOURS_TYPE_REDIRECT_URL_LABEL="Relative URL" diff --git a/administrator/language/en-GB/com_installer.ini b/administrator/language/en-GB/com_installer.ini index fa3a097afedcf..010c079fc58cd 100644 --- a/administrator/language/en-GB/com_installer.ini +++ b/administrator/language/en-GB/com_installer.ini @@ -229,6 +229,8 @@ COM_INSTALLER_TOOLBAR_FIND_UPDATES="Check For Updates" COM_INSTALLER_TOOLBAR_INSTALL="Install" COM_INSTALLER_TOOLBAR_INSTALL_EXTENSIONS="Install Extensions" COM_INSTALLER_TOOLBAR_MANAGE="Manage Extensions" +COM_INSTALLER_TOOLBAR_MANAGE_LANGUAGES="Manage Languages" +COM_INSTALLER_TOOLBAR_MANAGE_LANGUAGES_CONTENT="Content Languages" COM_INSTALLER_TOOLBAR_PURGE="Clear Cache" COM_INSTALLER_TOOLBAR_UPDATE="Update" COM_INSTALLER_TYPE_CLIENT="Location" diff --git a/administrator/language/en-GB/com_joomlaupdate.ini b/administrator/language/en-GB/com_joomlaupdate.ini index 17fca2758a9b6..e2deeffc76a07 100644 --- a/administrator/language/en-GB/com_joomlaupdate.ini +++ b/administrator/language/en-GB/com_joomlaupdate.ini @@ -44,10 +44,10 @@ COM_JOOMLAUPDATE_MINIMUM_STABILITY_STABLE="Stable" COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_APPEND="Upload and Update" COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_BUTTON_ADD="Retry check for update" COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_CONTENT="An update to Joomla %1$s was found, but it wasn't possible to fetch the download URL for that update. Either the update to Joomla %1$s is not available for your stability level or there is a problem with the Joomla Update Server.
    Please try to download the update package from the official Joomla download page and use the Upload and Update function." -COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON="An update to Joomla %1$s was found but your web server doesn't meet the minimum requirements.
    " -COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_ACTION="Please contact your web host to update your server.
    " -COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_DATABASE="Your %1$s version \"%2$s\" is lower than \"%3$s\".
    " -COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_PHP="Your PHP version \"%1$s\" is lower than \"%2$s\".
    " +COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON="An update to Joomla %1$s was found but your web server doesn't meet the minimum requirements." +COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_ACTION="Please contact your web host to update your server." +COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_DATABASE="Your %1$s version \"%2$s\" is lower than \"%3$s\"." +COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_REASON_PHP="Your PHP version \"%1$s\" is lower than \"%2$s\"." COM_JOOMLAUPDATE_NODOWNLOAD_EMPTYSTATE_TITLE="This site can't be updated to Joomla %1$s" COM_JOOMLAUPDATE_OVERVIEW="Joomla Update" COM_JOOMLAUPDATE_PREUPDATE_CHECK_CAPTION="Server settings to check before update." @@ -174,6 +174,7 @@ COM_JOOMLAUPDATE_VIEW_DEFAULT_UPLOAD_INTRO="You can use this feature to update J COM_JOOMLAUPDATE_VIEW_UPDATE_BYTESEXTRACTED="Bytes extracted" COM_JOOMLAUPDATE_VIEW_UPDATE_BYTESREAD="Bytes read" COM_JOOMLAUPDATE_VIEW_UPDATE_CHECKSUM_WRONG="File Checksum Failed" +COM_JOOMLAUPDATE_VIEW_UPDATE_VERSION_WRONG="The version of the update package and the requested version do not match, try to refresh the update information." COM_JOOMLAUPDATE_VIEW_UPDATE_DOWNLOADFAILED="Download of update package failed." COM_JOOMLAUPDATE_VIEW_UPDATE_ITEMS="items" COM_JOOMLAUPDATE_VIEW_UPDATE_FILESEXTRACTED="Files extracted" diff --git a/administrator/language/en-GB/install.xml b/administrator/language/en-GB/install.xml index 255380df220db..2ae768b53ce8e 100644 --- a/administrator/language/en-GB/install.xml +++ b/administrator/language/en-GB/install.xml @@ -3,7 +3,7 @@ English (en-GB) en-GB 5.1.0 - 2023-12 + 2024-02 Joomla! Project admin@joomla.org www.joomla.org diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index 4adc9b185f4e1..04a50421f9024 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -433,6 +433,8 @@ JGLOBAL_FIELD_MODIFIED_BY_DESC="The user who did the last modification." JGLOBAL_FIELD_MODIFIED_BY_LABEL="Modified By" JGLOBAL_FIELD_MODIFIED_LABEL="Modified Date" JGLOBAL_FIELD_MOVE="Move" +JGLOBAL_FIELD_MOVE_DOWN="Move down" +JGLOBAL_FIELD_MOVE_UP="Move up" JGLOBAL_FIELD_NUM_CATEGORY_ITEMS_DESC="Number of categories to display for each level." JGLOBAL_FIELD_NUM_CATEGORY_ITEMS_LABEL="Number of Categories" JGLOBAL_FIELD_PUBLISH_DOWN_DESC="An optional date to stop publishing." diff --git a/administrator/language/en-GB/langmetadata.xml b/administrator/language/en-GB/langmetadata.xml index 28398a486918e..81c26d5ae956c 100644 --- a/administrator/language/en-GB/langmetadata.xml +++ b/administrator/language/en-GB/langmetadata.xml @@ -2,7 +2,7 @@ English (en-GB) 5.1.0 - 2023-12 + 2024-02 Joomla! Project admin@joomla.org www.joomla.org diff --git a/administrator/language/en-GB/lib_joomla.ini b/administrator/language/en-GB/lib_joomla.ini index 7fbad4d2981c0..dbfbebda42de0 100644 --- a/administrator/language/en-GB/lib_joomla.ini +++ b/administrator/language/en-GB/lib_joomla.ini @@ -347,7 +347,9 @@ JLIB_FORM_SELECT_USER="Select a User" JLIB_FORM_VALIDATE_FIELD_INVALID="Invalid field: %s" JLIB_FORM_VALIDATE_FIELD_REQUIRED="Field required: %s" JLIB_FORM_VALIDATE_FIELD_RULE_MISSING="Validation Rule missing: %s" +JLIB_FORM_VALIDATE_FIELD_URL_INJECTION_DETECTED="Invalid URL: A code injection has been detected in %1$s." JLIB_FORM_VALIDATE_FIELD_URL_SCHEMA_MISSING="Invalid URL: URL schema is missing in %1$s. Please add one of the following at the beginning: %2$s." +JLIB_FORM_VALIDATE_FIELD_URL_INJECTION_DETECTED="Invalid URL: A code injection has been detected in %1$s." JLIB_FORM_VALUE_CACHE_APCU="APC User Cache" JLIB_FORM_VALUE_CACHE_FILE="File" JLIB_FORM_VALUE_CACHE_MEMCACHED="Memcached (Experimental)" @@ -545,7 +547,7 @@ JLIB_INSTALLER_AVAILABLE_UPDATE_PHP_VERSION="For the extension %1$s version %2$s JLIB_INSTALLER_DEFAULT_STYLE="%s - Default" JLIB_INSTALLER_DISCOVER="Discover" JLIB_INSTALLER_DISCOVER_INSTALL="Discover Install" -JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE="The %s extension is part of a package which does not allow individual extensions to be uninstalled." +JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE="The %1$s extension is part of a package which does not allow individual extensions to be uninstalled." JLIB_INSTALLER_ERROR_COMP_DISCOVER_STORE_DETAILS="Component Discover install: Failed to store component details." JLIB_INSTALLER_ERROR_COMP_INSTALL_ADMIN_ELEMENT="Component Install: The XML file did not have an administration element." JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_ADMIN="Component Install: Another component is already using folder: %s" @@ -615,8 +617,10 @@ JLIB_INSTALLER_ERROR_PACK_UNINSTALL_INVALID_MANIFEST="Package Uninstall: Invalid JLIB_INSTALLER_ERROR_PACK_UNINSTALL_INVALID_NOTFOUND_MANIFEST="Package Uninstall: Manifest file invalid or not found: %s" JLIB_INSTALLER_ERROR_PACK_UNINSTALL_LOAD_MANIFEST="Package Uninstall: Could not load manifest file." JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MANIFEST_NOT_REMOVED="Package Uninstall: Errors were detected, manifest file not removed!" +JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MISSING_EXTENSION="Package Uninstall: This extension is missing or has already been uninstalled: %s" JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MISSINGMANIFEST="Package Uninstall: Missing manifest file." JLIB_INSTALLER_ERROR_PACK_UNINSTALL_NOT_PROPER="Package Uninstall: This extension may have already been uninstalled or might not have been uninstalled properly: %s" +; The following string is deprecated and will be removed with 6.0 JLIB_INSTALLER_ERROR_PACK_UNINSTALL_UNKNOWN_EXTENSION="Trying to uninstall unknown extension from package. This extension may have already been removed earlier." JLIB_INSTALLER_ERROR_PACK_UNINSTALL_WARNCOREPACK="Package Uninstall: Trying to uninstall core package." JLIB_INSTALLER_ERROR_PLG_DISCOVER_STORE_DETAILS="Plugin Discover install: Failed to store plugin details." @@ -658,6 +662,13 @@ JLIB_INSTALLER_SQL_BEGIN="Start of SQL updates." JLIB_INSTALLER_SQL_BEGIN_SCHEMA="The current database version (schema) is %s." JLIB_INSTALLER_SQL_END="End of SQL updates." JLIB_INSTALLER_SQL_END_NOT_COMPLETE="End of SQL updates - INCOMPLETE." +JLIB_INSTALLER_TUF_FREEZE_ATTACK="Update not possible because the offered update has expired." +JLIB_INSTALLER_TUF_DEBUG_MESSAGE="TUF Debug Message: %s" +JLIB_INSTALLER_TUF_INVALID_METADATA="The saved TUF update information is invalid." +JLIB_INSTALLER_TUF_NOT_AVAILABLE="TUF is not available for extensions yet." +JLIB_INSTALLER_TUF_DOWNLOAD_SIZE="The size of the update downloaded did not match the expected size." +JLIB_INSTALLER_TUF_ROLLBACK_ATTACK="Update not possible because the offered update is older than the currently installed version." +JLIB_INSTALLER_TUF_SIGNATURE_THRESHOLD="Update not possible because the offered update does not have enough signatures." JLIB_INSTALLER_UNINSTALL="Uninstall" JLIB_INSTALLER_UPDATE="Update" JLIB_INSTALLER_UPDATE_LOG_QUERY="Ran query from file %1$s. Query text: %2$s." diff --git a/administrator/language/en-GB/plg_fields_list.ini b/administrator/language/en-GB/plg_fields_list.ini index f3b4e535323f2..4208cf647e8e3 100644 --- a/administrator/language/en-GB/plg_fields_list.ini +++ b/administrator/language/en-GB/plg_fields_list.ini @@ -5,6 +5,10 @@ PLG_FIELDS_LIST="Fields - List" PLG_FIELDS_LIST_LABEL="List (%s)" +; The following string is deprecated and will be removed with 6.0 +PLG_FIELDS_LIST_PARAMS_FORM_LAYOUT_FANCY_SELECT="Enhanced select" +PLG_FIELDS_LIST_PARAMS_HEADER_DESC="Add a string with no value at the top of the dropdown list eg ' - Select Article - '." +PLG_FIELDS_LIST_PARAMS_HEADER_LABEL="Header" PLG_FIELDS_LIST_PARAMS_MULTIPLE_LABEL="Multiple" PLG_FIELDS_LIST_PARAMS_OPTIONS_LABEL="List Values" PLG_FIELDS_LIST_PARAMS_OPTIONS_NAME_LABEL="Text" diff --git a/administrator/language/en-GB/plg_fields_sql.ini b/administrator/language/en-GB/plg_fields_sql.ini index 69403cdbc53c5..0354e65bde29b 100644 --- a/administrator/language/en-GB/plg_fields_sql.ini +++ b/administrator/language/en-GB/plg_fields_sql.ini @@ -6,6 +6,8 @@ PLG_FIELDS_SQL="Fields - SQL" PLG_FIELDS_SQL_CREATE_NOT_POSSIBLE="Only a Super User can create or edit an SQL field!" PLG_FIELDS_SQL_LABEL="SQL (%s)" +; The following string is deprecated and will be removed with 6.0 +PLG_FIELDS_SQL_PARAMS_FORM_LAYOUT_FANCY_SELECT="Enhanced select" PLG_FIELDS_SQL_PARAMS_HEADER_DESC="Add a string with no value at the top of the dropdown list eg ' - Select Article - '." PLG_FIELDS_SQL_PARAMS_HEADER_LABEL="Header" PLG_FIELDS_SQL_PARAMS_MULTIPLE_LABEL="Multiple" diff --git a/administrator/language/en-GB/plg_schemaorg_article.ini b/administrator/language/en-GB/plg_schemaorg_article.ini new file mode 100644 index 0000000000000..d4fd8dca6f197 --- /dev/null +++ b/administrator/language/en-GB/plg_schemaorg_article.ini @@ -0,0 +1,28 @@ +; Joomla! Project +; (C) 2024 Open Source Matters, Inc. +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_SCHEMAORG_ARTICLE="Schema.org - Article" +PLG_SCHEMAORG_ARTICLE_DESCRIPTION_LABEL="More information on the Schema.org Article Type can be found at https://schema.org/Article" +PLG_SCHEMAORG_ARTICLE_FIELD_ADDRESS_LABEL="Address" +PLG_SCHEMAORG_ARTICLE_FIELD_AUTHOR_LABEL="Author" +PLG_SCHEMAORG_ARTICLE_FIELD_DATE_MODIFIED_LABEL="Date Modified" +PLG_SCHEMAORG_ARTICLE_FIELD_DATE_PUBLISHED_LABEL="Date Published" +PLG_SCHEMAORG_ARTICLE_FIELD_DESCRIPTION_LABEL="Description" +PLG_SCHEMAORG_ARTICLE_FIELD_EMAIL_LABEL="Email" +PLG_SCHEMAORG_ARTICLE_FIELD_GENERIC_FIELD_LABEL="Generic Field" +PLG_SCHEMAORG_ARTICLE_FIELD_GENERIC_TITLE_LABEL="Title" +PLG_SCHEMAORG_ARTICLE_FIELD_GENERIC_VALUE_LABEL="Value" +PLG_SCHEMAORG_ARTICLE_FIELD_HEADLINE_LABEL="Headline" +PLG_SCHEMAORG_ARTICLE_FIELD_IMAGE_LABEL="Image" +PLG_SCHEMAORG_ARTICLE_FIELD_LOCALITY_LABEL="Locality" +PLG_SCHEMAORG_ARTICLE_FIELD_LOGO_LABEL="Logo" +PLG_SCHEMAORG_ARTICLE_FIELD_NAME_LABEL="Name" +PLG_SCHEMAORG_ARTICLE_FIELD_ORGANIZATION_LABEL="Organization" +PLG_SCHEMAORG_ARTICLE_FIELD_PERSON_LABEL="Person" +PLG_SCHEMAORG_ARTICLE_FIELD_POSTAL_CODE_LABEL="Postal Code" +PLG_SCHEMAORG_ARTICLE_FIELD_STREET_ADDRESS_LABEL="Street Address" +PLG_SCHEMAORG_ARTICLE_FIELD_TYPE_LABEL="Type" +PLG_SCHEMAORG_ARTICLE_FIELD_URL_LABEL="Url" +PLG_SCHEMAORG_ARTICLE_XML_DESCRIPTION="Adds Article as a new schema type in existing schemas." diff --git a/administrator/language/en-GB/plg_schemaorg_article.sys.ini b/administrator/language/en-GB/plg_schemaorg_article.sys.ini new file mode 100644 index 0000000000000..c2d56801161fb --- /dev/null +++ b/administrator/language/en-GB/plg_schemaorg_article.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; (C) 2024 Open Source Matters, Inc. +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_SCHEMAORG_ARTICLE="Schema.org - Article" +PLG_SCHEMAORG_ARTICLE_XML_DESCRIPTION="Adds Article as a new schema type in existing schemas." diff --git a/administrator/language/en-GB/plg_schemaorg_custom.ini b/administrator/language/en-GB/plg_schemaorg_custom.ini new file mode 100755 index 0000000000000..26431d79293ce --- /dev/null +++ b/administrator/language/en-GB/plg_schemaorg_custom.ini @@ -0,0 +1,10 @@ +; Joomla! Project +; (C) 2024 Open Source Matters, Inc. +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_SCHEMAORG_CUSTOM="Schema.org - Custom" +PLG_SCHEMAORG_CUSTOM_XML_DESCRIPTION="Adds a custom field to add any schema type." +PLG_SCHEMAORG_CUSTOM_DESCRIPTION_LABEL="Use any JSON-LD code here to add currently unsupported schema types." +PLG_SCHEMAORG_CUSTOM_JSON_ERROR="The JSON code is not valid or @context or @type is missing." +PLG_SCHEMAORG_CUSTOM_JSON_FIELD_LABEL="JSON Code" diff --git a/administrator/language/en-GB/plg_schemaorg_custom.sys.ini b/administrator/language/en-GB/plg_schemaorg_custom.sys.ini new file mode 100755 index 0000000000000..69568f944c3ef --- /dev/null +++ b/administrator/language/en-GB/plg_schemaorg_custom.sys.ini @@ -0,0 +1,8 @@ +; Joomla! Project +; (C) 2024 Open Source Matters, Inc. + +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_SCHEMAORG_CUSTOM="Schema.org - Custom" +PLG_SCHEMAORG_CUSTOM_XML_DESCRIPTION="Adds a custom field to add any schema type." diff --git a/administrator/language/en-GB/plg_system_jooa11y.ini b/administrator/language/en-GB/plg_system_jooa11y.ini index e061fc5a5ca7b..18c008803749c 100644 --- a/administrator/language/en-GB/plg_system_jooa11y.ini +++ b/administrator/language/en-GB/plg_system_jooa11y.ini @@ -4,17 +4,33 @@ ; Note : All ini files need to be saved as UTF-8 PLG_SYSTEM_JOOA11Y="System - Joomla Accessibility Checker" -PLG_SYSTEM_JOOA11Y_FIELD_CHECK_ROOT="Content Container" -PLG_SYSTEM_JOOA11Y_FIELD_CHECK_ROOT_DESC="Landmark on the page that will be checked for accessibility. The default setting is the landmark main. Alternatives to landmarks are classes, elements or ARIA roles (eg #example, .example, [role=example])." +PLG_SYSTEM_JOOA11Y_XML_DESCRIPTION="The Joomla Accessibility Checker visually highlights common accessibility and usability issues. Geared towards content authors, the plugin identifies errors or warnings and provides guidance on how to fix them. Please be aware that this plugin does not offer an exhaustive analysis of your website, nor does it automatically ensure your website's accessibility. It's important to select a template that is inherently accessible to ensure your site meets accessibility standards." +PLG_SYSTEM_JOOA11Y_FIELD_CHECK_ROOT="Target Area to Check" +PLG_SYSTEM_JOOA11Y_FIELD_CHECK_ROOT_DESC="Input a single selector to target a specific region of your website. The default setting is the landmark main. Alternatives to landmarks are classes, elements or ARIA roles (e.g. #main-content, .main, [role='main']). Input body to check the entire page." PLG_SYSTEM_JOOA11Y_FIELD_CONTAINER_IGNORE="Ignore Regions" PLG_SYSTEM_JOOA11Y_FIELD_CONTAINER_IGNORE_DESC="Ignore specific regions within the Content Container. Use commas to separate classes or elements (eg #ignore, .ignore)." -PLG_SYSTEM_JOOA11Y_FIELD_READABILITY_ROOT="Readability Container" -PLG_SYSTEM_JOOA11Y_FIELD_READABILITY_ROOT_DESC="Landmark on the page that will be checked for readability. The default setting is the landmark main. Alternatives to landmarks are classes, elements or ARIA roles (eg #example, .example, [role=example])." +PLG_SYSTEM_JOOA11Y_FIELD_READABILITY_ROOT="Readability Target Area" +PLG_SYSTEM_JOOA11Y_FIELD_READABILITY_ROOT_DESC="Landmark on the page that will be checked for readability. The default setting is the landmark main." PLG_SYSTEM_JOOA11Y_FIELD_SHOW_ALWAYS="Show Always" -PLG_SYSTEM_JOOA11Y_FIELD_SHOW_ALWAYS_DESC="Load the accessiblity checker on all pages. This is useful when developing the website but should not be left on when the website is live." -PLG_SYSTEM_JOOA11Y_XML_DESCRIPTION="The Joomla Accessibility Checker visually highlights common accessibility and usability issues. Geared towards content authors, the plugin identifies errors or warnings and provides guidance on how to fix them." +PLG_SYSTEM_JOOA11Y_FIELD_SHOW_ALWAYS_DESC="Load the accessiblity checker on all pages. This is useful when developing the website, but should not be left on when the website is live." +PLG_SYSTEM_JOOA11Y_FIELD_ADDITIONAL_CHECKS="Additional Checks Always On" +PLG_SYSTEM_JOOA11Y_FIELD_ADDITIONAL_CHECKS_DESC="Enabling this option will visually hide the toggle switches for Form Labels, Contrast, Links (Advanced) in the Settings panel." +PLG_SYSTEM_JOOA11Y_FIELD_WEB_COMPONENTS="Web Components to Check" +PLG_SYSTEM_JOOA11Y_FIELD_WEB_COMPONENTS_DESC="Provide a list of all known web components or containers with an open shadow DOM." +PLG_SYSTEM_JOOA11Y_FIELD_CONTRAST="Contrast" +PLG_SYSTEM_JOOA11Y_FIELD_CONTRAST_DESC="Show Contrast toggle in Settings panel. Check for WCAG 2.0 Level AA contrast issues between foreground text and background elements." +PLG_SYSTEM_JOOA11Y_FIELD_FORM_LABELS="Form Labels" +PLG_SYSTEM_JOOA11Y_FIELD_FORM_LABELS_DESC="Show Form Labels toggle in Settings panel. Check for form inputs missing a corresponding label. Not necessarily a content author issue, and usually not an issue when using a reputable, accessible forms plugin." +PLG_SYSTEM_JOOA11Y_FIELD_LINKS_ADVANCED="Links (Advanced)" +PLG_SYSTEM_JOOA11Y_FIELD_LINKS_ADVANCED_DESC="Show Links (Advanced) toggle in Settings panel. Check for additional issues such as: links that open in a new tab without warning, have identical names but different purpose, or points to a PDF and other files without warning." +PLG_SYSTEM_JOOA11Y_FIELD_COLOUR_FILTER="Colour Filter" +PLG_SYSTEM_JOOA11Y_FIELD_COLOUR_FILTER_DESC="Show Colour Filter toggle in Settings panel. Colour filters help identify colour combinations that may be difficult for people to distinguish." +PLG_SYSTEM_JOOA11Y_FIELD_EXTRA_PROPS="Extra Properties" +PLG_SYSTEM_JOOA11Y_FIELD_EXTRA_PROPS_DESC="Pass additional properties to customise. Provide a valid key/value pair. Refer to documentation." +PLG_SYSTEM_JOOA11Y_KEY="Key" +PLG_SYSTEM_JOOA11Y_VALUE="Value" -;Global text +; All the following strings are deprecated and will be removed with 6.0 PLG_SYSTEM_JOOA11Y_ALERT_CLOSE="Close" PLG_SYSTEM_JOOA11Y_ALERT_TEXT="Alert" PLG_SYSTEM_JOOA11Y_CONTAINER_LABEL="Accessibility Checker" @@ -37,8 +53,6 @@ PLG_SYSTEM_JOOA11Y_SHORTCUT_TOOLTIP="Skip to issue" PLG_SYSTEM_JOOA11Y_SHOW_OUTLINE="Show Outline" PLG_SYSTEM_JOOA11Y_SHOW_SETTINGS="Show Settings" PLG_SYSTEM_JOOA11Y_WARNING="Warning" - -;Readability panel. PLG_SYSTEM_JOOA11Y_AVG_WORD_PER_SENTENCE="Average words per sentence:" PLG_SYSTEM_JOOA11Y_COMPLEX_WORDS="Complex words:" PLG_SYSTEM_JOOA11Y_DIFFICULT_READABILITY="Difficult" @@ -47,16 +61,12 @@ PLG_SYSTEM_JOOA11Y_GOOD_READABILITY="Good" PLG_SYSTEM_JOOA11Y_READABILITY="Readability:" PLG_SYSTEM_JOOA11Y_TOTAL_WORDS="Words:" PLG_SYSTEM_JOOA11Y_VERY_DIFFICULT_READABILITY="Very difficult" - -;Panel status PLG_SYSTEM_JOOA11Y_PANEL_STATUS_BOTH="Accessibility Errors: %(errorCount). Accessibility Warnings: %(warningCount)." PLG_SYSTEM_JOOA11Y_PANEL_STATUS_ERRORS="Accessibility Errors: %(errorCount)." PLG_SYSTEM_JOOA11Y_PANEL_STATUS_HIDDEN="The item you are trying to view is not visible; it may be hidden or inside of an accordion or tab component. Here's a preview: " PLG_SYSTEM_JOOA11Y_PANEL_STATUS_ICON="Total issues found: %(totalCount)" PLG_SYSTEM_JOOA11Y_PANEL_STATUS_NONE="No accessibility errors found." PLG_SYSTEM_JOOA11Y_PANEL_STATUS_WARNINGS="Accessibility Warnings: %(warningCount)." - -;Headings PLG_SYSTEM_JOOA11Y_HEADING_EMPTY="Empty heading found! To fix, delete this line or change its format from Heading %(level) to Normal or Paragraph." PLG_SYSTEM_JOOA11Y_HEADING_EMPTY_WITH_IMAGE="Heading has no text, but contains an image. If this is not a heading, change its format from Heading %(level) to Normal or Paragraph. Otherwise, please add alt text to the image if it is not decorative." PLG_SYSTEM_JOOA11Y_HEADING_FIRST="The first heading on a page should usually be a Heading 1 or Heading 2. Heading 1 should be the start of the main content section, and is the main heading that describes the overall purpose of the page. Learn more about Heading Structure." @@ -65,8 +75,6 @@ PLG_SYSTEM_JOOA11Y_HEADING_LONG_INFO="Character Count: %(headingLength)< PLG_SYSTEM_JOOA11Y_HEADING_MISSING_ONE="Missing Heading 1. Heading 1 should be the start of the main content area, and is the main heading that describes the overall purpose of the page. Learn more about Heading Structure." PLG_SYSTEM_JOOA11Y_HEADING_NON_CONSECUTIVE_LEVEL="Non-consecutive heading level used. Headings should never skip levels, or go from Heading %(prevLevel) to Heading %(level)." PLG_SYSTEM_JOOA11Y_PANEL_HEADING_MISSING_ONE="Missing Heading 1!" - -;Link Text PLG_SYSTEM_JOOA11Y_LINK_BEST_PRACTICES="Consider replacing the link text: %(error)" PLG_SYSTEM_JOOA11Y_LINK_BEST_PRACTICES_DETAILS="
    • "Click here" places focus on mouse mechanics, when many people do not use a mouse or may be viewing this website on a mobile device. Consider using a different verb that relates to the task.
    • Avoid using HTML symbols as call to actions unless they are hidden to assistive technologies.
    " PLG_SYSTEM_JOOA11Y_LINK_EMPTY="Remove empty links without any text." @@ -76,16 +84,12 @@ PLG_SYSTEM_JOOA11Y_LINK_STOPWORD="Link text may not be descriptive enough out of PLG_SYSTEM_JOOA11Y_LINK_STOPWORD_TIP="Tip! Link text should always be clear, unique, and meaningful. Avoid common words like \"click here\"; or \"learn more\"." PLG_SYSTEM_JOOA11Y_LINK_URL="Longer, less intelligible URLs used as link text might be difficult to listen to with assistive technology. In most cases, it is better to use human-readable text instead of the URL. Short URLs (such as a site's homepage) are okay." PLG_SYSTEM_JOOA11Y_LINK_URL_TIP="Tip! Link text should always be clear, unique, and meaningful so it could be understood out of context." - -;Links Advanced PLG_SYSTEM_JOOA11Y_FILE_TYPE_WARNING="Link points to a PDF or downloadable file (e.g. MP3, Zip, Word Doc) without warning. Indicate the file type within the link text. If it is a large file, consider including the file size." PLG_SYSTEM_JOOA11Y_FILE_TYPE_WARNING_TIP="Example: Executive Report (PDF, 3MB)" PLG_SYSTEM_JOOA11Y_LINK_IDENTICAL_NAME="Link has identical text as another link, although it points to a different page. Multiple links with the same text may cause confusion for people who use screen readers." PLG_SYSTEM_JOOA11Y_LINK_IDENTICAL_NAME_TIP="Consider making the following link more descriptive to help distinguish it from other links: %(linkText)" PLG_SYSTEM_JOOA11Y_NEW_TAB_WARNING="Link opens in a new tab or window without warning. Doing so can be disorienting, especially for people who have difficulty perceiving visual content. Secondly, it is not always a good practice to control someone's experience or make decisions for them. Indicate that the link opens in a new window within the link text." PLG_SYSTEM_JOOA11Y_NEW_TAB_WARNING_TIP="Tip! Learn best practices: opening links in new browser windows and tabs." - -;Images PLG_SYSTEM_JOOA11Y_HYPERLINK_ALT_LENGTH_MESSAGE="Alt text description on a linked image is too long. The alt text on linked images should describe where the link takes you, not a literal description of the image. Consider using the title of the page it links to as the alt text." PLG_SYSTEM_JOOA11Y_HYPERLINK_ALT_LENGTH_MESSAGE_INFO="The alt text is %(altLength) characters: %(altText)" PLG_SYSTEM_JOOA11Y_IMAGE_FIGURE_DECORATIVE="Image is marked as decorative and will be ignored by assistive technology." @@ -117,8 +121,6 @@ PLG_SYSTEM_JOOA11Y_MISSING_ALT_LINK_MESSAGE="Image is being used as a link but i PLG_SYSTEM_JOOA11Y_MISSING_ALT_MESSAGE="Missing alt text! If the image conveys a story, mood, or important information - be sure to describe the image." PLG_SYSTEM_JOOA11Y_TEXT_UNDERLINE_WARNING="Underlined text can be confused with links." PLG_SYSTEM_JOOA11Y_TEXT_UNDERLINE_WARNING_TIP="Consider using a different style such as <em>emphasis</em>." - -;Labels PLG_SYSTEM_JOOA11Y_LABELS_ARIA_LABEL_INPUT_MESSAGE="Input has an accessible name, although please ensure there is a visible label too." PLG_SYSTEM_JOOA11Y_LABELS_ARIA_LABEL_INPUT_MESSAGE_INFO="The accessible name for this input is: %(ariaLabel)" PLG_SYSTEM_JOOA11Y_LABELS_INPUT_RESET_MESSAGE="Reset buttons should not be used unless specifically needed because they are easy to activate by mistake." @@ -127,26 +129,18 @@ PLG_SYSTEM_JOOA11Y_LABELS_MISSING_IMAGE_INPUT_MESSAGE="Image button is missing a PLG_SYSTEM_JOOA11Y_LABELS_MISSING_LABEL_MESSAGE="There is no label associated with this input. Please add an id to this input, and add a matching for attribute to the label." PLG_SYSTEM_JOOA11Y_LABELS_NO_FOR_ATTRIBUTE_MESSAGE="There is no label associated with this input. Add a for attribute to the label that matches the id of this input." PLG_SYSTEM_JOOA11Y_LABELS_NO_FOR_ATTRIBUTE_MESSAGE_INFO="The ID for this input is: id="%(t)"" - -;Embedded content PLG_SYSTEM_JOOA11Y_EMBED_AUDIO="Please ensure to provide a transcript for all podcasts. Providing transcripts for audio content is a mandatory Level A requirement. Transcripts support people who are D/deaf or hard-of-hearing, but can benefit everyone. Consider placing the transcript below or within an accordion panel." PLG_SYSTEM_JOOA11Y_EMBED_GENERAL_WARNING="Unable to check embedded content. Please make sure that images have alt text, videos have captions, text has sufficient contrast, and interactive components are keyboard accessible." PLG_SYSTEM_JOOA11Y_EMBED_MISSING_TITLE="Embedded content requires an accessible name that describes its contents. Please provide a unique title or aria-label attribute on the iframe element. Learn more about iFrames." PLG_SYSTEM_JOOA11Y_EMBED_VIDEO="Please ensure all videos have closed captioning. Providing captions for all audio and video content is a mandatory Level A requirement. Captions support people who are D/deaf or hard-of-hearing." - -;Contrast PLG_SYSTEM_JOOA11Y_CONTRAST_ERROR_INPUT_MESSAGE="The text within this input does not have enough contrast with the background. The contrast ratio should be at least 4.5:1 for normal text and 3:1 for large text." PLG_SYSTEM_JOOA11Y_CONTRAST_ERROR_INPUT_MESSAGE_INFO="The contrast ratio is %(cratio)." PLG_SYSTEM_JOOA11Y_CONTRAST_ERROR_MESSAGE="This text does not have enough contrast with the background. The contrast ratio should be at least 4.5:1 for normal text and 3:1 for large text." PLG_SYSTEM_JOOA11Y_CONTRAST_ERROR_MESSAGE_INFO="The contrast ratio is %(cratio) for the following text: %(nodetext)" PLG_SYSTEM_JOOA11Y_CONTRAST_WARNING_MESSAGE="The contrast of this text is unknown and needs to be manually reviewed. Ensure the text and the background have strong contrasting colours. The contrast ratio should be at least 4.5:1 for normal text and 3:1 for large text." PLG_SYSTEM_JOOA11Y_CONTRAST_WARNING_MESSAGE_INFO="Please review contrast of the following text:
    %(nodetext)" - -;Readability PLG_SYSTEM_JOOA11Y_READABILITY_NOT_ENOUGH_CONTENT_MESSAGE="Not enough content to calculate readability score." PLG_SYSTEM_JOOA11Y_READABILITY_NO_P_OR_LI_MESSAGE="Unable to calculate readability score. No paragraph <p> or list content <li> found." - -;QA PLG_SYSTEM_JOOA11Y_QA_BAD_ITALICS="Bold and italic tags have semantic meaning, and should not be used to highlight entire paragraphs. Bolded text should be used to provide strong emphasis on a word or phrase. Italics should be used to highlight proper names (i.e. book and article titles), foreign words, quotes. Long quotes should be formatted as a blockquote." PLG_SYSTEM_JOOA11Y_QA_BAD_LINK="Bad link found. Link appears to point to a development environment. This link points to: %(el)" PLG_SYSTEM_JOOA11Y_QA_BLOCKQUOTE_MESSAGE="Is this a heading? %(bqHeadingText)" @@ -160,8 +154,6 @@ PLG_SYSTEM_JOOA11Y_QA_PDF_COUNT="PDFs are considered web content and must be mad PLG_SYSTEM_JOOA11Y_QA_SHOULD_BE_LIST="Are you trying to create a list? Possible list item found: %(firstPrefix)" PLG_SYSTEM_JOOA11Y_QA_SHOULD_BE_LIST_TIP="Make sure to use semantic lists by using the bullet or number formatting buttons instead. When using a semantic list, assistive technologies are able to convey information such as the total number of items and the relative position of each item in the list. Learn more about semantic lists." PLG_SYSTEM_JOOA11Y_QA_UPPERCASE_WARNING="Found all caps. Some screen readers may interpret all caps text as an acronym and will read each letter individually. Additionally, some people find all caps more difficult to read and it may give the appearance of SHOUTING." - -;Tables PLG_SYSTEM_JOOA11Y_TABLES_EMPTY_HEADING="Empty table header found! Table headers should never be empty. It is important to designate row and/or column headers to convey their relationship. This information provides context to people who use assistive technology. Please keep in mind that tables should be used for tabular data only." PLG_SYSTEM_JOOA11Y_TABLES_EMPTY_HEADING_INFO="Learn more about accessible tables." PLG_SYSTEM_JOOA11Y_TABLES_MISSING_HEADINGS="Missing table headers! Accessible tables need HTML markup that indicates header cells and data cells which defines their relationship. This information provides context to people who use assistive technology. Tables should be used for tabular data only." diff --git a/administrator/language/en-GB/plg_system_jooa11y.sys.ini b/administrator/language/en-GB/plg_system_jooa11y.sys.ini index 02519b0004979..9bac6ee47a022 100644 --- a/administrator/language/en-GB/plg_system_jooa11y.sys.ini +++ b/administrator/language/en-GB/plg_system_jooa11y.sys.ini @@ -4,4 +4,4 @@ ; Note : All ini files need to be saved as UTF-8 PLG_SYSTEM_JOOA11Y="System - Joomla Accessibility Checker" -PLG_SYSTEM_JOOA11Y_XML_DESCRIPTION="The Joomla Accessibility Checker visually highlights common accessibility and usability issues. Geared towards content authors, the plugin identifies errors or warnings and provides guidance on how to fix them." +PLG_SYSTEM_JOOA11Y_XML_DESCRIPTION="The Joomla Accessibility Checker visually highlights common accessibility and usability issues. Geared towards content authors, the plugin identifies errors or warnings and provides guidance on how to fix them. Please be aware that this plugin does not offer an exhaustive analysis of your website, nor does it automatically ensure your website's accessibility. It's important to select a template that is inherently accessible to ensure your site meets accessibility standards." diff --git a/administrator/language/en-GB/plg_system_schemaorg.ini b/administrator/language/en-GB/plg_system_schemaorg.ini index 1a09bab4e6adf..189a8c2a5f227 100755 --- a/administrator/language/en-GB/plg_system_schemaorg.ini +++ b/administrator/language/en-GB/plg_system_schemaorg.ini @@ -11,6 +11,7 @@ PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_PERSON="Person" PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION="Structured data is a standardised format for organising and representing information on the web. It provides a way to describe the content and meaning of data in a structured manner, making it easier for search engines and other applications to understand and process the information. More information on schema.org." PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION_NOT_CONFIGURATED="To use the schema.org functionality, you have to configure the plugin first. Please contact an administrator of the page to get it configured." PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION_NOT_CONFIGURATED_ADMIN="To use the schema.org functionality, you have to configure the plugin first. Please select this link to open the plugin, configure and save." +PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_EXTEND_JED_DESC="Need more Schema types? Extend with Schema Plugins from Joomla! Extension Directory." PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_LABEL="Schema" PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_TYPE_LABEL="Schema Type" PLG_SYSTEM_SCHEMAORG_IMAGE_LABEL="Image" diff --git a/administrator/language/en-GB/plg_system_sef.ini b/administrator/language/en-GB/plg_system_sef.ini index 42e97e4a285c8..6540197978992 100644 --- a/administrator/language/en-GB/plg_system_sef.ini +++ b/administrator/language/en-GB/plg_system_sef.ini @@ -5,5 +5,12 @@ PLG_SEF_DOMAIN_DESCRIPTION="If your site can be accessed through more than one domain enter the preferred (sometimes referred to as canonical) domain here.
    Note: https://example.com and https://www.example.com are different domains." PLG_SEF_DOMAIN_LABEL="Site Domain" +PLG_SEF_INDEXPHP_DESCRIPTION="This option enables a stricter handling of 'index.php' in URLs when 'Use URL Rewriting' is enabled in Global Configuration. It will remove 'index.php' if a URL still contains it and redirect incoming requests with 'index.php' to the version without the 'index.php'." +PLG_SEF_INDEXPHP_LABEL="Strict handling of index.php" +PLG_SEF_TRAILINGSLASH_DESCRIPTION="Force Joomla to only use URLs with or without trailing slash. When set, this will force the right URL with redirects and is only applied when 'Add suffix to URL' is disabled." +PLG_SEF_TRAILINGSLASH_LABEL="Trailing slash for URLs" +PLG_SEF_TRAILINGSLASH_OPTION_NONE="No change" +PLG_SEF_TRAILINGSLASH_OPTION_NO_SLASH="Enforce URLs without trailing slash" +PLG_SEF_TRAILINGSLASH_OPTION_SLASH="Enforce URLs with trailing slash" PLG_SEF_XML_DESCRIPTION="Adds SEF support to links in the document. It operates directly on the HTML and does not require a special tag." PLG_SYSTEM_SEF="System - SEF" diff --git a/administrator/language/en-GB/plg_task_deleteactionlogs.ini b/administrator/language/en-GB/plg_task_deleteactionlogs.ini index 30a9ede1a6fb2..43ba702e4bd6f 100644 --- a/administrator/language/en-GB/plg_task_deleteactionlogs.ini +++ b/administrator/language/en-GB/plg_task_deleteactionlogs.ini @@ -5,6 +5,6 @@ PLG_TASK_DELETEACTIONLOGS="Task - Delete Action Logs" PLG_TASK_DELETEACTIONLOGS_DELETE_DESC="Delete Action logs after days" -PLG_TASK_DELETEACTIONLOGS_DELETE_TITLE="Delete ActionLogs - Task" +PLG_TASK_DELETEACTIONLOGS_DELETE_TITLE="Delete ActionLogs" PLG_TASK_DELETEACTIONLOGS_LOG_DELETE_PERIOD="Days to delete action logs after" PLG_TASK_DELETEACTIONLOGS_XML_DESCRIPTION="This plugin for schedule Action Logs delete Tasks." diff --git a/administrator/language/en-GB/plg_task_sessiongc.ini b/administrator/language/en-GB/plg_task_sessiongc.ini index 0064055c70eb8..e01f337c39ce3 100644 --- a/administrator/language/en-GB/plg_task_sessiongc.ini +++ b/administrator/language/en-GB/plg_task_sessiongc.ini @@ -9,5 +9,5 @@ PLG_TASK_SESSIONGC_ENABLE_SESSION_GC_DESC="When enabled, this plugin will attemp PLG_TASK_SESSIONGC_ENABLE_SESSION_GC_LABEL="Enable Session Data Cleanup" PLG_TASK_SESSIONGC_ENABLE_SESSION_METADATA_GC_DESC="When enabled, this plugin will clean optional session metadata from the database. Note that this operation will not run when the database handler is in use as that data is cleared as part of the Session Data Cleanup operation." PLG_TASK_SESSIONGC_ENABLE_SESSION_METADATA_GC_LABEL="Enable Session Metadata Cleanup" -PLG_TASK_SESSIONGC_TITLE="Task - Session Data Purge" +PLG_TASK_SESSIONGC_TITLE="Session Data Purge" PLG_TASK_SESSIONGC_XML_DESCRIPTION="Task Plugin that purges expired data and metadata depending on the session handler set in Global Configuration." diff --git a/administrator/manifests/files/joomla.xml b/administrator/manifests/files/joomla.xml index 9ad2ce83ad101..6c85e64939d30 100644 --- a/administrator/manifests/files/joomla.xml +++ b/administrator/manifests/files/joomla.xml @@ -6,8 +6,8 @@ www.joomla.org (C) 2019 Open Source Matters, Inc. GNU General Public License version 2 or later; see LICENSE.txt - 5.1.0-alpha3-dev - 2023-12 + 5.1.0-beta1-dev + 2024-02 FILES_JOOMLA_XML_DESCRIPTION administrator/components/com_admin/script.php diff --git a/administrator/manifests/packages/pkg_en-GB.xml b/administrator/manifests/packages/pkg_en-GB.xml index 37ebce28f1b8e..eb67d5684a636 100644 --- a/administrator/manifests/packages/pkg_en-GB.xml +++ b/administrator/manifests/packages/pkg_en-GB.xml @@ -3,7 +3,7 @@ English (en-GB) Language Pack en-GB 5.1.0.1 - 2023-12 + 2024-02 Joomla! Project admin@joomla.org www.joomla.org diff --git a/administrator/modules/mod_custom/mod_custom.php b/administrator/modules/mod_custom/mod_custom.php deleted file mode 100644 index fff0ea7ebba93..0000000000000 --- a/administrator/modules/mod_custom/mod_custom.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; -use Joomla\CMS\HTML\HTMLHelper; -use Joomla\CMS\Plugin\PluginHelper; - -if ($params->def('prepare_content', 1)) { - PluginHelper::importPlugin('content'); - $module->content = HTMLHelper::_('content.prepare', $module->content, '', 'mod_custom.content'); -} - -// Replace 'images/' to '../images/' when using an image from /images in backend. -$module->content = preg_replace('*src\=\"(?!administrator\/)images/*', 'src="../images/', $module->content); - -require ModuleHelper::getLayoutPath('mod_custom', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_custom/mod_custom.xml b/administrator/modules/mod_custom/mod_custom.xml index 1ebbe2b756ac3..a7c89c43e4f85 100644 --- a/administrator/modules/mod_custom/mod_custom.xml +++ b/administrator/modules/mod_custom/mod_custom.xml @@ -9,11 +9,13 @@ www.joomla.org 3.0.0 MOD_CUSTOM_XML_DESCRIPTION + Joomla\Module\Custom - mod_custom.php + services + src tmpl diff --git a/administrator/modules/mod_custom/services/provider.php b/administrator/modules/mod_custom/services/provider.php new file mode 100644 index 0000000000000..9f934359ea5e9 --- /dev/null +++ b/administrator/modules/mod_custom/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The custom module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Custom')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_custom/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_custom/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..b1b999e6b470b --- /dev/null +++ b/administrator/modules/mod_custom/src/Dispatcher/Dispatcher.php @@ -0,0 +1,49 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Custom\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\HTML\HTMLHelper; +use Joomla\CMS\Plugin\PluginHelper; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_custom + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + if ($data['params']->def('prepare_content', 1)) { + PluginHelper::importPlugin('content'); + $this->module->content = HTMLHelper::_('content.prepare', $this->module->content, '', 'mod_custom.content'); + } + + // Replace 'images/' to '../images/' when using an image from /images in backend. + $this->module->content = preg_replace('*src\=\"(?!administrator\/)images/*', 'src="../images/', $this->module->content); + + return $data; + } +} diff --git a/administrator/modules/mod_feed/tmpl/default.php b/administrator/modules/mod_feed/tmpl/default.php index 7a85db77211a2..4a547a3c2f2f3 100644 --- a/administrator/modules/mod_feed/tmpl/default.php +++ b/administrator/modules/mod_feed/tmpl/default.php @@ -56,7 +56,7 @@ get('rssdate', 1)) : ?> + if ($params->get('rssdate', 1) && ($feed->publishedDate !== null)) : ?>

    publishedDate, Text::_('DATE_FORMAT_LC3')); ?>

    @@ -93,7 +93,7 @@ - get('rssitemdate', 0)) : ?> + get('rssitemdate', 0) && $feed[$i]->publishedDate !== null) : ?>
    publishedDate, Text::_('DATE_FORMAT_LC3')); ?>
    diff --git a/administrator/modules/mod_frontend/mod_frontend.php b/administrator/modules/mod_frontend/mod_frontend.php deleted file mode 100644 index 30a2040ff5100..0000000000000 --- a/administrator/modules/mod_frontend/mod_frontend.php +++ /dev/null @@ -1,17 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; - -$sitename = htmlspecialchars($app->get('sitename', ''), ENT_QUOTES, 'UTF-8'); - -require ModuleHelper::getLayoutPath('mod_frontend', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_frontend/mod_frontend.xml b/administrator/modules/mod_frontend/mod_frontend.xml index aed7ae00bca83..cc25290c6fffb 100644 --- a/administrator/modules/mod_frontend/mod_frontend.xml +++ b/administrator/modules/mod_frontend/mod_frontend.xml @@ -9,8 +9,10 @@ www.joomla.org 4.0.0 MOD_FRONTEND_XML_DESCRIPTION + Joomla\Module\Frontend - mod_frontend.php + services + src tmpl diff --git a/administrator/modules/mod_frontend/services/provider.php b/administrator/modules/mod_frontend/services/provider.php new file mode 100644 index 0000000000000..afb9da4d32c16 --- /dev/null +++ b/administrator/modules/mod_frontend/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The frontend link module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Frontend')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_frontend/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_frontend/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..fa0eec3f6f16b --- /dev/null +++ b/administrator/modules/mod_frontend/src/Dispatcher/Dispatcher.php @@ -0,0 +1,41 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Frontend\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_frontend + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['sitename'] = htmlspecialchars($this->getApplication()->get('sitename', ''), ENT_QUOTES, 'UTF-8'); + + return $data; + } +} diff --git a/administrator/modules/mod_latestactions/mod_latestactions.php b/administrator/modules/mod_latestactions/mod_latestactions.php deleted file mode 100644 index 6672e1a38b002..0000000000000 --- a/administrator/modules/mod_latestactions/mod_latestactions.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; -use Joomla\Module\LatestActions\Administrator\Helper\LatestActionsHelper; - -// Only super user can view this data -if (!$app->getIdentity()->authorise('core.admin')) { - return; -} - -$list = LatestActionsHelper::getList($params); - -if ($params->get('automatic_title', 0)) { - $module->title = LatestActionsHelper::getTitle($params); -} - -require ModuleHelper::getLayoutPath('mod_latestactions', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_latestactions/mod_latestactions.xml b/administrator/modules/mod_latestactions/mod_latestactions.xml index 834d2265293cb..98c7e13dbafec 100644 --- a/administrator/modules/mod_latestactions/mod_latestactions.xml +++ b/administrator/modules/mod_latestactions/mod_latestactions.xml @@ -11,7 +11,7 @@ MOD_LATESTACTIONS_XML_DESCRIPTION Joomla\Module\LatestActions - mod_latestactions.php + services src tmpl diff --git a/administrator/modules/mod_latestactions/services/provider.php b/administrator/modules/mod_latestactions/services/provider.php new file mode 100644 index 0000000000000..16f0f1c5f8c82 --- /dev/null +++ b/administrator/modules/mod_latestactions/services/provider.php @@ -0,0 +1,41 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\HelperFactory; +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The latest actions module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\LatestActions')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\LatestActions\\Administrator\\Helper')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_latestactions/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_latestactions/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..112a361903c84 --- /dev/null +++ b/administrator/modules/mod_latestactions/src/Dispatcher/Dispatcher.php @@ -0,0 +1,65 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\LatestActions\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Helper\HelperFactoryAwareInterface; +use Joomla\CMS\Helper\HelperFactoryAwareTrait; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_latestactions + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface +{ + use HelperFactoryAwareTrait; + + /** + * Runs the dispatcher. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function dispatch() + { + if (!$this->getApplication()->getIdentity()->authorise('core.admin')) { + return; + } + + parent::dispatch(); + } + + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['list'] = $this->getHelperFactory()->getHelper('LatestActionsHelper')->getActions($data['params']); + + if ($data['params']->get('automatic_title', 0)) { + $this->module->title = $this->getHelperFactory()->getHelper('LatestActionsHelper')->getModuleTitle($data['params']); + } + + return $data; + } +} diff --git a/administrator/modules/mod_latestactions/src/Helper/LatestActionsHelper.php b/administrator/modules/mod_latestactions/src/Helper/LatestActionsHelper.php index 1f2c2916efb47..f57eb56e98e41 100644 --- a/administrator/modules/mod_latestactions/src/Helper/LatestActionsHelper.php +++ b/administrator/modules/mod_latestactions/src/Helper/LatestActionsHelper.php @@ -24,7 +24,7 @@ * * @since 3.9.0 */ -abstract class LatestActionsHelper +class LatestActionsHelper { /** * Get a list of logged actions. @@ -33,11 +33,11 @@ abstract class LatestActionsHelper * * @return mixed An array of action logs, or false on error. * - * @since 3.9.1 + * @since __DEPLOY_VERSION__ * * @throws \Exception */ - public static function getList(&$params) + public function getActions(&$params) { /** @var \Joomla\Component\Actionlogs\Administrator\Model\ActionlogsModel $model */ $model = Factory::getApplication()->bootComponent('com_actionlogs')->getMVCFactory() @@ -61,6 +61,20 @@ public static function getList(&$params) return $rows; } + /** + * Get the alternate title for the module + * + * @param Registry $params The module parameters. + * + * @return string The alternate title for the module. + * + * @since __DEPLOY_VERSION__ + */ + public function getModuleTitle($params) + { + return Text::plural('MOD_LATESTACTIONS_TITLE', $params->get('count', 5)); + } + /** * Get the alternate title for the module * @@ -69,9 +83,37 @@ public static function getList(&$params) * @return string The alternate title for the module. * * @since 3.9.1 + * + * @deprecated __DEPLOY_VERSION__ will be removed in 7.0 + * Use the non-static method getModuleTitle + * Example: Factory::getApplication()->bootModule('mod_latestactions', 'administrator') + * ->getHelper('LatestActionsHelper') + * ->getModuleTitle($params) */ public static function getTitle($params) { - return Text::plural('MOD_LATESTACTIONS_TITLE', $params->get('count', 5)); + return (new self())->getModuleTitle($params); + } + + /** + * Get a list of logged actions. + * + * @param Registry &$params The module parameters. + * + * @return mixed An array of action logs, or false on error. + * + * @since 3.9.1 + * + * @throws \Exception + * + * @deprecated __DEPLOY_VERSION__ will be removed in 7.0 + * Use the non-static method getActions + * Example: Factory::getApplication()->bootModule('mod_latestactions', 'administrator') + * ->getHelper('LatestActionsHelper') + * ->getActions($params) + */ + public static function getList(&$params) + { + return (new self())->getActions($params); } } diff --git a/administrator/modules/mod_loginsupport/mod_loginsupport.php b/administrator/modules/mod_loginsupport/mod_loginsupport.php deleted file mode 100644 index a18fa6e566bc4..0000000000000 --- a/administrator/modules/mod_loginsupport/mod_loginsupport.php +++ /dev/null @@ -1,20 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; -use Joomla\CMS\Language\Text; - -if ($params->get('automatic_title')) { - $module->title = Text::_('MOD_LOGINSUPPORT_TITLE'); -} - -require ModuleHelper::getLayoutPath('mod_loginsupport', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_loginsupport/mod_loginsupport.xml b/administrator/modules/mod_loginsupport/mod_loginsupport.xml index 6b91edb8d7724..d4415329a868e 100644 --- a/administrator/modules/mod_loginsupport/mod_loginsupport.xml +++ b/administrator/modules/mod_loginsupport/mod_loginsupport.xml @@ -11,7 +11,8 @@ MOD_LOGINSUPPORT_XML_DESCRIPTION Joomla\Module\Loginsupport - mod_loginsupport.php + services + src tmpl diff --git a/administrator/modules/mod_loginsupport/services/provider.php b/administrator/modules/mod_loginsupport/services/provider.php new file mode 100644 index 0000000000000..6007807c09004 --- /dev/null +++ b/administrator/modules/mod_loginsupport/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The login support information module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Loginsupport')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_loginsupport/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_loginsupport/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..47d6610ecd4b6 --- /dev/null +++ b/administrator/modules/mod_loginsupport/src/Dispatcher/Dispatcher.php @@ -0,0 +1,44 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Loginsupport\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Language\Text; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_loginsupport + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + if ($data['params']->get('automatic_title')) { + $this->module->title = Text::_('MOD_LOGINSUPPORT_TITLE'); + } + + return $data; + } +} diff --git a/administrator/modules/mod_messages/mod_messages.php b/administrator/modules/mod_messages/mod_messages.php deleted file mode 100644 index 3ba859aa80b2c..0000000000000 --- a/administrator/modules/mod_messages/mod_messages.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; - -// Check permissions. -if (!$app->getIdentity()->authorise('core.login.admin') || !$app->getIdentity()->authorise('core.manage', 'com_messages')) { - return; -} - -// Try to get the items from the messages model -try { - /** @var \Joomla\Component\Messages\Administrator\Model\MessagesModel $messagesModel */ - $messagesModel = $app->bootComponent('com_messages')->getMVCFactory() - ->createModel('Messages', 'Administrator', ['ignore_request' => true]); - $messagesModel->setState('filter.state', 0); - $messages = $messagesModel->getItems(); -} catch (RuntimeException $e) { - $messages = []; - - // Still render the error message from the Exception object - $app->enqueueMessage($e->getMessage(), 'error'); -} - -$countUnread = \count($messages); - -require ModuleHelper::getLayoutPath('mod_messages', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_messages/mod_messages.xml b/administrator/modules/mod_messages/mod_messages.xml index 47000f0b61439..397db74c8b11d 100644 --- a/administrator/modules/mod_messages/mod_messages.xml +++ b/administrator/modules/mod_messages/mod_messages.xml @@ -9,8 +9,10 @@ www.joomla.org 4.0.0 MOD_MESSAGES_XML_DESCRIPTION + Joomla\Module\Messages - mod_messages.php + services + src tmpl diff --git a/administrator/modules/mod_messages/services/provider.php b/administrator/modules/mod_messages/services/provider.php new file mode 100644 index 0000000000000..7bae4fd324da9 --- /dev/null +++ b/administrator/modules/mod_messages/services/provider.php @@ -0,0 +1,43 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +use Joomla\CMS\Extension\Service\Provider\HelperFactory; +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * The messages module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Messages')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\Messages\\Administrator\\Helper')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_messages/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_messages/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..03840ffda2e15 --- /dev/null +++ b/administrator/modules/mod_messages/src/Dispatcher/Dispatcher.php @@ -0,0 +1,65 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Messages\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Helper\HelperFactoryAwareInterface; +use Joomla\CMS\Helper\HelperFactoryAwareTrait; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_messages + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface +{ + use HelperFactoryAwareTrait; + + /** + * Runs the dispatcher. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function dispatch() + { + // Check permissions. + if ( + !$this->getApplication()->getIdentity()->authorise('core.login.admin') + || !$this->getApplication()->getIdentity()->authorise('core.manage', 'com_messages') + ) { + return; + } + + parent::dispatch(); + } + + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['countUnread'] = $this->getHelperFactory()->getHelper('MessagesHelper')->getUnreadMessagesCount($data['params'], $this->getApplication()); + + return $data; + } +} diff --git a/administrator/modules/mod_messages/src/Helper/MessagesHelper.php b/administrator/modules/mod_messages/src/Helper/MessagesHelper.php new file mode 100644 index 0000000000000..50086f05beece --- /dev/null +++ b/administrator/modules/mod_messages/src/Helper/MessagesHelper.php @@ -0,0 +1,58 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Messages\Administrator\Helper; + +use Joomla\CMS\Application\AdministratorApplication; +use Joomla\Registry\Registry; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Helper for mod_messages + * + * @since __DEPLOY_VERSION__ + */ +class MessagesHelper +{ + /** + * Get count of unread messages. + * + * @param Registry $params Object holding the module parameters + * @param AdministratorApplication $app The application + * + * @return integer + * + * @since __DEPLOY_VERSION__ + */ + public function getUnreadMessagesCount(Registry $params, AdministratorApplication $app) + { + // Try to get the items from the messages model + try { + /** + * @var \Joomla\Component\Messages\Administrator\Model\MessagesModel $messagesModel + * + */ + $messagesModel = $app->bootComponent('com_messages')->getMVCFactory() + ->createModel('Messages', 'Administrator', ['ignore_request' => true]); + $messagesModel->setState('filter.state', 0); + $messages = $messagesModel->getItems(); + + return \count($messages); + } catch (\RuntimeException $e) { + // Still render the error message from the Exception object + $app->enqueueMessage($e->getMessage(), 'error'); + + return 0; + } + } +} diff --git a/administrator/modules/mod_multilangstatus/mod_multilangstatus.php b/administrator/modules/mod_multilangstatus/mod_multilangstatus.php deleted file mode 100644 index 8193348594647..0000000000000 --- a/administrator/modules/mod_multilangstatus/mod_multilangstatus.php +++ /dev/null @@ -1,20 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Factory; -use Joomla\CMS\Helper\ModuleHelper; -use Joomla\CMS\Language\Multilanguage; -use Joomla\Database\DatabaseInterface; - -$multilanguageEnabled = Multilanguage::isEnabled($app, Factory::getContainer()->get(DatabaseInterface::class)); - -require ModuleHelper::getLayoutPath('mod_multilangstatus', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_multilangstatus/mod_multilangstatus.xml b/administrator/modules/mod_multilangstatus/mod_multilangstatus.xml index c4250ec2cb968..6dfb9815725cd 100644 --- a/administrator/modules/mod_multilangstatus/mod_multilangstatus.xml +++ b/administrator/modules/mod_multilangstatus/mod_multilangstatus.xml @@ -9,8 +9,10 @@ www.joomla.org 3.0.0 MOD_MULTILANGSTATUS_XML_DESCRIPTION + Joomla\Module\MultilangStatus - mod_multilangstatus.php + services + src tmpl diff --git a/administrator/modules/mod_multilangstatus/services/provider.php b/administrator/modules/mod_multilangstatus/services/provider.php new file mode 100644 index 0000000000000..c73ed2fb399ed --- /dev/null +++ b/administrator/modules/mod_multilangstatus/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The multilanguage status module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\MultilangStatus')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_multilangstatus/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_multilangstatus/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..f76a8a1ced0fc --- /dev/null +++ b/administrator/modules/mod_multilangstatus/src/Dispatcher/Dispatcher.php @@ -0,0 +1,44 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\MultilangStatus\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Factory; +use Joomla\CMS\Language\Multilanguage; +use Joomla\Database\DatabaseInterface; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_multilangstatus + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['multilanguageEnabled'] = Multilanguage::isEnabled($this->getApplication(), Factory::getContainer()->get(DatabaseInterface::class)); + + return $data; + } +} diff --git a/administrator/modules/mod_sampledata/mod_sampledata.php b/administrator/modules/mod_sampledata/mod_sampledata.php deleted file mode 100644 index 7f15a7c4a8eec..0000000000000 --- a/administrator/modules/mod_sampledata/mod_sampledata.php +++ /dev/null @@ -1,18 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -$items = \Joomla\Module\Sampledata\Administrator\Helper\SampledataHelper::getList(); - -// Filter out empty entries -$items = array_filter($items); - -require \Joomla\CMS\Helper\ModuleHelper::getLayoutPath('mod_sampledata', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_sampledata/mod_sampledata.xml b/administrator/modules/mod_sampledata/mod_sampledata.xml index d8ce585454148..b057e826c062b 100644 --- a/administrator/modules/mod_sampledata/mod_sampledata.xml +++ b/administrator/modules/mod_sampledata/mod_sampledata.xml @@ -11,7 +11,7 @@ MOD_SAMPLEDATA_XML_DESCRIPTION Joomla\Module\Sampledata - mod_sampledata.php + services src tmpl diff --git a/administrator/modules/mod_sampledata/services/provider.php b/administrator/modules/mod_sampledata/services/provider.php new file mode 100644 index 0000000000000..7b3d51bd387a7 --- /dev/null +++ b/administrator/modules/mod_sampledata/services/provider.php @@ -0,0 +1,41 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\HelperFactory; +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The sample data module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Sampledata')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\Sampledata\\Administrator\\Helper')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_sampledata/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_sampledata/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..ab17fdd0bc7c6 --- /dev/null +++ b/administrator/modules/mod_sampledata/src/Dispatcher/Dispatcher.php @@ -0,0 +1,48 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Sampledata\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Helper\HelperFactoryAwareInterface; +use Joomla\CMS\Helper\HelperFactoryAwareTrait; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_sampledata + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface +{ + use HelperFactoryAwareTrait; + + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $items = $this->getHelperFactory()->getHelper('SampledataHelper')->getSampledataList(); + + // Filter out empty entries + $data['items'] = array_filter($items); + + return $data; + } +} diff --git a/administrator/modules/mod_sampledata/src/Helper/SampledataHelper.php b/administrator/modules/mod_sampledata/src/Helper/SampledataHelper.php index bba9341ff3028..6eb95940751dc 100644 --- a/administrator/modules/mod_sampledata/src/Helper/SampledataHelper.php +++ b/administrator/modules/mod_sampledata/src/Helper/SampledataHelper.php @@ -23,16 +23,16 @@ * * @since 3.8.0 */ -abstract class SampledataHelper +class SampledataHelper { /** * Get a list of sampledata. * * @return mixed An array of sampledata, or false on error. * - * @since 3.8.0 + * @since __DEPLOY_VERSION__ */ - public static function getList() + public function getSampledataList() { PluginHelper::importPlugin('sampledata'); @@ -49,4 +49,22 @@ public static function getList() ) ->getArgument('result') ?? []; } + + /** + * Get a list of sampledata. + * + * @return mixed An array of sampledata, or false on error. + * + * @since 3.8.0 + * + * @deprecated __DEPLOY_VERSION__ will be removed in 6.0 + * Use the non-static method getSampledataList + * Example: Factory::getApplication()->bootModule('mod_sampledata', 'administrator') + * ->getHelper('SampledataHelper') + * ->getSampledataList() + */ + public static function getList() + { + return (new self())->getSampledataList(); + } } diff --git a/administrator/modules/mod_stats_admin/mod_stats_admin.php b/administrator/modules/mod_stats_admin/mod_stats_admin.php deleted file mode 100644 index 6b5e4c1bce172..0000000000000 --- a/administrator/modules/mod_stats_admin/mod_stats_admin.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Factory; -use Joomla\CMS\Helper\ModuleHelper; -use Joomla\Database\DatabaseInterface; -use Joomla\Module\StatsAdmin\Administrator\Helper\StatsAdminHelper; - -$serverinfo = $params->get('serverinfo'); -$siteinfo = $params->get('siteinfo'); -$list = StatsAdminHelper::getStats($params, $app, Factory::getContainer()->get(DatabaseInterface::class)); - -require ModuleHelper::getLayoutPath('mod_stats_admin', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_stats_admin/mod_stats_admin.xml b/administrator/modules/mod_stats_admin/mod_stats_admin.xml index 0dd4195459a82..7dd5411f4bcad 100644 --- a/administrator/modules/mod_stats_admin/mod_stats_admin.xml +++ b/administrator/modules/mod_stats_admin/mod_stats_admin.xml @@ -11,7 +11,7 @@ MOD_STATS_XML_DESCRIPTION Joomla\Module\StatsAdmin - mod_stats_admin.php + services src tmpl diff --git a/administrator/modules/mod_stats_admin/services/provider.php b/administrator/modules/mod_stats_admin/services/provider.php new file mode 100644 index 0000000000000..7f12e3b234f01 --- /dev/null +++ b/administrator/modules/mod_stats_admin/services/provider.php @@ -0,0 +1,41 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\HelperFactory; +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The statistics administrator module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\StatsAdmin')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\StatsAdmin\\Administrator\\Helper')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_stats_admin/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_stats_admin/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..527c469ef2bb7 --- /dev/null +++ b/administrator/modules/mod_stats_admin/src/Dispatcher/Dispatcher.php @@ -0,0 +1,49 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\StatsAdmin\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Factory; +use Joomla\CMS\Helper\HelperFactoryAwareInterface; +use Joomla\CMS\Helper\HelperFactoryAwareTrait; +use Joomla\Database\DatabaseInterface; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_stats_admin + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface +{ + use HelperFactoryAwareTrait; + + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['serverinfo'] = $data['params']->get('serverinfo'); + $data['siteinfo'] = $data['params']->get('siteinfo'); + $data['list'] = $this->getHelperFactory()->getHelper('StatsAdminHelper')->getStatsData($data['params'], $this->getApplication(), Factory::getContainer()->get(DatabaseInterface::class)); + + return $data; + } +} diff --git a/administrator/modules/mod_stats_admin/src/Helper/StatsAdminHelper.php b/administrator/modules/mod_stats_admin/src/Helper/StatsAdminHelper.php index 20399e03d4c18..e8609abe3daf9 100644 --- a/administrator/modules/mod_stats_admin/src/Helper/StatsAdminHelper.php +++ b/administrator/modules/mod_stats_admin/src/Helper/StatsAdminHelper.php @@ -37,9 +37,9 @@ class StatsAdminHelper * * @return array Array containing site information * - * @since 3.0 + * @since __DEPLOY_VERSION__ */ - public static function getStats(Registry $params, CMSApplication $app, DatabaseInterface $db) + public function getStatsData(Registry $params, CMSApplication $app, DatabaseInterface $db) { $user = $app->getIdentity(); @@ -144,4 +144,26 @@ public static function getStats(Registry $params, CMSApplication $app, DatabaseI return $rows; } + + /** + * Method to retrieve information about the site + * + * @param Registry $params The module parameters + * @param CMSApplication $app The application + * @param DatabaseInterface $db The database + * + * @return array Array containing site information + * + * @since 3.0 + * + * @deprecated __DEPLOY_VERSION__ will be removed in 6.0 + * Use the non-static method getStatsData + * Example: Factory::getApplication()->bootModule('mod_stats_admin', 'administrator') + * ->getHelper('StatsAdminHelper') + * ->getStatsData($params, Factory::getApplication(), Factory::getContainer()->get(DatabaseInterface::class)) + */ + public static function getStats(Registry $params, CMSApplication $app, DatabaseInterface $db) + { + return (new self())->getStatsData($params, $app, $db); + } } diff --git a/administrator/modules/mod_title/mod_title.php b/administrator/modules/mod_title/mod_title.php deleted file mode 100644 index 0644615f954f3..0000000000000 --- a/administrator/modules/mod_title/mod_title.php +++ /dev/null @@ -1,20 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; - -// Get the component title div -if (isset($app->JComponentTitle)) { - $title = $app->JComponentTitle; -} - -require ModuleHelper::getLayoutPath('mod_title', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_title/mod_title.xml b/administrator/modules/mod_title/mod_title.xml index 817e4fc7fd95b..28c20598ec4db 100644 --- a/administrator/modules/mod_title/mod_title.xml +++ b/administrator/modules/mod_title/mod_title.xml @@ -9,8 +9,10 @@ www.joomla.org 3.0.0 MOD_TITLE_XML_DESCRIPTION + Joomla\Module\Title - mod_title.php + services + src tmpl diff --git a/administrator/modules/mod_title/services/provider.php b/administrator/modules/mod_title/services/provider.php new file mode 100644 index 0000000000000..4219c6928c481 --- /dev/null +++ b/administrator/modules/mod_title/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The title module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Title')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_title/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_title/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..edd10efcac56d --- /dev/null +++ b/administrator/modules/mod_title/src/Dispatcher/Dispatcher.php @@ -0,0 +1,44 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Title\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_title + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + // Get the component title div + if (isset($this->getApplication()->JComponentTitle)) { + $data['title'] = $this->getApplication()->JComponentTitle; + } + + return $data; + } +} diff --git a/administrator/modules/mod_toolbar/mod_toolbar.php b/administrator/modules/mod_toolbar/mod_toolbar.php deleted file mode 100644 index 31a579d9987ee..0000000000000 --- a/administrator/modules/mod_toolbar/mod_toolbar.php +++ /dev/null @@ -1,20 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Factory; -use Joomla\CMS\Helper\ModuleHelper; - -/** @var $params Joomla\Registry\Registry */ - -$toolbar = Factory::getApplication()->getDocument()->getToolbar($params->get('toolbar', 'toolbar'))->render(); - -require ModuleHelper::getLayoutPath('mod_toolbar', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_toolbar/mod_toolbar.xml b/administrator/modules/mod_toolbar/mod_toolbar.xml index 05ba439b0e4d9..99fbf46026af1 100644 --- a/administrator/modules/mod_toolbar/mod_toolbar.xml +++ b/administrator/modules/mod_toolbar/mod_toolbar.xml @@ -9,8 +9,10 @@ www.joomla.org 3.0.0 MOD_TOOLBAR_XML_DESCRIPTION + Joomla\Module\Toolbar - mod_toolbar.php + services + src tmpl diff --git a/administrator/modules/mod_toolbar/services/provider.php b/administrator/modules/mod_toolbar/services/provider.php new file mode 100644 index 0000000000000..f03fcc55a3f9b --- /dev/null +++ b/administrator/modules/mod_toolbar/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The toolbar module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Toolbar')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_toolbar/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_toolbar/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..0f2908ebcabc0 --- /dev/null +++ b/administrator/modules/mod_toolbar/src/Dispatcher/Dispatcher.php @@ -0,0 +1,41 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Toolbar\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_toolbar + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['toolbar'] = $this->getApplication()->getDocument()->getToolbar($data['params']->get('toolbar', 'toolbar'))->render(); + + return $data; + } +} diff --git a/administrator/modules/mod_user/mod_user.php b/administrator/modules/mod_user/mod_user.php deleted file mode 100644 index a78693f73252a..0000000000000 --- a/administrator/modules/mod_user/mod_user.php +++ /dev/null @@ -1,17 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -use Joomla\CMS\Helper\ModuleHelper; - -$user = $app->getIdentity(); - -require ModuleHelper::getLayoutPath('mod_user', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_user/mod_user.xml b/administrator/modules/mod_user/mod_user.xml index 2ddf26bbadb5d..4c491b040bff3 100644 --- a/administrator/modules/mod_user/mod_user.xml +++ b/administrator/modules/mod_user/mod_user.xml @@ -9,8 +9,10 @@ www.joomla.org 4.0.0 MOD_USER_XML_DESCRIPTION + Joomla\Module\User - mod_user.php + services + src tmpl diff --git a/administrator/modules/mod_user/services/provider.php b/administrator/modules/mod_user/services/provider.php new file mode 100644 index 0000000000000..3c23c7c9228d3 --- /dev/null +++ b/administrator/modules/mod_user/services/provider.php @@ -0,0 +1,39 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The user menu module service provider. + * + * @since __DEPLOY_VERSION__ + */ +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\User')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_user/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_user/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..6ad5e94ad346b --- /dev/null +++ b/administrator/modules/mod_user/src/Dispatcher/Dispatcher.php @@ -0,0 +1,41 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\User\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_user + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher +{ + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['user'] = $this->getApplication()->getIdentity(); + + return $data; + } +} diff --git a/administrator/modules/mod_version/mod_version.php b/administrator/modules/mod_version/mod_version.php deleted file mode 100644 index 44df5077adcb2..0000000000000 --- a/administrator/modules/mod_version/mod_version.php +++ /dev/null @@ -1,15 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -\defined('_JEXEC') or die; - -$version = \Joomla\Module\Version\Administrator\Helper\VersionHelper::getVersion(); - -require \Joomla\CMS\Helper\ModuleHelper::getLayoutPath('mod_version', $params->get('layout', 'default')); diff --git a/administrator/modules/mod_version/mod_version.xml b/administrator/modules/mod_version/mod_version.xml index 027188e8eaa23..7dc92925e3721 100644 --- a/administrator/modules/mod_version/mod_version.xml +++ b/administrator/modules/mod_version/mod_version.xml @@ -11,7 +11,7 @@ MOD_VERSION_XML_DESCRIPTION Joomla\Module\Version - mod_version.php + services src tmpl diff --git a/administrator/modules/mod_version/services/provider.php b/administrator/modules/mod_version/services/provider.php new file mode 100644 index 0000000000000..c2df6be8272ea --- /dev/null +++ b/administrator/modules/mod_version/services/provider.php @@ -0,0 +1,36 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +\defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\HelperFactory; +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +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->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Version')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\Version\\Administrator\\Helper')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/administrator/modules/mod_version/src/Dispatcher/Dispatcher.php b/administrator/modules/mod_version/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..0a214d780c188 --- /dev/null +++ b/administrator/modules/mod_version/src/Dispatcher/Dispatcher.php @@ -0,0 +1,45 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\Version\Administrator\Dispatcher; + +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Helper\HelperFactoryAwareInterface; +use Joomla\CMS\Helper\HelperFactoryAwareTrait; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_version + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface +{ + use HelperFactoryAwareTrait; + + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + $data['version'] = $this->getHelperFactory()->getHelper('VersionHelper')->getVersionString(); + + return $data; + } +} diff --git a/administrator/modules/mod_version/src/Helper/VersionHelper.php b/administrator/modules/mod_version/src/Helper/VersionHelper.php index d74cce3a761f8..7b0e079e72c82 100644 --- a/administrator/modules/mod_version/src/Helper/VersionHelper.php +++ b/administrator/modules/mod_version/src/Helper/VersionHelper.php @@ -21,17 +21,35 @@ * * @since 1.6 */ -abstract class VersionHelper +class VersionHelper { /** * Get the Joomla version number. * * @return string String containing the current Joomla version. + * + * @since __DEPLOY_VERSION__ */ - public static function getVersion() + public function getVersionString() { $version = new Version(); return '‎' . $version->getShortVersion(); } + + /** + * Get the Joomla version number. + * + * @return string String containing the current Joomla version. + * + * @deprecated __DEPLOY_VERSION__ will be removed in 6.0 + * Use the non-static method getVersionString + * Example: Factory::getApplication()->bootModule('mod_version', 'administrator') + * ->getHelper('VersionHelper') + * ->getVersionString() + */ + public static function getVersion() + { + return (new self())->getVersionString(); + } } diff --git a/administrator/templates/atum/error_login.php b/administrator/templates/atum/error_login.php index d0bfcfa118f79..417ff6d9edc34 100644 --- a/administrator/templates/atum/error_login.php +++ b/administrator/templates/atum/error_login.php @@ -124,7 +124,7 @@
    'eager', 'decoding' => 'async'], false, 0); ?>
    -

    +

    error->getCode(); ?> diff --git a/administrator/templates/atum/templateDetails.xml b/administrator/templates/atum/templateDetails.xml index 32ded9d2ed915..41cd585b6e1f3 100644 --- a/administrator/templates/atum/templateDetails.xml +++ b/administrator/templates/atum/templateDetails.xml @@ -118,6 +118,9 @@ input->get('filter', [], 'array'); + $filter = InputFilter::getInstance(); + + if (\array_key_exists('search', $apiFilterInfo)) { + $this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING')); + } + $this->modelState->set('filter.extension', $this->getExtensionFromInput()); return parent::displayList(); diff --git a/api/components/com_content/src/Controller/ArticlesController.php b/api/components/com_content/src/Controller/ArticlesController.php index fd8d1f97a70c7..a5226eb00e390 100644 --- a/api/components/com_content/src/Controller/ArticlesController.php +++ b/api/components/com_content/src/Controller/ArticlesController.php @@ -115,9 +115,11 @@ protected function preprocessSaveData(array $data): array } } - $tags = new TagsHelper(); - $tags->getTagIds($data['id'], 'com_content.article'); - $data['tags'] = explode(',', $tags->tags); + if (($this->input->getMethod() === 'PATCH') && !(\array_key_exists('tags', $data))) { + $tags = new TagsHelper(); + $tags->getTagIds($data['id'], 'com_content.article'); + $data['tags'] = explode(',', $tags->tags); + } return $data; } diff --git a/api/components/com_media/src/Controller/MediaController.php b/api/components/com_media/src/Controller/MediaController.php index b1624960e342e..ed21098dc32bf 100644 --- a/api/components/com_media/src/Controller/MediaController.php +++ b/api/components/com_media/src/Controller/MediaController.php @@ -350,9 +350,9 @@ private function checkContent(): void // Check if the size of the request body does not exceed various server imposed limits. if ( ($params->get('upload_maxsize', 0) > 0 && $serverlength > ($params->get('upload_maxsize', 0) * 1024 * 1024)) - || $serverlength > $helper->toBytes(ini_get('upload_max_filesize')) - || $serverlength > $helper->toBytes(ini_get('post_max_size')) - || $serverlength > $helper->toBytes(ini_get('memory_limit')) + || $serverlength > $helper->toBytes(\ini_get('upload_max_filesize')) + || $serverlength > $helper->toBytes(\ini_get('post_max_size')) + || $serverlength > $helper->toBytes(\ini_get('memory_limit')) ) { throw new \RuntimeException(Text::_('COM_MEDIA_ERROR_WARNFILETOOLARGE'), 400); } diff --git a/api/components/com_tags/src/Controller/TagsController.php b/api/components/com_tags/src/Controller/TagsController.php index 56361738a269f..88afd48196909 100644 --- a/api/components/com_tags/src/Controller/TagsController.php +++ b/api/components/com_tags/src/Controller/TagsController.php @@ -10,6 +10,7 @@ namespace Joomla\Component\Tags\Api\Controller; +use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\MVC\Controller\ApiController; // phpcs:disable PSR1.Files.SideEffects @@ -38,4 +39,23 @@ class TagsController extends ApiController * @since 3.0 */ protected $default_view = 'tags'; + + /** + * Basic display of a list view + * + * @return static A \JControllerLegacy object to support chaining. + * + * @since __DEPLOY_VERSION__ + */ + public function displayList() + { + $apiFilterInfo = $this->input->get('filter', [], 'array'); + $filter = InputFilter::getInstance(); + + if (\array_key_exists('search', $apiFilterInfo)) { + $this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING')); + } + + return parent::displayList(); + } } diff --git a/api/language/en-GB/install.xml b/api/language/en-GB/install.xml index bfd8974dfe32a..f8abbed399ef0 100644 --- a/api/language/en-GB/install.xml +++ b/api/language/en-GB/install.xml @@ -3,7 +3,7 @@ English (en-GB) en-GB 5.1.0 - 2023-12 + 2024-02 Joomla! Project admin@joomla.org www.joomla.org diff --git a/api/language/en-GB/joomla.ini b/api/language/en-GB/joomla.ini index fc0b6dfa82a1f..152a4a8bca4bd 100644 --- a/api/language/en-GB/joomla.ini +++ b/api/language/en-GB/joomla.ini @@ -427,6 +427,8 @@ JGLOBAL_FIELD_MODIFIED_BY_DESC="The user who did the last modification." JGLOBAL_FIELD_MODIFIED_BY_LABEL="Modified By" JGLOBAL_FIELD_MODIFIED_LABEL="Modified Date" JGLOBAL_FIELD_MOVE="Move" +JGLOBAL_FIELD_MOVE_DOWN="Move down" +JGLOBAL_FIELD_MOVE_UP="Move up" JGLOBAL_FIELD_NUM_CATEGORY_ITEMS_DESC="Number of categories to display for each level." JGLOBAL_FIELD_NUM_CATEGORY_ITEMS_LABEL="Number of Categories" JGLOBAL_FIELD_PUBLISH_DOWN_DESC="An optional date to stop publishing." diff --git a/api/language/en-GB/langmetadata.xml b/api/language/en-GB/langmetadata.xml index f4a5cd2594227..2074a4f00f97a 100644 --- a/api/language/en-GB/langmetadata.xml +++ b/api/language/en-GB/langmetadata.xml @@ -2,7 +2,7 @@ English (en-GB) 5.1.0 - 2023-12 + 2024-02 Joomla! Project admin@joomla.org www.joomla.org diff --git a/build/build-modules-js/compress.es6.js b/build/build-modules-js/compress.es6.js index 5a8d7909ba074..e8a2b4c9adf55 100644 --- a/build/build-modules-js/compress.es6.js +++ b/build/build-modules-js/compress.es6.js @@ -1,7 +1,20 @@ -const { getFiles } = require('@dgrammatiko/compress/src/getFiles.js'); -const { compressFile } = require('@dgrammatiko/compress/src/compressFile.js'); +const { readdir } = require('fs').promises; +const { extname } = require('path'); +const { compressFile } = require('./utils/compressFile.es6.js'); const { Timer } = require('./utils/timer.es6.js'); +/** + * Get files recursively + * + * @param {string} path The path + */ +async function getFiles(path) { + // Get files within the current directory + return (await readdir(path, { withFileTypes: true, recursive: true })) + .filter((file) => (!file.isDirectory() && ['.js', '.css'].includes(extname(file.name)))) + .map((file) => `${file.path}/${file.name}`); +} + /** * Method that will pre compress (gzip) all .css/.js files * in the templates and in the media folder @@ -15,11 +28,8 @@ module.exports.compressFiles = async (enableBrotli = false) => { `${process.cwd()}/administrator/templates`, ]; - const tasks = []; const compressTasks = []; - paths.map((path) => tasks.push(getFiles(`${path}/`))); - - const files = await Promise.all(tasks); + const files = await Promise.all(paths.map((path) => getFiles(`${path}`))); [].concat(...files).map((file) => compressTasks.push(compressFile(file, enableBrotli))); await Promise.all(compressTasks); diff --git a/build/build-modules-js/css-versioning.es6.js b/build/build-modules-js/css-versioning.es6.js index 3cf7b9ac4672e..9377ca485fed4 100644 --- a/build/build-modules-js/css-versioning.es6.js +++ b/build/build-modules-js/css-versioning.es6.js @@ -1,30 +1,52 @@ -const { readFile, writeFile } = require('fs/promises'); -const { existsSync, readFileSync } = require('fs'); -const { resolve, dirname } = require('path'); -const crypto = require('crypto'); -const jetpack = require('fs-jetpack'); -const Postcss = require('postcss'); -const UrlVersion = require('postcss-url-version'); +const { createHash } = require('node:crypto'); +const { readdir, readFile, writeFile } = require('fs/promises'); +const { existsSync, readFileSync } = require('node:fs'); +const { dirname, extname, resolve } = require('node:path'); +const { transform, composeVisitors } = require('lightningcss'); const { Timer } = require('./utils/timer.es6.js'); -const opts = { - version: (imagePath, sourceCssPath) => { - if (!sourceCssPath) { - return (new Date()).valueOf().toString(); - } +const skipExternal = true; +const variable = 'v'; - const directory = dirname(sourceCssPath); - if (!(imagePath.startsWith('http') || imagePath.startsWith('//')) && existsSync(resolve(`${directory}/${imagePath}`))) { - const fileBuffer = readFileSync(resolve(`${directory}/${imagePath}`)); - const hashSum = crypto.createHash('md5'); - hashSum.update(fileBuffer); +function version(urlString, fromFile) { + // Skip external URLs + if (skipExternal && (urlString.startsWith('http') || urlString.startsWith('//'))) { + return `${urlString}`; + } + // Skip base64 URLs + if (urlString.startsWith('data:')) { + return `${urlString}`; + } + // Skip URLs with existing query + if (urlString.includes('?')) { + return `${urlString}`; + } - return (hashSum.digest('hex')).substring(0, 6); - } + if (fromFile && existsSync(resolve(`${dirname(fromFile)}/${urlString}`))) { + const hash = createHash('md5'); + hash.update(readFileSync(resolve(`${dirname(fromFile)}/${urlString}`))); - return (new Date()).valueOf().toString(); - }, -}; + return `${urlString}?${variable}=${hash.digest('hex').substring(0, 6)}`; + } + + return `${urlString}?${variable}=${(new Date()).valueOf().toString().substring(0, 6)}`; +} + +/** + * @param {from: String} - the filepath for the css file + * @returns {import('lightningcss').Visitor} - A visitor that replaces the url + */ +function urlVersioning(fromFile) { + return { + /** + * @param {import('lightningcss').Url} url - The url object to transform + * @returns {import('lightningcss').Url} - The transformed url object + */ + Url(url) { + return { ...url, ...{ url: version(url.url, fromFile) } }; + }, + }; +} /** * Adds a hash to the url() parts of the static css @@ -34,9 +56,13 @@ const opts = { */ const fixVersion = async (file) => { try { - const cssString = await readFile(file, { encoding: 'utf8' }); - const data = await Postcss([UrlVersion(opts)]).process(cssString, { from: file }); - await writeFile(file, data.css, { encoding: 'utf8', mode: 0o644 }); + const cssString = await readFile(file); + const { code } = transform({ + code: cssString, + minify: false, + visitor: composeVisitors([urlVersioning(file)]), + }); + await writeFile(file, code, { encoding: 'utf8', mode: 0o644 }); } catch (error) { throw new Error(error); } @@ -50,8 +76,10 @@ const fixVersion = async (file) => { module.exports.cssVersioning = async () => { const bench = new Timer('Versioning'); - const cssFiles = jetpack.find('media', { matching: '/**/**/*.css' }); - await Promise.all(cssFiles.map((file) => fixVersion(file))); + const cssFiles = (await readdir('media', { withFileTypes: true, recursive: true })) + .filter((file) => (!file.isDirectory() && extname(file.name) === '.css')) + .map((file) => `${file.path}/${file.name}`); - bench.stop(); + Promise.all(cssFiles.map((file) => fixVersion(file))) + .then(() => bench.stop()); }; diff --git a/build/build-modules-js/javascript/compile-to-es2017.es6.js b/build/build-modules-js/javascript/compile-to-es2017.es6.js index 9dd93b4e0863c..84386773f3cde 100644 --- a/build/build-modules-js/javascript/compile-to-es2017.es6.js +++ b/build/build-modules-js/javascript/compile-to-es2017.es6.js @@ -53,13 +53,15 @@ const collectExternals = () => { return; } - // Joomla modules + // Joomla and Vendor modules externalModules.push( 'cropper-module', 'codemirror', 'joomla.dialog', 'editor-api', 'editor-decorator', + 'sa11y', + 'sa11y-lang', ); // Codemirror modules diff --git a/build/build-modules-js/settings.json b/build/build-modules-js/settings.json index c9f7a04454e99..a655a2e7804e2 100644 --- a/build/build-modules-js/settings.json +++ b/build/build-modules-js/settings.json @@ -403,7 +403,7 @@ "hotkeys-js": { "name": "hotkeysjs", "licenseFilename": "LICENSE", - "js" : { + "js": { "dist/hotkeys.js": "js/hotkeys.js", "dist/hotkeys.min.js": "js/hotkeys.min.js" }, @@ -458,10 +458,6 @@ ], "licenseFilename": "LICENSE.txt" }, - "@joomla/joomla-a11y-checker": { - "name": "joomla-a11y-checker", - "licenseFilename": "LICENSE.md" - }, "joomla-ui-custom-elements": { "name": "joomla-custom-elements", "js": { @@ -745,6 +741,66 @@ } ] }, + "sa11y": { + "name": "sa11y", + "licenseFilename": "LICENSE.md", + "js": { + "dist/js/sa11y.esm.min.js": "js/sa11y.esm.min.js", + "dist/js/lang/bg.js": "js/bg.js", + "dist/js/lang/cs.js": "js/cs.js", + "dist/js/lang/da.js": "js/da.js", + "dist/js/lang/de.js": "js/de.js", + "dist/js/lang/el.js": "js/el.js", + "dist/js/lang/en.js": "js/en.js", + "dist/js/lang/enUS.js": "js/enUS.js", + "dist/js/lang/es.js": "js/es.js", + "dist/js/lang/et.js": "js/et.js", + "dist/js/lang/fi.js": "js/fi.js", + "dist/js/lang/fr.js": "js/fr.js", + "dist/js/lang/hu.js": "js/hu.js", + "dist/js/lang/id.js": "js/id.js", + "dist/js/lang/it.js": "js/it.js", + "dist/js/lang/ja.js": "js/ja.js", + "dist/js/lang/ko.js": "js/ko.js", + "dist/js/lang/lt.js": "js/lt.js", + "dist/js/lang/lv.js": "js/lv.js", + "dist/js/lang/nb.js": "js/nb.js", + "dist/js/lang/nl.js": "js/nl.js", + "dist/js/lang/pl.js": "js/pl.js", + "dist/js/lang/ptBR.js": "js/ptBR.js", + "dist/js/lang/ptPT.js": "js/ptPT.js", + "dist/js/lang/ro.js": "js/ro.js", + "dist/js/lang/sk.js": "js/sk.js", + "dist/js/lang/sl.js": "js/sl.js", + "dist/js/lang/sv.js": "js/sv.js", + "dist/js/lang/tr.js": "js/tr.js", + "dist/js/lang/ua.js": "js/ua.js", + "dist/js/lang/zh.js": "js/zh.js" + }, + "css": { + "dist/css/sa11y.min.css": "css/sa11y.min.css" + }, + "provideAssets": [ + { + "name": "sa11y", + "type": "script", + "uri": "sa11y.esm.min.js", + "importmap": true + }, + { + "name": "sa11y-lang", + "type": "script", + "uri": "en.js", + "importmap": true, + "description": "A placeholder asset which is later initialised by plugin, depending on active language." + }, + { + "name": "sa11y", + "type": "style", + "uri": "sa11y.min.css" + } + ] + }, "qrcode-generator": { "name": "qrcode", "js": { @@ -793,7 +849,9 @@ "text": "It looks like you are trying to run Joomla! from our git repository. To do so requires you complete a couple of extra steps first.", "link": "J4.x:Setting_Up_Your_Local_Environment", "linkText": "More Details", - "destFile": ["/templates/system/build_incomplete.html"] + "destFile": [ + "/templates/system/build_incomplete.html" + ] }, "unsupported": { "title": "Joomla: unsupported PHP version", @@ -801,7 +859,10 @@ "text": "Your host needs to use PHP version {{phpversion}} or newer to run this version of Joomla!", "link": "J4.x:Unsupported_PHP_Version", "linkText": "Help me resolve this", - "destFile": ["/templates/system/incompatible.html", "/includes/incompatible.html"] + "destFile": [ + "/templates/system/incompatible.html", + "/includes/incompatible.html" + ] }, "noxml": { "title": "Joomla: Missing PHP-XML library", @@ -809,7 +870,9 @@ "text": "Your host needs to use PHP with support for the XML library to run this version of Joomla!", "link": "J4.x:Missing_XML_Library", "linkText": "Help me resolve this", - "destFile": ["/media/system/html/noxml.html"] + "destFile": [ + "/media/system/html/noxml.html" + ] }, "fatal": { "title": "An Error Occurred: {{statusText}}", @@ -817,8 +880,10 @@ "text": "The server returned a \"{{statusCode_statusText}}\"", "link": "J4.x:FatalError", "linkText": "Help me resolve this", - "destFile": ["/templates/system/fatal-error.html"] + "destFile": [ + "/templates/system/fatal-error.html" + ] } } } -} +} \ No newline at end of file diff --git a/build/build-modules-js/utils/compressFile.es6.js b/build/build-modules-js/utils/compressFile.es6.js new file mode 100644 index 0000000000000..8373729eebd95 --- /dev/null +++ b/build/build-modules-js/utils/compressFile.es6.js @@ -0,0 +1,39 @@ +const { readFile, writeFile } = require('fs').promises; +const { promisify } = require('util'); +const { constants, gzip, brotliCompress } = require('zlib'); + +const gzipOpts = { + level: constants.Z_BEST_COMPRESSION, +}; + +const brotliOpts = { + params: { + [constants.BROTLI_PARAM_MODE]: constants.BROTLI_MODE_TEXT, + [constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY, + }, +}; + +const gzipPromise = promisify(gzip); +const gzipEncode = (data) => gzipPromise(data, gzipOpts); + +const brotliPromise = promisify(brotliCompress); +const brotliEncode = (data) => brotliPromise(data, brotliOpts); + +const compressFile = async (file, enableBrotli) => { + if (file.endsWith('.min.js') || file.endsWith('.min.css')) { + try { + const data = await readFile(file); + await writeFile(`${file}.gz`, await gzipEncode(data)); + if (enableBrotli) { + await writeFile(`${file}.br`, await brotliEncode(data)); + } + // eslint-disable-next-line no-console + console.log(file); + } catch (err) { + // eslint-disable-next-line no-console + console.info(`Error on ${file}: ${err.code}`); + } + } +}; + +module.exports.compressFile = compressFile; diff --git a/build/build.php b/build/build.php index 10b6a21b45fc3..262df44faeec1 100644 --- a/build/build.php +++ b/build/build.php @@ -232,7 +232,7 @@ function clean_composer(string $dir) $fullpath = $tmp . '/' . $time; // Parse input options -$options = getopt('', ['help', 'remote::', 'exclude-zip', 'exclude-gzip', 'exclude-bzip2', 'include-zstd', 'disable-patch-packages']); +$options = getopt('', ['help', 'remote::', 'exclude-zip', 'exclude-gzip', 'include-bzip2', 'exclude-zstd', 'disable-patch-packages']); $remote = $options['remote'] ?? false; $excludeZip = isset($options['exclude-zip']); @@ -512,14 +512,14 @@ function clean_composer(string $dir) break; - // Deleted files case 'D': + // Deleted files $deletedFiles[] = $fileName; break; - // Regular additions and modifications default: + // Regular additions and modifications $filesArray[$fileName] = true; break; @@ -671,21 +671,26 @@ function clean_composer(string $dir) } } - echo "Generating checksums.txt file\n"; + echo "Generating checksums files\n"; - $checksumsContent = ''; + $checksumsContent = ''; + $checksumsContentUpdate = ''; foreach ($checksums as $packageName => $packageHashes) { $checksumsContent .= "Filename: $packageName\n"; foreach ($packageHashes as $hashType => $hash) { $checksumsContent .= "$hashType: $hash\n"; + if (strpos($packageName, 'Update_Package.zip') !== false) { + $checksumsContentUpdate .= "<$hashType>$hash\n"; + } } $checksumsContent .= "\n"; } file_put_contents('checksums.txt', $checksumsContent); + file_put_contents('checksums_update.txt', $checksumsContentUpdate); echo "Generating github_release.txt file\n"; diff --git a/build/media_source/com_associations/joomla.asset.json b/build/media_source/com_associations/joomla.asset.json index bbf3b05d877c7..d680ad66c8985 100644 --- a/build/media_source/com_associations/joomla.asset.json +++ b/build/media_source/com_associations/joomla.asset.json @@ -49,11 +49,10 @@ "type": "script", "uri": "com_associations/sidebyside.min.js", "dependencies": [ - "core", - "jquery" + "core" ], "attributes": { - "defer": true + "type": "module" } }, { diff --git a/build/media_source/com_associations/js/sidebyside.es5.js b/build/media_source/com_associations/js/sidebyside.es5.js deleted file mode 100644 index b6ceb1dc2e427..0000000000000 --- a/build/media_source/com_associations/js/sidebyside.es5.js +++ /dev/null @@ -1,304 +0,0 @@ -/** - * @copyright (C) 2017 Open Source Matters, Inc. - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ -// @TODO remove jQuery dependency -jQuery(document).ready(function($) { - $('#toolbar-target').hide(); - $('#toolbar-copy').hide(); - - // Save button actions, replacing the default Joomla.submitbutton() with custom function. - Joomla.submitbutton = function(task) { - // Using close button, normal joomla submit. - if (task === 'association.cancel') { - Joomla.submitform(task); - } else if(task === 'copy') { - document.body.appendChild(document.createElement('joomla-core-loader')); - - var targetLang = document.getElementById('target-association').getAttribute('data-language'), - referlangInput = window.frames['reference-association'].document.getElementById('jform_language'); - - // Set target language, to get correct content language in the copy - referlangInput.removeAttribute('disabled'); - referlangInput.value = targetLang; - - window.frames['reference-association'].Joomla.submitbutton(document.getElementById('adminForm').getAttribute('data-associatedview') + '.save2copy'); - } else if (task === 'undo-association') { // Undo association - var reference = document.getElementById('reference-association'); - var target = document.getElementById('target-association'); - var referenceId = reference.getAttribute('data-id'); - var referenceLang = reference.getAttribute('data-language').replace(/-/,'_'); - var targetId = target.getAttribute('data-id'); - var targetLang = target.getAttribute('data-language').replace(/-/,'_'); - reference = $(reference).contents(); - target = $(target).contents(); - - // Remove it on the reference - // - For modal association selectors. - reference.find('#jform_associations_' + targetLang + '_id').val(''); - reference.find('#jform_associations_' + targetLang + '_name').val(''); - - // - For chosen association selectors (menus). - reference.find('#jform_associations_' + targetLang).val(''); - - var lang = ''; - - // Remove it on the target - $('#jform_itemlanguage option').each(function() - { - lang = $(this).val().split(':')[0]; - - if (lang) { - lang = lang.replace(/-/,'_'); - - // - For modal association selectors. - target.find('#jform_associations_' + lang + '_id').val(''); - // - For chosen association selectors (menus). - target.find('#jform_associations_' + lang).val(''); - } - }); - - // Same as above but reference language is not in the selector - // - For modal association selectors. - target.find('#jform_associations_' + referenceLang + '_id').val(''); - target.find('#jform_associations_' + referenceLang + '_name').val(''); - - // - For chosen association selectors (menus). - target.find('#jform_associations_' + referenceLang).val(''); - - // Reset switcher after removing association - var currentLangSelect = $('#jform_itemlanguage'); - var currentSwitcher = currentLangSelect.val(); - var currentLang = targetLang.replace(/_/,'-'); - $('#jform_itemlanguage option[value=\"' + currentSwitcher + '\"]').val(currentLang + ':0:add'); - currentLangSelect.val(''); - currentLangSelect[0].dispatchEvent(new CustomEvent('change', { - bubbles: true, - cancelable: true, - })); - - // Save one of the items to confirm action - Joomla.submitbutton('reference'); - } else { - // Saving target or reference, send the save action to the target/reference iframe. - // We need to re-enable the language field to save. - $('#' + task + '-association').contents().find('#jform_language').attr('disabled', false); - window.frames[task + '-association'].Joomla.submitbutton(document.getElementById('adminForm').getAttribute('data-associatedview') + '.apply'); - } - - return false; - }; - - // Attach behaviour to toggle button. - $(document).on('click', '#toggle-left-panel', function() { - var referenceHide = this.getAttribute('data-hide-reference'); - var referenceShow = this.getAttribute('data-show-reference'); - - if ($(this).text() === referenceHide) { - $(this).text(referenceShow); - } else { - $(this).text(referenceHide); - } - - $('#left-panel').toggle(); - $('#right-panel').toggleClass('full-width'); - }); - - // Attach behaviour to language selector change event. - $(document).on('change', '#jform_itemlanguage', function() { - var target = document.getElementById('target-association'); - var selected = $(this).val(); - - // Populate the data attributes and load the the edit page in target frame. - if (selected !== '' && typeof selected !== 'undefined') { - target.setAttribute('data-action', selected.split(':')[2]); - target.setAttribute('data-id', selected.split(':')[1]); - target.setAttribute('data-language', selected.split(':')[0]); - - // Iframe load start, show Joomla loading layer. - document.body.appendChild(document.createElement('joomla-core-loader')); - - // Load the target frame. - target.src = target.getAttribute('data-editurl') + '&task=' + target.getAttribute('data-item') + '.' + target.getAttribute('data-action') + '&id=' + target.getAttribute('data-id'); - } else { - // Reset the data attributes and no item to load. - $('#toolbar-target').hide(); - $('#toolbar-copy').hide(); - $('#select-change').addClass("hidden"); - $('#remove-assoc').addClass("hidden"); - - target.setAttribute('data-action', ''); - target.setAttribute('data-id', '0'); - target.setAttribute('data-language', ''); - target.src = ''; - } - }); - - // Attach behaviour to reference frame load event. - $('#reference-association').on('load', function() { - // Waiting until the reference has loaded before loading the target to avoid race conditions - var targetURL = Joomla.getOptions('targetSrc', false); - - if (targetURL) - { - targetURL = targetURL.split('&').join('&'); - document.getElementById('target-association').setAttribute('src', targetURL); - Joomla.loadOptions({'targetSrc': false}); - return; - } - - // Load Target Pane AFTER reference pane has loaded to prevent session conflict with checkout - document.getElementById('target-association').setAttribute('src', document.getElementById('target-association').getAttribute('src')); - - // If copy button used - if ($(this).contents().find('#jform_id').val() !== this.getAttribute('data-id')) { - var target = document.getElementById('target-association'); - target.src = target.getAttribute('data-editurl') + '&task=' + target.getAttribute('data-item') + '.edit' + '&id=' + $(this).contents().find('#jform_id').val(); - this.src = this.getAttribute('data-editurl') + '&task=' + this.getAttribute('data-item') + '.edit' + '&id=' + this.getAttribute('data-id'); - } - - var reference = $(this).contents(); - - // Disable language field. - reference.find('#jform_language').attr('disabled', ''); - - // Remove modal buttons on the reference - reference.find('#associations').find('.btn').remove(); - - var parse = ''; - - $('#jform_itemlanguage option').each(function() { - parse = $(this).val().split(':'); - - if (typeof parse[0] !== 'undefined') { - // - For modal association selectors. - var langAssociation = parse[0].replace(/-/,'_'); - - if (reference.find('#jform_associations_' + langAssociation + '_id').val() == '') { - reference.find('#jform_associations_' + langAssociation + '_name') - .val(document.getElementById('reference-association').getAttribute('data-no-assoc')); - } - } - }); - - // Iframe load finished, hide Joomla loading layer. - var spinner = document.querySelector('joomla-core-loader'); - if (spinner) { - spinner.parentNode.removeChild(spinner); - } - }); - - // Attach behaviour to target frame load event. - $('#target-association').on('load', function() { - // We need to check if we are not loading a blank iframe. - if (this.getAttribute('src') != '') { - $('#toolbar-target').show(); - $('#toolbar-copy').show(); - $('#select-change').removeClass("hidden"); - - var targetLanguage = this.getAttribute('data-language'); - var targetId = this.getAttribute('data-id'); - var targetLoadedId = $(this).contents().find('#jform_id').val() || '0'; - - // Remove modal buttons on the target - $(this).contents().find('a[href=\"#associations\"]').parent().find('.btn').remove(); - $(this).contents().find('#associations').find('.btn').remove(); - - // Always show General tab first if associations tab is selected on the reference - if ($(this).contents().find('#associations').hasClass('active')) { - $(this).contents().find('a[href=\"#associations\"]').parent().removeClass('active'); - $(this).contents().find('#associations').removeClass('active'); - - $(this).contents().find('.nav-tabs').find('li').first().addClass('active'); - $(this).contents().find('.tab-content').find('.tab-pane').first().addClass('active'); - } - - // Update language field with the selected language and them disable it. - $(this).contents().find('#jform_language').val(targetLanguage).attr('disabled', ''); - - // If we are creating a new association (before save) we need to add the new association. - if (targetLoadedId == '0') - { - document.getElementById('select-change-text').innerHTML = Joomla.sanitizeHtml(document.getElementById('select-change').getAttribute('data-select')); - } - // If we are editing an association. - else - { - // Show change language button - document.getElementById('select-change-text').innerHTML = Joomla.sanitizeHtml(document.getElementById('select-change').getAttribute('data-change')); - $('#remove-assoc').removeClass("hidden"); - $('#toolbar-copy').hide(); - - // Add the id to list of items to check in on close. - var currentIdList = document.getElementById('target-id').value; - var updatedList = currentIdList == '' ? targetLoadedId : currentIdList + ',' + targetLoadedId; - document.getElementById('target-id').value = updatedList; - - // If we created a new association (after save). - if (targetLoadedId != targetId) { - // Refresh the language selector with the new id (used after save). - $('#jform_itemlanguage option[value^=\"' + targetLanguage + ':' + targetId + ':add\"]').val(targetLanguage + ':' + targetLoadedId + ':edit'); - - // Update main frame data-id attribute (used after save). - this.setAttribute('data-id', targetLoadedId); - this.setAttribute('data-action', 'edit'); - } - - // Update the reference item associations tab. - var reference = document.getElementById('reference-association'); - var languageCode = targetLanguage.replace(/-/, '_'); - var referenceTitle = reference.getAttribute('data-title'); - var title = $(this).contents().find('#jform_' + referenceTitle).val(); - - // - For modal association selectors. - $(reference).contents().find('#jform_associations_' + languageCode + '_id').val(targetLoadedId); - $(reference).contents().find('#jform_associations_' + languageCode + '_name').val(title); - - // - For chosen association selectors (menus). - $(reference).contents().find('#jform_associations_' + languageCode).append(''); - $(reference).contents().find('#jform_associations_' + languageCode).val(targetLoadedId); - } - - // Update the target item associations tab. - var reference = document.getElementById('reference-association'); - var referenceId = reference.getAttribute('data-id'); - var languageCode = reference.getAttribute('data-language').replace(/-/, '_'); - var target = document.getElementById('target-association'); - var targetTitle = target.getAttribute('data-title'); - var title = reference.getAttribute('data-title-value'); - var target = $(this).contents(); - - // - For modal association selectors. - target.find('#jform_associations_' + languageCode + '_id').val(referenceId); - target.find('#jform_associations_' + languageCode + '_name').val(title); - - // - For chosen association selectors (menus). - var chosenField = target.find('#jform_associations_' + languageCode); - chosenField.append(''); - chosenField.val(referenceId); - - var parse, langAssociation; - - $('#jform_itemlanguage option').each(function() { - parse = $(this).val().split(':'); - - if (typeof parse[1] !== 'undefined' && parse[1] !== '0') { - // - For modal association selectors. - langAssociation = parse[0].replace(/-/,'_'); - target.find('#jform_associations_' + langAssociation + '_id').val(parse[1]); - - // - For chosen association selectors (menus). - chosenField = target.find('#jform_associations_' + langAssociation); - chosenField.append(''); - chosenField.val(parse[1]); - } - }); - - // Iframe load finished, hide Joomla loading layer. - var spinner = document.querySelector('joomla-core-loader'); - if (spinner) { - spinner.parentNode.removeChild(spinner); - } - } - }); -}); diff --git a/build/media_source/com_associations/js/sidebyside.es6.js b/build/media_source/com_associations/js/sidebyside.es6.js new file mode 100644 index 0000000000000..b1fa689199e7a --- /dev/null +++ b/build/media_source/com_associations/js/sidebyside.es6.js @@ -0,0 +1,349 @@ +/** + * @copyright (C) 2017 Open Source Matters, Inc. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +if (!Joomla) { + throw new Error('Joomla API is not properly initialised'); +} + +const hideElements = (ids) => { + ids.forEach((id) => { + const element = document.getElementById(id); + if (element) { + element.classList.add('hidden'); + } + }); +}; + +const createOption = (value, text) => { + const option = document.createElement('option'); + option.value = value; + option.innerText = text; + return option; +}; + +// Attach behaviour to toggle button. +document.body.addEventListener('click', ({ target }) => { + if (target.id === 'toggle-left-panel') { + const referenceHide = target.getAttribute('data-hide-reference'); + const referenceShow = target.getAttribute('data-show-reference'); + + if (target.innerText === referenceHide) { + target.innerText = referenceShow; + } else { + target.innerText = referenceHide; + } + + document.getElementById('left-panel').classList.toggle('hidden'); + document.getElementById('right-panel').classList.toggle('full-width'); + } +}); + +// Attach behaviour to language selector change event. +document.body.addEventListener('change', ({ target }) => { + if (target.id === 'jform_itemlanguage') { + const targetIframe = document.getElementById('target-association'); + const selected = target.value; + + // Populate the data attributes and load the the edit page in target frame. + if (selected !== '' && typeof selected !== 'undefined') { + targetIframe.setAttribute('data-action', selected.split(':')[2]); + targetIframe.setAttribute('data-id', selected.split(':')[1]); + targetIframe.setAttribute('data-language', selected.split(':')[0]); + + // Iframe load start, show Joomla loading layer. + document.body.appendChild(document.createElement('joomla-core-loader')); + + // Load the target frame. + targetIframe.src = `${targetIframe.getAttribute('data-editurl')}&task=${targetIframe.getAttribute('data-item')}.${targetIframe.getAttribute('data-action')}&id=${targetIframe.getAttribute('data-id')}`; + } else { + // Reset the data attributes and no item to load. + hideElements(['toolbar-target', 'toolbar-copy', 'select-change', 'remove-assoc']); + + targetIframe.setAttribute('data-action', ''); + targetIframe.setAttribute('data-id', '0'); + targetIframe.setAttribute('data-language', ''); + targetIframe.src = ''; + } + } +}); + +// Attach behaviour to reference frame load event. +document.getElementById('reference-association').addEventListener('load', ({ target }) => { + // Waiting until the reference has loaded before loading the target to avoid race conditions + let targetURL = Joomla.getOptions('targetSrc', false); + + if (targetURL) { + targetURL = targetURL.split('&').join('&'); + document.getElementById('target-association').setAttribute('src', targetURL); + Joomla.loadOptions({ targetSrc: false }); + return; + } + + // Load Target Pane AFTER reference pane has loaded to prevent session conflict with checkout + document.getElementById('target-association').setAttribute('src', document.getElementById('target-association').getAttribute('src')); + + const content = target.contentDocument.body || target.contentWindow.document.body; + + // If copy button used + if (content.querySelector('#jform_id').value !== target.getAttribute('data-id')) { + const targetAssociation = document.getElementById('target-association'); + targetAssociation.src = `${targetAssociation.getAttribute('data-editurl')}&task=${targetAssociation.getAttribute('data-item')}.edit&id=${content.querySelector('#jform_id').value}`; + target.src = `${target.getAttribute('data-editurl')}&task=${target.getAttribute('data-item')}.edit&id=${target.getAttribute('data-id')}`; + } + + // Disable language field. + content.querySelector('#jform_language').setAttribute('disabled', 'disabled'); + + // Remove modal buttons on the reference + content.querySelector('#associations .btn').remove(); + + document.querySelectorAll('#jform_itemlanguage option').forEach((option) => { + const parse = option.value.split(':'); + + if (typeof parse[0] !== 'undefined') { + // - For modal association selectors. + const langAssociation = parse[0].replace(/-/, '_'); + + const langAssociationId = content.querySelector(`#jform_associations_${langAssociation}_id`); + if (langAssociationId && langAssociationId.value === '') { + const referenceAssociation = document.getElementById('reference-association'); + if (referenceAssociation.hasAttribute('data-no-assoc')) { + content.querySelector(`#jform_associations_${langAssociation}_name`).value = referenceAssociation.getAttribute('data-no-assoc'); + } + } + } + }); + + // Iframe load finished, hide Joomla loading layer. + const spinner = document.querySelector('joomla-core-loader'); + if (spinner) { + spinner.parentNode.removeChild(spinner); + } +}); + +// Attach behaviour to target frame load event. +document.getElementById('target-association').addEventListener('load', ({ target }) => { + // We need to check if we are not loading a blank iframe. + if (target.getAttribute('src') !== '') { + document.getElementById('toolbar-target').classList.remove('hidden'); + document.getElementById('toolbar-copy').classList.remove('hidden'); + document.getElementById('select-change').classList.remove('hidden'); + + const targetLanguage = target.getAttribute('data-language'); + const targetId = target.getAttribute('data-id'); + const content = target.contentDocument.body || target.contentWindow.document.body; + const targetLoadedId = content.querySelector('#jform_id').value || '0'; + + const reference = document.getElementById('reference-association'); + + // Remove modal buttons on the target + // content.querySelector('a[href="#associations"]').parentNode.querySelector('.btn').forEach(btn => btn.remove()); + // content.querySelector('#associations .btn').forEach(btn => btn.remove()); + + // Always show General tab first if associations tab is selected on the reference + if (content.querySelector('#associations').classList.contains('active')) { + content.querySelector('a[href="#associations"]').parentNode.classList.remove('active'); + content.querySelector('#associations').classList.remove('active'); + + content.querySelector('.nav-tabs li').classList.add('active'); + content.querySelector('.tab-content .tab-pane').classList.add('active'); + } + + // Update language field with the selected language and them disable it. + content.querySelector('#jform_language').value = targetLanguage; + content.querySelector('#jform_language').setAttribute('disabled', 'disabled'); + + // If we are creating a new association (before save) we need to add the new association. + if (targetLoadedId === '0') { + document.getElementById('select-change-text').innerHTML = Joomla.sanitizeHtml(document.getElementById('select-change').getAttribute('data-select')); + } else { + // If we are editing an association. + + // Show change language button + document.getElementById('select-change-text').innerHTML = Joomla.sanitizeHtml(document.getElementById('select-change').getAttribute('data-change')); + document.getElementById('remove-assoc').classList.remove('hidden'); + document.getElementById('remove-assoc').classList.add('toolbar-copy'); + + // Add the id to list of items to check in on close. + const currentIdList = document.getElementById('target-id').value; + const updatedList = currentIdList === '' ? targetLoadedId : `${currentIdList},${targetLoadedId}`; + document.getElementById('target-id').value = updatedList; + + // If we created a new association (after save). + if (targetLoadedId !== targetId) { + // Refresh the language selector with the new id (used after save). + document.querySelector(`#jform_itemlanguage option[value^="${targetLanguage}:${targetId}:add"]`).value = `${targetLanguage}:${targetLoadedId}:edit`; + + // Update main frame data-id attribute (used after save). + target.setAttribute('data-id', targetLoadedId); + target.setAttribute('data-action', 'edit'); + } + + // Update the reference item associations tab. + const referenceContent = reference.contentDocument.body || reference.contentWindow.document.body; + const languageCode = targetLanguage.replace(/-/, '_'); + const title = content.querySelector(`#jform_${reference.getAttribute('data-title')}`).value; + + // - For modal association selectors. + const referenceContentId = referenceContent.querySelector(`#jform_associations_${languageCode}_id`); + if (referenceContentId) { + referenceContentId.value = targetLoadedId; + } + const referenceContentName = referenceContent.querySelector(`#jform_associations_${languageCode}_name`); + if (referenceContentName) { + referenceContentName.value = title; + } + + // - For chosen association selectors (menus). + const referenceContentDropdown = referenceContent.querySelector(`#jform_associations_${languageCode}`); + if (referenceContentDropdown) { + referenceContentDropdown.appendChild(createOption(targetLoadedId, title)); + referenceContentDropdown.value = targetLoadedId; + } + } + + // Update the target item associations tab. + const referenceId = reference.getAttribute('data-id'); + const referenceLanguageCode = reference.getAttribute('data-language').replace(/-/, '_'); + const referenceTitle = reference.getAttribute('data-title-value'); + + // - For modal association selectors. + const targetContentId = content.querySelector(`#jform_associations_${referenceLanguageCode}_id`); + if (targetContentId) { + targetContentId.value = referenceId; + } + const targetContentName = content.querySelector(`#jform_associations_${referenceLanguageCode}_name`); + if (targetContentName) { + targetContentName.value = referenceTitle; + } + + // - For chosen association selectors (menus). + let chosenField = content.querySelector(`#jform_associations_${referenceLanguageCode}`); + chosenField.appendChild(createOption(referenceId, referenceTitle)); + chosenField.value = referenceId; + + document.querySelectorAll('#jform_itemlanguage option').forEach((option) => { + const parse = option.value.split(':'); + + if (typeof parse[1] !== 'undefined' && parse[1] !== '0') { + // - For modal association selectors. + const langAssociation = parse[0].replace(/-/, '_'); + // eslint-disable-next-line prefer-destructuring + content.querySelector(`#jform_associations_${langAssociation}_id`).value = parse[1]; + + // - For chosen association selectors (menus). + chosenField = content.querySelector(`#jform_associations_${langAssociation}`); + chosenField.appendChild(createOption(parse[1], '')); + // eslint-disable-next-line prefer-destructuring + chosenField.value = parse[1]; + } + }); + + // Iframe load finished, hide Joomla loading layer. + const spinner = document.querySelector('joomla-core-loader'); + if (spinner) { + spinner.parentNode.removeChild(spinner); + } + } +}); + +// Save button actions, replacing the default Joomla.submitbutton() with custom function. +Joomla.submitbutton = (task) => { + // Using close button, normal joomla submit. + if (task === 'association.cancel') { + Joomla.submitform(task); + } else if (task === 'copy') { + document.body.appendChild(document.createElement('joomla-core-loader')); + + const targetLang = document.getElementById('target-association').getAttribute('data-language'); + const referlangInput = window.frames['reference-association'].document.getElementById('jform_language'); + + // Set target language, to get correct content language in the copy + referlangInput.removeAttribute('disabled'); + referlangInput.value = targetLang; + + window.frames['reference-association'].Joomla.submitbutton(`${document.getElementById('adminForm').getAttribute('data-associatedview')}.save2copy`); + } else if (task === 'undo-association') { // Undo association + const referenceEl = document.getElementById('reference-association'); + const targetEl = document.getElementById('target-association'); + const referenceLang = referenceEl.getAttribute('data-language').replace(/-/, '_'); + const targetLang = targetEl.getAttribute('data-language').replace(/-/, '_'); + const reference = referenceEl.contentDocument.body || referenceEl.contentWindow.document.body; + const target = targetEl.contentDocument.body || targetEl.contentWindow.document.body; + + // Remove it on the reference + // - For modal association selectors. + const referenceAssocId = reference.querySelector(`#jform_associations_${targetLang}_id`); + if (referenceAssocId) { + referenceAssocId.value = ''; + } + const referenceAssocName = reference.querySelector(`#jform_associations_${targetLang}_name`); + if (referenceAssocName) { + referenceAssocName.value = ''; + } + + // - For chosen association selectors (menus). + const referenceAssoc = reference.querySelector(`#jform_associations_${targetLang}`); + if (referenceAssoc) { + referenceAssoc.value = ''; + } + + // Remove it on the target + document.querySelectorAll('#jform_itemlanguage option').forEach((option) => { + let lang = option.value.split(':')[0]; + + if (lang) { + lang = lang.replace(/-/, '_'); + + // - For modal association selectors. + target.querySelector(`#jform_associations_${lang}_id`).value = ''; + // - For chosen association selectors (menus). + target.querySelector(`#jform_associations_${lang}`).value = ''; + } + }); + + // Same as above but reference language is not in the selector + // - For modal association selectors. + const targetAssocId = target.querySelector(`#jform_associations_${referenceLang}_id`); + if (targetAssocId) { + targetAssocId.value = ''; + } + const targetAssocName = target.querySelector(`#jform_associations_${referenceLang}_name`); + if (targetAssocName) { + targetAssocName.value = ''; + } + + // - For chosen association selectors (menus). + const targetAssoc = target.querySelector(`#jform_associations_${referenceLang}`); + if (targetAssoc) { + targetAssoc.value = ''; + } + + // Reset switcher after removing association + const currentLangSelect = document.getElementById('jform_itemlanguage'); + const currentSwitcher = currentLangSelect.value; + const currentLang = targetLang.replace(/_/, '-'); + document.querySelector(`#jform_itemlanguage option[value="${currentSwitcher}"]`).value = `${currentLang}:0:add`; + currentLangSelect.value = ''; + currentLangSelect.dispatchEvent(new CustomEvent('change', { + bubbles: true, + cancelable: true, + })); + + // Save one of the items to confirm action + Joomla.submitbutton('reference'); + } else { + // Saving target or reference, send the save action to the target/reference iframe. + // We need to re-enable the language field to save. + const el = document.getElementById(`${task}-association`); + const content = el.contentDocument.body || el.contentWindow.document.body; + content.querySelector('#jform_language').removeAttribute('disabled'); + window.frames[`${task}-association`].Joomla.submitbutton(`${document.getElementById('adminForm').getAttribute('data-associatedview')}.apply`); + } + + return false; +}; + +hideElements(['toolbar-target', 'toolbar-copy']); diff --git a/build/media_source/com_contenthistory/joomla.asset.json b/build/media_source/com_contenthistory/joomla.asset.json index 2271393b7db16..db2e63cf18e92 100644 --- a/build/media_source/com_contenthistory/joomla.asset.json +++ b/build/media_source/com_contenthistory/joomla.asset.json @@ -10,7 +10,8 @@ "type": "script", "uri": "com_contenthistory/admin-compare-compare.min.js", "dependencies": [ - "core" + "core", + "diff" ], "attributes": { "type": "module" diff --git a/build/media_source/com_cpanel/joomla.asset.json b/build/media_source/com_cpanel/joomla.asset.json index 9dee0564003fa..9764d8c116aa6 100644 --- a/build/media_source/com_cpanel/joomla.asset.json +++ b/build/media_source/com_cpanel/joomla.asset.json @@ -8,13 +8,14 @@ { "name": "com_cpanel.admin-addmodule", "type": "script", - "uri": "com_cpanel/admin-add_module.min.js", + "uri": "", "dependencies": [ "core" ], "attributes": { "type": "module" - } + }, + "deprecated": true }, { "name": "com_cpanel.admin-cpanel", @@ -35,8 +36,7 @@ "core" ], "attributes": { - "type": "module", - "defer": true + "type": "module" } } ] diff --git a/build/media_source/com_cpanel/js/admin-add_module.es6.js b/build/media_source/com_cpanel/js/admin-add_module.es6.js deleted file mode 100644 index fdbfeb5450842..0000000000000 --- a/build/media_source/com_cpanel/js/admin-add_module.es6.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @copyright (C) 2019 Open Source Matters, Inc. - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ -((document) => { - 'use strict'; - - document.addEventListener('DOMContentLoaded', () => { - window.jSelectModuleType = () => { - const elements = document.querySelectorAll('#moduleDashboardAddModal .modal-footer .btn.hidden'); - - if (elements.length) { - setTimeout(() => { - elements.forEach((button) => { - button.classList.remove('hidden'); - }); - }, 1000); - } - }; - - const buttons = document.querySelectorAll('#moduleDashboardAddModal .modal-footer .btn'); - const hideButtons = []; - let isSaving = false; - - if (buttons.length) { - buttons.forEach((button) => { - if (button.classList.contains('hidden')) { - hideButtons.push(button); - } - - button.addEventListener('click', (event) => { - let elem = event.currentTarget; - - // There is some bug with events in iframe where currentTarget is "null" - // => prevent this here by bubble up - if (!elem) { - elem = event.target; - } - - if (elem) { - const clickTarget = elem.dataset.bsTarget; - - // We remember to be in the saving process - isSaving = clickTarget === '#saveBtn'; - - // Reset saving process, if e.g. the validation of the form fails - setTimeout(() => { isSaving = false; }, 1500); - - const iframe = document.querySelector('#moduleDashboardAddModal iframe'); - const content = iframe.contentDocument || iframe.contentWindow.document; - const targetBtn = content.querySelector(clickTarget); - - if (targetBtn) { - targetBtn.click(); - } - } - }); - }); - } - - const elementH = document.querySelector('#moduleDashboardAddModal'); - - if (elementH) { - elementH.addEventListener('hide.bs.modal', () => { - hideButtons.forEach((button) => { - button.classList.add('hidden'); - }); - }); - - elementH.addEventListener('hidden.bs.modal', () => { - if (isSaving) { - setTimeout(() => { window.parent.location.reload(); }, 1000); - } - }); - } - }); -})(document); diff --git a/build/media_source/com_guidedtours/joomla.asset.json b/build/media_source/com_guidedtours/joomla.asset.json new file mode 100644 index 0000000000000..32b9bf4a8527c --- /dev/null +++ b/build/media_source/com_guidedtours/joomla.asset.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name": "com_guidedtours", + "version": "4.0.0", + "description": "Joomla CMS", + "license": "GPL-2.0-or-later", + "assets": [ + { + "name": "com_guidedtours.tour-edit", + "type": "script", + "uri": "com_guidedtours/tour-edit.min.js", + "dependencies": [ + "core" + ], + "attributes": { + "type": "module", + "defer": true + } + } + ] +} diff --git a/build/media_source/com_guidedtours/js/tour-edit.es6.js b/build/media_source/com_guidedtours/js/tour-edit.es6.js new file mode 100644 index 0000000000000..6858160ce31a5 --- /dev/null +++ b/build/media_source/com_guidedtours/js/tour-edit.es6.js @@ -0,0 +1,37 @@ +/** + * @copyright (C) 2018 Open Source Matters, Inc. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +(() => { + 'use strict'; + + // before 'joomla:showon-processed' is implemented in Showon we must use more frequent 'joomla:showon-show' and'joomla:showon-hide' events + ['joomla:showon-show', 'joomla:showon-hide'].forEach((eventType) => { + document.addEventListener(eventType, () => { + document.querySelectorAll('#guidedtour-dates-form fieldset').forEach((fieldset) => { + // Only hide fieldsets containing field control-group i.e. not radio selectors etc. that may use fieldsets + if (fieldset.querySelectorAll(':scope .control-group').length === 0) { + return; + } + const visibleChildren = fieldset.querySelectorAll(':scope .control-group:not(.hidden)'); + if (visibleChildren.length) { + fieldset.classList.remove('hidden'); + } else { + fieldset.classList.add('hidden'); + } + }); + document.querySelectorAll('#guidedtour-dates-form joomla-tab-element').forEach((tabelement) => { + const tabLabel = document.querySelector(`button[aria-controls="${tabelement.id}"]`); + if (tabLabel) { + const visibleChildren = tabelement.querySelectorAll(':scope .control-group:not(.hidden)'); + if (visibleChildren.length) { + tabLabel.removeAttribute('hidden'); + } else { + tabLabel.setAttribute('hidden', 'hidden'); + } + } + }); + }); + }); +})(); diff --git a/build/media_source/com_installer/joomla.asset.json b/build/media_source/com_installer/joomla.asset.json index 11bc62d387616..3ca54fcb2b578 100644 --- a/build/media_source/com_installer/joomla.asset.json +++ b/build/media_source/com_installer/joomla.asset.json @@ -14,7 +14,9 @@ ], "attributes": { "type": "module" - } + }, + "deprecated": true, + "deprecatedMsg": "Use joomla.dialog asset for changelog popup" }, { "name": "com_installer.installer", diff --git a/build/media_source/com_media/scss/components/_media-browser.scss b/build/media_source/com_media/scss/components/_media-browser.scss index 66a0609a5d819..f797126c4398e 100644 --- a/build/media_source/com_media/scss/components/_media-browser.scss +++ b/build/media_source/com_media/scss/components/_media-browser.scss @@ -57,6 +57,7 @@ } .media-browser-item-info { + max-width: 250px; padding: 0 2px; overflow: hidden; font-size: .9rem; @@ -124,8 +125,7 @@ &.active { top: 0; z-index: 1; - width: max-content; - min-width: 100%; + width: 100%; background-color: $browser-background-color; border: 1px solid hsl(var(--hue), 35%, 95%); border-radius: .25rem; @@ -158,6 +158,9 @@ .media-browser-actions-item-name { padding: 2px; margin-block-end: 3px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } button, a { position: relative; @@ -380,6 +383,7 @@ > td, > th { + color: #fff; background-color: $table-item-icon-bg-selected; } } diff --git a/build/media_source/com_menus/js/admin-item-edit_modules.es6.js b/build/media_source/com_menus/js/admin-item-edit_modules.es6.js index f8d7f434964f9..17cafc2ead89b 100644 --- a/build/media_source/com_menus/js/admin-item-edit_modules.es6.js +++ b/build/media_source/com_menus/js/admin-item-edit_modules.es6.js @@ -3,99 +3,176 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -Joomla = window.Joomla || {}; - -(() => { - 'use strict'; +const options = Joomla.getOptions('menus-edit-modules', {}); +const viewLevels = options.viewLevels || []; +const menuId = options.itemId || 0; +const assigned1 = document.getElementById('jform_toggle_modules_assigned1'); +const assigned0 = document.getElementById('jform_toggle_modules_assigned0'); +const published1 = document.getElementById('jform_toggle_modules_published1'); +const published0 = document.getElementById('jform_toggle_modules_published0'); + +if (assigned1) { + assigned1.addEventListener('click', () => { + const list = [].slice.call(document.querySelectorAll('tr.no')); + + list.forEach((item) => { + item.classList.add('table-row'); + item.classList.remove('hidden'); + }); + }); +} - const options = Joomla.getOptions('menus-edit-modules'); +if (assigned0) { + assigned0.addEventListener('click', () => { + const list = [].slice.call(document.querySelectorAll('tr.no')); - if (options) { - window.viewLevels = options.viewLevels; - window.menuId = parseInt(options.itemId, 10); - } - - const baseLink = 'index.php?option=com_modules&client_id=0&task=module.edit&tmpl=component&view=module&layout=modal&id='; - const assigned1 = document.getElementById('jform_toggle_modules_assigned1'); - const assigned0 = document.getElementById('jform_toggle_modules_assigned0'); - const published1 = document.getElementById('jform_toggle_modules_published1'); - const published0 = document.getElementById('jform_toggle_modules_published0'); - const linkElements = [].slice.call(document.getElementsByClassName('module-edit-link')); - const elements = [].slice.call(document.querySelectorAll('#moduleEditModal .modal-footer .btn')); - - if (assigned1) { - assigned1.addEventListener('click', () => { - const list = [].slice.call(document.querySelectorAll('tr.no')); - - list.forEach((item) => { - item.classList.add('table-row'); - item.classList.remove('hidden'); - }); + list.forEach((item) => { + item.classList.add('hidden'); + item.classList.remove('table-row'); }); - } + }); +} - if (assigned0) { - assigned0.addEventListener('click', () => { - const list = [].slice.call(document.querySelectorAll('tr.no')); +if (published1) { + published1.addEventListener('click', () => { + const list = [].slice.call(document.querySelectorAll('.table tr.unpublished')); - list.forEach((item) => { - item.classList.add('hidden'); - item.classList.remove('table-row'); - }); + list.forEach((item) => { + item.classList.add('table-row'); + item.classList.remove('hidden'); }); - } + }); +} - if (published1) { - published1.addEventListener('click', () => { - const list = [].slice.call(document.querySelectorAll('.table tr.unpublished')); +if (published0) { + published0.addEventListener('click', () => { + const list = [].slice.call(document.querySelectorAll('.table tr.unpublished')); - list.forEach((item) => { - item.classList.add('table-row'); - item.classList.remove('hidden'); - }); + list.forEach((item) => { + item.classList.add('hidden'); + item.classList.remove('table-row'); }); + }); +} + +/** + * A helper to create an element + * @param {String} tag + * @param {String} content + * @param {Array} classList + * @returns {HTMLElement} + */ +const createElement = (tag, content, classList = []) => { + const el = document.createElement(tag); + el.textContent = content; + if (classList.length) { + el.classList.add(...classList); } + return el; +}; - if (published0) { - published0.addEventListener('click', () => { - const list = [].slice.call(document.querySelectorAll('.table tr.unpublished')); +/** + * Update module in list + * @param {Object} data + */ +const updateView = (data) => { + const modId = data.id; + const updPosition = data.position; + const updTitle = data.title; + const updMenus = data.assignment; + const updStatus = data.status; + const updAccess = data.access; + const tmpMenu = document.getElementById(`menus-${modId}`); + const tmpRow = document.getElementById(`tr-${modId}`); + const tmpStatus = document.getElementById(`status-${modId}`); + const assigned = data.assigned || []; + const inMenus = assigned.map((v) => Math.abs(v)); + const inAssignedList = inMenus.indexOf(menuId); + let assignedState = 0; // 0 = No, 1 = Yes, 2 = All + + // Update assignment badge + if (updMenus === '-') { + assignedState = 0; + } else if (updMenus === 0) { + assignedState = 2; + } else if (updMenus > 0) { + if (inAssignedList >= 0) { + assignedState = 1; + } else if (inAssignedList < 0) { + assignedState = 0; + } + } else if (updMenus < 0) { + if (inAssignedList >= 0) { + assignedState = 0; + } else if (inAssignedList < 0) { + assignedState = 1; + } + } - list.forEach((item) => { - item.classList.add('hidden'); - item.classList.remove('table-row'); - }); - }); + switch (assignedState) { + case 1: + tmpMenu.innerHTML = createElement('span', Joomla.Text._('JYES'), ['badge', 'bg-success']).outerHTML; + tmpRow.classList.add('no'); + break; + + case 2: + tmpMenu.innerHTML = createElement('span', Joomla.Text._('JALL'), ['badge', 'bg-info']).outerHTML; + tmpRow.classList.add('no'); + break; + + case 0: + default: + tmpMenu.innerHTML = createElement('span', Joomla.Text._('JNO'), ['badge', 'bg-danger']).outerHTML; + tmpRow.classList.add('no'); } - if (linkElements.length) { - linkElements.forEach((linkElement) => { - linkElement.addEventListener('click', ({ target }) => { - const link = baseLink + target.getAttribute('data-module-id'); - const modal = document.getElementById('moduleEditModal'); - const body = modal.querySelector('.modal-body'); - const iFrame = document.createElement('iframe'); - - iFrame.src = link; - iFrame.setAttribute('class', 'class="iframe jviewport-height70"'); - body.innerHTML = ''; - body.appendChild(iFrame); - - modal.open(); - }); - }); + // Update status + if (updStatus === 1) { + tmpStatus.innerHTML = createElement('span', Joomla.Text._('JYES'), ['badge', 'bg-success']).outerHTML; + tmpRow.classList.remove('unpublished'); + } else if (updStatus === 0) { + tmpStatus.innerHTML = createElement('span', Joomla.Text._('JNO'), ['badge', 'bg-danger']).outerHTML; + tmpRow.classList.add('unpublished'); + } else if (updStatus === -2) { + tmpStatus.innerHTML = createElement('span', Joomla.Text._('JTRASHED'), ['badge', 'bg-secondary']).outerHTML; + tmpRow.classList.add('unpublished'); } - if (elements.length) { - elements.forEach((element) => { - element.addEventListener('click', ({ target }) => { - const dataTarget = target.getAttribute('data-bs-target'); - - if (dataTarget) { - const iframe = document.querySelector('#moduleEditModal iframe'); - const iframeDocument = iframe.contentDocument || iframe.contentWindow.document; - iframeDocument.querySelector(dataTarget).click(); - } - }); - }); + // Update Title, Position and Access + document.querySelector(`#title-${modId}`).textContent = updTitle; + document.querySelector(`#position-${modId}`).textContent = updPosition; + document.querySelector(`#access-${modId}`).textContent = viewLevels[updAccess] || ''; +}; + +/** + * Message listener + * @param {MessageEvent} event + */ +const msgListener = function (event) { + // Avoid cross origins + if (event.origin !== window.location.origin) return; + // Check message + if (event.data.messageType === 'joomla:content-select' && event.data.contentType === 'com_modules.module') { + // Update view, if there are any changes + if (event.data.id) { + updateView(event.data); + } + // Close dialog + this.close(); } -})(); +}; + +// Listen when "add module" dialog opens, and add message listener +document.addEventListener('joomla-dialog:open', ({ target }) => { + if (!target.classList.contains('menus-dialog-module-editing')) return; + // Create a listener with current dialog context + const listener = msgListener.bind(target); + + // Wait for a message + window.addEventListener('message', listener); + + // Remove listener on close + target.addEventListener('joomla-dialog:close', () => { + window.removeEventListener('message', listener); + }); +}); diff --git a/build/media_source/com_menus/js/admin-menus-default.es6.js b/build/media_source/com_menus/js/admin-menus-default.es6.js index 6b75d9e0e8dcb..fe5d0548b0d76 100644 --- a/build/media_source/com_menus/js/admin-menus-default.es6.js +++ b/build/media_source/com_menus/js/admin-menus-default.es6.js @@ -2,35 +2,22 @@ * @copyright (C) 2018 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ -((Joomla) => { - 'use strict'; - if (Joomla.getOptions('menus-default')) { - // eslint-disable-next-line prefer-destructuring - const items = Joomla.getOptions('menus-default').items; +if (Joomla.getOptions('menus-default')) { + const items = Joomla.getOptions('menus-default', {}).items || []; - items.forEach((item) => { - window[`jSelectPosition_${item}`] = (name) => { - document.getElementById(item).value = name; - Joomla.Modal.getCurrent().close(); - }; - }); - } - - Array.from(document.querySelectorAll('.modal')).forEach((modalEl) => { - modalEl.addEventListener('hidden.bs.modal', () => { - setTimeout(() => { window.parent.location.reload(); }, 1000); - }); + items.forEach((item) => { + window[`jSelectPosition_${item}`] = (name) => { + document.getElementById(item).value = name; + Joomla.Modal.getCurrent().close(); + }; }); -})(Joomla); +} -((originalFn) => { - 'use strict'; - - Joomla.submitform = (task, form) => { - originalFn(task, form); - if (task === 'menu.exportXml') { - document.adminForm.task.value = ''; - } - }; -})(Joomla.submitform); +const originalFn = Joomla.submitform; +Joomla.submitform = (task, form) => { + originalFn(task, form); + if (task === 'menu.exportXml') { + document.adminForm.task.value = ''; + } +}; diff --git a/build/media_source/com_modules/joomla.asset.json b/build/media_source/com_modules/joomla.asset.json index 70ff669528af7..17ac88cbec032 100644 --- a/build/media_source/com_modules/joomla.asset.json +++ b/build/media_source/com_modules/joomla.asset.json @@ -8,13 +8,14 @@ { "name": "com_modules.admin-module-edit", "type": "script", - "uri": "com_modules/admin-module-edit.min.js", + "uri": "", "dependencies": [ "core" ], "attributes": { "type": "module" - } + }, + "deprecated": true }, { "name": "com_modules.admin-module-edit-assignment", diff --git a/build/media_source/com_modules/js/admin-module-edit.es6.js b/build/media_source/com_modules/js/admin-module-edit.es6.js deleted file mode 100644 index c5f022ddd0baf..0000000000000 --- a/build/media_source/com_modules/js/admin-module-edit.es6.js +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @copyright (C) 2018 Open Source Matters, Inc. - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ -Joomla = window.Joomla || {}; - -((Joomla) => { - 'use strict'; - - Joomla.submitbutton = (task) => { - if (task === 'module.cancel' || document.formvalidator.isValid(document.getElementById('module-form'))) { - Joomla.submitform(task, document.getElementById('module-form')); - - const options = Joomla.getOptions('module-edit'); - - if (window.self !== window.top) { - if (window.parent.viewLevels) { - const updPosition = document.getElementById('jform_position').value; - const updTitle = document.getElementById('jform_title').value; - const updMenus = document.querySelector('#jform_assignment').value; - const updStatus = document.querySelector('#jform_published').value; - const updAccess = document.querySelector('#jform_access').value; - const tmpMenu = window.parent.document.getElementById(`menus-${options.itemId}`); - const tmpRow = window.parent.document.getElementById(`tr-${options.itemId}`); - const tmpStatus = window.parent.document.getElementById(`status-${options.itemId}`); - window.parent.inMenus = []; - window.parent.numMenus = [].slice.call(document.querySelectorAll('input[name="jform[assigned][]"]')).length; - - [].slice.call(document.querySelectorAll('input[name="jform[assigned][]"]')).forEach((element) => { - if (updMenus > 0) { - if (element.checked) { - window.parent.inMenus.push(parseInt(element.value, 10)); - } - } - if (updMenus < 0) { - if (!element.checked) { - window.parent.inMenus.push(parseInt(element.value, 10)); - } - } - }); - if (updMenus === '-') { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JNO')}`); - if (!tmpRow.classList.contains('no') || tmpRow.classList.length === 0) { tmpRow.classList.add('no'); } - } - if (parseInt(updMenus, 10) === 0) { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JALL')}`); - if (tmpRow.classList.contains('no')) { tmpRow.classList.remove('no'); } - } - if (parseInt(updMenus, 10) > 0) { - if (window.parent.inMenus.indexOf(window.parent.menuId) >= 0) { - if (window.parent.numMenus === window.parent.inMenus.length) { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JALL')}`); - if (tmpRow.classList.contains('no') || tmpRow.classList.length === 0) { tmpRow.classList.remove('no'); } - } else { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JYES')}`); - if (tmpRow.classList.contains('no')) { tmpRow.classList.remove('no'); } - } - } - if (window.parent.inMenus.indexOf(window.parent.menuId) < 0) { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JNO')}`); - if (!tmpRow.classList.contains('no')) { tmpRow.classList.add('no'); } - } - } - if (parseInt(updMenus, 10) < 0) { - if (window.parent.inMenus.indexOf(window.parent.menuId) >= 0) { - if (window.parent.numMenus === window.parent.inMenus.length) { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JALL')}`); - if (tmpRow.classList.contains('no')) { tmpRow.classList.remove('no'); } - } else { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JYES')}`); - if (tmpRow.classList.contains('no')) { tmpRow.classList.remove('no'); } - } - } - if (window.parent.inMenus.indexOf(window.parent.menuId) < 0) { - tmpMenu.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JNO')}`); - if (!tmpRow.classList.contains('no') || tmpRow.classList.length === 0) { tmpRow.classList.add('no'); } - } - } - if (parseInt(updStatus, 10) === 1) { - tmpStatus.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JYES')}`); - if (tmpRow.classList.contains('unpublished')) { tmpRow.classList.remove('unpublished'); } - } - if (parseInt(updStatus, 10) === 0) { - tmpStatus.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JNO')}`); - if (!tmpRow.classList.contains('unpublished') || tmpRow.classList.length === 0) { tmpRow.classList.add('unpublished'); } - } - if (parseInt(updStatus, 10) === -2) { - tmpStatus.innerHTML = Joomla.sanitizeHtml(`${Joomla.Text._('JTRASHED')}`); - if (!tmpRow.classList.contains('unpublished') || tmpRow.classList.length === 0) { tmpRow.classList.add('unpublished'); } - } - if (document.formvalidator.isValid(document.getElementById('module-form'))) { - window.parent.document.querySelector(`#title-${options.itemId}`).innerText = updTitle; - window.parent.document.querySelector(`#position-${options.itemId}`).innerText = updPosition; - window.parent.document.querySelector(`#access-${options.itemId}`).innerHTML = Joomla.sanitizeHtml(window.parent.viewLevels[updAccess]); - } - } - - if (task !== 'module.apply') { - window.parent.Joomla.Modal.getCurrent().close(); - } - } - } - }; -})(Joomla); diff --git a/build/media_source/com_scheduler/joomla.asset.json b/build/media_source/com_scheduler/joomla.asset.json index 0a02038b91012..96b02e1639119 100644 --- a/build/media_source/com_scheduler/joomla.asset.json +++ b/build/media_source/com_scheduler/joomla.asset.json @@ -10,7 +10,8 @@ "type": "script", "uri": "com_scheduler/admin-view-run-test-task.js", "dependencies": [ - "core" + "core", + "joomla.dialog" ], "attributes": { "type" : "module" diff --git a/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js b/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js index 6981c9786f975..539e6a3689977 100644 --- a/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js +++ b/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js @@ -2,7 +2,6 @@ * @copyright (C) 2021 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ - /** * Provides the manual-run functionality for tasks over the com_scheduler administrator backend. * @@ -11,85 +10,120 @@ * * @since 4.1.0 */ -if (!window.Joomla) { - throw new Error('Joomla API was not properly initialised'); -} - -const initRunner = () => { - const paths = Joomla.getOptions('system.paths'); - const token = Joomla.getOptions('com_scheduler.test-task.token'); - const uri = `${paths ? `${paths.base}/index.php` : window.location.pathname}?option=com_ajax&format=json&plugin=RunSchedulerTest&group=system&id=%d${token ? `&${token}=1` : ''}`; - const modal = document.getElementById('scheduler-test-modal'); - - // Task output template - const template = ` -

    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_TASK')}

    -
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_STARTED')}
    -
    - `; - - const sanitiseTaskOutput = (text) => text - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1
    $2'); - - // Trigger the task through a GET request, populate the modal with output on completion. - const triggerTaskAndShowOutput = (e) => { - const button = e.relatedTarget; - const id = parseInt(button.dataset.id, 10); - const { title } = button.dataset; - - modal.querySelector('.modal-title').innerHTML = Joomla.Text._('COM_SCHEDULER_TEST_RUN_TITLE').replace('%d', id.toString()); - modal.querySelector('.modal-body > div').innerHTML = template.replace('%s', title); - - Joomla.request({ - url: uri.replace('%d', id.toString()), - onSuccess: (data, xhr) => { - [].slice.call(modal.querySelectorAll('.modal-body > div > div')).forEach((el) => { - el.parentNode.removeChild(el); - }); +// eslint-disable-next-line import/no-unresolved +import JoomlaDialog from 'joomla.dialog'; - const output = JSON.parse(data); - - if (output && output.success && output.data) { - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_COMPLETED')}
    `; - - if (output.data.duration > 0) { - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_DURATION').replace('%s', output.data.duration.toFixed(2))}
    `; - } - - if (output.data.output) { - const result = Joomla.sanitizeHtml((output.data.output), null, sanitiseTaskOutput); - - // Can use an indication for non-0 exit codes - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', result)}
    `; - } - } else { - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_TERMINATED')}
    `; - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status))}
    `; - } - }, - onError: (xhr) => { - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_TERMINATED')}
    `; - - const msg = Joomla.ajaxErrorsMessages(xhr); - modal.querySelector('.modal-body > div').innerHTML += `
    ${Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', msg.error)}
    `; - }, - }); - }; +/** + * 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; +}; - const reloadOnClose = () => { - window.location.href = `${paths ? `${paths.base}/index.php` : window.location.pathname}?option=com_scheduler&view=tasks`; +/** + * Trigger the task through a GET request + * + * @param {String} url + * @param {HTMLElement} resultContainer + */ +const runTheTask = (url, resultContainer) => { + const statusHolder = resultContainer.querySelector('.scheduler-status'); + const progressBar = resultContainer.querySelector('.progress-bar'); + const complete = (success) => { + progressBar.style.width = '100%'; + progressBar.classList.add(success ? 'bg-success' : 'bg-danger'); + setTimeout(() => progressBar.classList.remove('progress-bar-animated'), 500); }; - - if (modal) { - modal.addEventListener('show.bs.modal', triggerTaskAndShowOutput); - modal.addEventListener('hidden.bs.modal', reloadOnClose); - } - document.removeEventListener('DOMContentLoaded', initRunner); + progressBar.style.width = '15%'; + + fetch(url, { headers: { 'X-CSRF-Token': Joomla.getOptions('csrf.token', '') } }) + .then((response) => { + if (!response.ok) { + throw new Error(Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', response.status).replace('%d', response.status)); + } + return response.json(); + }) + .then((output) => { + if (!output.data) { + // The request was successful but the response is empty in some reason + throw new Error(Joomla.Text._('JLIB_JS_AJAX_ERROR_NO_CONTENT')); + } + + statusHolder.textContent = Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_COMPLETED'); + + if (output.data.duration > 0) { + resultContainer.appendChild(createEl('div', Joomla.Text._('COM_SCHEDULER_TEST_RUN_DURATION').replace('%s', output.data.duration.toFixed(2)))); + } + + if (output.data.output) { + resultContainer.appendChild(createEl('div', Joomla.Text._('COM_SCHEDULER_TEST_RUN_OUTPUT').replace('%s', '').replace('
    ', ''))); + resultContainer.appendChild(createEl('pre', output.data.output, ['bg-light', 'p-2'])); + } + + complete(true); + }) + .catch((error) => { + complete(false); + statusHolder.textContent = Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_TERMINATED'); + resultContainer.appendChild(createEl('div', error.message, ['text-danger'])); + }); }; -document.addEventListener('DOMContentLoaded', initRunner); +// Listen on click over a task button to run a task +document.addEventListener('click', (event) => { + const button = event.target.closest('button[data-scheduler-run]'); + if (!button) return; + event.preventDefault(); + + // Get the task info from the button + const { id, title, url } = button.dataset; + + // Prepare the initial popup content, by following template: + //
    + //

    Task: Task title

    + //
    Status: Task Status
    + //
    + //
    + const content = (() => { + const body = createEl('div', '', ['p-3']); + const progress = createEl('div', '', ['progress', 'mb-2']); + const progressBar = createEl('div', '', ['progress-bar', 'progress-bar-striped', 'progress-bar-animated']); + body.appendChild(createEl('h4', Joomla.Text._('COM_SCHEDULER_TEST_RUN_TASK').replace('%s', title))); + body.appendChild(createEl('div', Joomla.Text._('COM_SCHEDULER_TEST_RUN_STATUS_STARTED'), ['mb-2', 'scheduler-status'])); + progress.appendChild(progressBar); + body.appendChild(progress); + progressBar.style.width = '0%'; + return body; + })(); + + // Create dialog instance + const dialog = new JoomlaDialog({ + popupType: 'inline', + textHeader: Joomla.Text._('COM_SCHEDULER_TEST_RUN_TITLE').replace('%d', id), + textClose: Joomla.Text._('JCLOSE'), + popupContent: content, + width: '800px', + height: 'fit-content', + }); + + // Run the task when dialog is ready + dialog.addEventListener('joomla-dialog:open', () => { + runTheTask(url, content); + }); + // Reload the page when dialog is closed + dialog.addEventListener('joomla-dialog:close', () => { + window.location.reload(); + }); + + dialog.show(); +}); diff --git a/build/media_source/com_templates/css/admin-templates-default.css b/build/media_source/com_templates/css/admin-templates-default.css index ad23632aee633..7caebf6301625 100644 --- a/build/media_source/com_templates/css/admin-templates-default.css +++ b/build/media_source/com_templates/css/admin-templates-default.css @@ -74,12 +74,12 @@ [dir=rtl] #core-pane textarea, #override-pane textarea { - text-align: left; + direction: ltr; } [dir=rtl] #core-pane joomla-editor-codemirror, #override-pane joomla-editor-codemirror { - text-align: left; + direction: ltr; } [dir=rtl] #toggle-buttons { diff --git a/build/media_source/legacy/joomla.asset.json b/build/media_source/legacy/joomla.asset.json index 41d6a1fe972fb..f1849ef812c26 100644 --- a/build/media_source/legacy/joomla.asset.json +++ b/build/media_source/legacy/joomla.asset.json @@ -12,17 +12,6 @@ "jquery" ], "uri": "legacy/jquery-noconflict.min.js" - }, - { - "name": "joomla.treeselectmenu", - "type": "script", - "dependencies": [ - "jquery" - ], - "uri": "legacy/treeselectmenu.min.js", - "attributes": { - "defer": true - } } ] } diff --git a/build/media_source/legacy/js/toolbar.es5.js b/build/media_source/legacy/js/toolbar.es5.js index 24e33ce054949..9ab5b2e00aeb7 100644 --- a/build/media_source/legacy/js/toolbar.es5.js +++ b/build/media_source/legacy/js/toolbar.es5.js @@ -43,7 +43,7 @@ Joomla = window.Joomla || {}; // Handle Help buttons document.querySelectorAll('.js-toolbar-help-btn').forEach((button) => { button.addEventListener('click', (event) => { - const btn = event.target; + const btn = event.currentTarget; const winprops = `height=${parseInt(btn.dataset.height, 10)},width=${parseInt(btn.dataset.width, 10)},top=${(window.innerHeight - parseInt(btn.dataset.height, 10)) / 2},` + `left=${(window.innerWidth - parseInt(btn.dataset.width, 10)) / 2},scrollbars=${btn.dataset.width === 'true'},resizable`; diff --git a/build/media_source/legacy/js/treeselectmenu.es5.js b/build/media_source/legacy/js/treeselectmenu.es5.js deleted file mode 100644 index 9f71957c98567..0000000000000 --- a/build/media_source/legacy/js/treeselectmenu.es5.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @copyright (C) 2012 Open Source Matters, Inc. - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ -jQuery(function($) -{ - var treeselectmenu = $('div#treeselectmenu').html(); - var direction = (document.dir !== undefined) ? document.dir : document.getElementsByTagName("html")[0].getAttribute("dir"); - - $('.treeselect li').each(function() - { - $li = $(this); - $div = $li.find('div.treeselect-item:first'); - - // Add icons - $li.prepend(''); - - if ($li.find('ul.treeselect-sub').length) { - // Add classes to Expand/Collapse icons - $li.find('span.icon-').addClass('treeselect-toggle icon-chevron-down'); - - // Append drop down menu in nodes - $div.find('label:first').after(treeselectmenu); - - if (!$li.find('ul.treeselect-sub ul.treeselect-sub').length) { - $li.find('div.treeselect-menu-expand').remove(); - } - } - }); - - // Takes care of the Expand/Collapse of a node - $('span.treeselect-toggle').click(function() - { - $i = $(this); - - if (direction === 'rtl') { - var chevron = 'icon-chevron-left'; - } else { - var chevron = 'icon-chevron-right'; - } - - // Take care of parent UL - if ($i.parent().find('ul.treeselect-sub').is(':visible')) { - $i.removeClass('icon-chevron-down').addClass(chevron); - $i.parent().find('ul.treeselect-sub').hide(); - $i.parent().find('ul.treeselect-sub i.treeselect-toggle').removeClass('icon-chevron-down').addClass(chevron); - } else { - $i.removeClass(chevron).addClass('icon-chevron-down'); - $i.parent().find('ul.treeselect-sub').show(); - $i.parent().find('ul.treeselect-sub i.treeselect-toggle').removeClass(chevron).addClass('icon-chevron-down'); - } - }); - - // Takes care of the filtering - $('#treeselectfilter').keyup(function() - { - var text = $(this).val().toLowerCase(); - var hidden = 0; - $("#noresultsfound").hide(); - var $list_elements = $('.treeselect li'); - $list_elements.each(function() - { - if ($(this).text().toLowerCase().indexOf(text) == -1) { - $(this).hide(); - hidden++; - } - else { - $(this).show(); - } - }); - if(hidden == $list_elements.length) - { - $("#noresultsfound").show(); - } - }); - - // Checks all checkboxes the tree - $('#treeCheckAll').click(function() - { - $('.treeselect input').attr('checked', 'checked'); - }); - - // Unchecks all checkboxes the tree - $('#treeUncheckAll').click(function() - { - $('.treeselect input').attr('checked', false); - }); - - // Checks all checkboxes the tree - $('#treeExpandAll').click(function() - { - $('ul.treeselect ul.treeselect-sub').show(); - $('ul.treeselect span.treeselect-toggle').removeClass('icon-chevron-right').addClass('icon-chevron-down'); - }); - - // Unchecks all checkboxes the tree - $('#treeCollapseAll').click(function() - { - $('ul.treeselect ul.treeselect-sub').hide(); - $('ul.treeselect span.treeselect-toggle').removeClass('icon-chevron-down').addClass('icon-chevron-right'); - }); - // Take care of children check/uncheck all - $('a.checkall').click(function() - { - $(this).parents().eq(4).find('ul.treeselect-sub input').attr('checked', 'checked'); - }); - $('a.uncheckall').click(function() - { - $(this).parents().eq(4).find('ul.treeselect-sub input').attr('checked', false); - }); - - // Take care of children toggle all - $('a.expandall').click(function() - { - var $parent = $(this).parents().eq(6); - $parent.find('ul.treeselect-sub').show(); - $parent.find('ul.treeselect-sub i.treeselect-toggle').removeClass('icon-chevron-right').addClass('icon-chevron-down'); - }); - $('a.collapseall').click(function() - { - var $parent = $(this).parents().eq(6); - $parent.find('li ul.treeselect-sub').hide(); - $parent.find('li i.treeselect-toggle').removeClass('icon-chevron-down').addClass('icon-chevron-right'); - }); -}); diff --git a/build/media_source/mod_menu/js/admin-menu.es6.js b/build/media_source/mod_menu/js/admin-menu.es6.js index 47f2cc8c13798..5d068c3a452e3 100644 --- a/build/media_source/mod_menu/js/admin-menu.es6.js +++ b/build/media_source/mod_menu/js/admin-menu.es6.js @@ -2,8 +2,8 @@ * @copyright (C) 2019 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ -const allMenus = document.querySelectorAll('ul.main-nav'); -allMenus.forEach((menu) => { + +document.querySelectorAll('ul.main-nav').forEach((menu) => { // eslint-disable-next-line no-new, no-undef new MetisMenu(menu); }); @@ -20,12 +20,10 @@ if (!sidebar) { if (sidebar && !sidebar.getAttribute('data-hidden')) { // Sidebar const menuToggle = document.getElementById('menu-collapse'); - const firsts = [].slice.call(sidebar.querySelectorAll('.collapse-level-1')); // Apply 2nd level collapse - firsts.forEach((first) => { - const seconds = [].slice.call(first.querySelectorAll('.collapse-level-1')); - seconds.forEach((second) => { + sidebar.querySelectorAll('.collapse-level-1').forEach((first) => { + first.querySelectorAll('.collapse-level-1').forEach((second) => { if (second) { second.classList.remove('collapse-level-1'); second.classList.add('collapse-level-2'); @@ -40,10 +38,7 @@ if (sidebar && !sidebar.getAttribute('data-hidden')) { menuToggleIcon.classList.toggle('icon-toggle-on'); menuToggleIcon.classList.toggle('icon-toggle-off'); - const listItems = [].slice.call(document.querySelectorAll('.main-nav > li')); - listItems.forEach((item) => { - item.classList.remove('open'); - }); + document.querySelectorAll('.main-nav > li').forEach((item) => item.classList.remove('open')); const elem = document.querySelector('.child-open'); if (elem) { @@ -58,14 +53,11 @@ if (sidebar && !sidebar.getAttribute('data-hidden')) { }); // Sidebar Nav - const allLinks = wrapper.querySelectorAll('a.no-dropdown, a.collapse-arrow, .menu-dashboard > a'); const currentUrl = window.location.href; const mainNav = document.querySelector('ul.main-nav'); - const menuParents = [].slice.call(mainNav.querySelectorAll('li.parent > a')); - const subMenusClose = [].slice.call(mainNav.querySelectorAll('li.parent .close')); // Set active class - allLinks.forEach((link) => { + wrapper.querySelectorAll('a.no-dropdown, a.collapse-arrow, .menu-dashboard > a').forEach((link) => { if ( (!link.href.match(/index\.php$/) && currentUrl.indexOf(link.href) === 0) || (link.href.match(/index\.php$/) && currentUrl.match(/index\.php$/))) { @@ -120,20 +112,15 @@ if (sidebar && !sidebar.getAttribute('data-hidden')) { })); }; - menuParents.forEach((parent) => { + mainNav.querySelectorAll('li.parent > a').forEach((parent) => { parent.addEventListener('click', openToggle); parent.addEventListener('keyup', openToggle); }); // Menu close - subMenusClose.forEach((subMenu) => { + mainNav.querySelectorAll('li.parent .close').forEach((subMenu) => { subMenu.addEventListener('click', () => { - const menuChildsOpen = [].slice.call(mainNav.querySelectorAll('.open')); - - menuChildsOpen.forEach((menuChild) => { - menuChild.classList.remove('open'); - }); - + mainNav.querySelectorAll('.open').forEach((menuChild) => menuChild.classList.remove('open')); mainNav.classList.remove('child-open'); }); }); diff --git a/build/media_source/mod_menu/js/menu.es6.js b/build/media_source/mod_menu/js/menu.es6.js index ad1745dd60624..50e9adebf0e7f 100644 --- a/build/media_source/mod_menu/js/menu.es6.js +++ b/build/media_source/mod_menu/js/menu.es6.js @@ -27,10 +27,9 @@ menuHoverClass: 'show-menu', dir: 'ltr', }; - const topLevelChilds = nav.querySelectorAll(':scope > li'); // Set tabIndex to -1 so that top_level_childs can't receive focus until menu is open - topLevelChilds.forEach((topLevelEl) => { + nav.querySelectorAll(':scope > li').forEach((topLevelEl) => { const linkEl = topLevelEl.querySelector('a'); if (linkEl) { linkEl.tabIndex = '0'; @@ -139,9 +138,6 @@ } document.addEventListener('DOMContentLoaded', () => { - const navs = document.querySelectorAll('.nav'); - [].forEach.call(navs, (nav) => { - setupNavigation(nav); - }); + document.querySelectorAll('.nav').forEach((nav) => setupNavigation(nav)); }); })(); diff --git a/build/media_source/mod_quickicon/js/quickicon.es6.js b/build/media_source/mod_quickicon/js/quickicon.es6.js index d0cc30c74ea18..a071955e23e3b 100644 --- a/build/media_source/mod_quickicon/js/quickicon.es6.js +++ b/build/media_source/mod_quickicon/js/quickicon.es6.js @@ -12,7 +12,7 @@ if (!Joomla) { throw new Error('Joomla API was not properly initialized'); } -Array.from(document.querySelectorAll('.quickicon')).forEach((quickicon) => { +document.querySelectorAll('.quickicon').forEach((quickicon) => { const counter = quickicon.querySelector('.quickicon-amount'); if (!counter) { return; @@ -30,7 +30,7 @@ Array.from(document.querySelectorAll('.quickicon')).forEach((quickicon) => { quickicon.classList.add('error'); } - if (Object.prototype.hasOwnProperty.call(response, 'data')) { + if (Object.hasOwn(response, 'data')) { const name = quickicon.querySelector('.quickicon-name'); const nameSpan = document.createElement('span'); quickicon.classList.add(response.data > 0 ? 'warning' : 'success'); diff --git a/build/media_source/mod_sampledata/js/sampledata-process.es6.js b/build/media_source/mod_sampledata/js/sampledata-process.es6.js index 29b6a0013a763..adc2be7c61340 100644 --- a/build/media_source/mod_sampledata/js/sampledata-process.es6.js +++ b/build/media_source/mod_sampledata/js/sampledata-process.es6.js @@ -149,9 +149,7 @@ const sampledataApply = (element) => { } // Turn on the progress container - const progressElements = [].slice.call(document.querySelectorAll(`.sampledata-progress-${type}`)); - - progressElements.forEach((progressElement) => { + document.querySelectorAll(`.sampledata-progress-${type}`).forEach((progressElement) => { progressElement.classList.remove('d-none'); }); @@ -167,8 +165,7 @@ const sampledataApply = (element) => { const sampleDataWrapper = document.getElementById('sample-data-wrapper'); if (sampleDataWrapper) { - const links = [].slice.call(sampleDataWrapper.querySelectorAll('.apply-sample-data')); - links.forEach((link) => { + sampleDataWrapper.querySelectorAll('.apply-sample-data').forEach((link) => { link.addEventListener('click', ({ currentTarget }) => sampledataApply(currentTarget)); }); } diff --git a/build/media_source/plg_behaviour_compat/es5.asset.json b/build/media_source/plg_behaviour_compat/es5.asset.json index fe0d8342c60ef..a2d72ce8e848b 100644 --- a/build/media_source/plg_behaviour_compat/es5.asset.json +++ b/build/media_source/plg_behaviour_compat/es5.asset.json @@ -650,7 +650,8 @@ "deprecated": true, "uri": "", "dependencies": [ - "core", "messages" + "core", + "messages" ], "attributes": { "nomodule": true, diff --git a/build/media_source/plg_editors_codemirror/css/codemirror.css b/build/media_source/plg_editors_codemirror/css/codemirror.css index f4a7a40614c0d..69340b4ec19ea 100644 --- a/build/media_source/plg_editors_codemirror/css/codemirror.css +++ b/build/media_source/plg_editors_codemirror/css/codemirror.css @@ -27,6 +27,7 @@ joomla-editor-codemirror.fullscreen { joomla-editor-codemirror.fullscreen .cm-editor { width: auto !important; height: 90vh !important; + background-color: var(--body-bg); } diff --git a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js index cdae08de84272..7345066947363 100644 --- a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js +++ b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js @@ -407,7 +407,7 @@ const TinyMCEBuilder = (container, options) => { [].forEach.call(target.attributes, (attrib) => { if (/^data-/.test(attrib.name)) { - const key = attrib.name.substr(5); + const key = attrib.name.substring(5); actionoptions[key] = attrib.value; } diff --git a/build/media_source/plg_installer_webinstaller/js/client.es6.js b/build/media_source/plg_installer_webinstaller/js/client.es6.js index b2b848ca501eb..17f30b55db7c0 100644 --- a/build/media_source/plg_installer_webinstaller/js/client.es6.js +++ b/build/media_source/plg_installer_webinstaller/js/client.es6.js @@ -103,8 +103,8 @@ class WebInstaller { const jedContainer = document.getElementById('jed-container'); jedContainer.innerHTML = Joomla.sanitizeHtml(response.data.html, allowList); - document.getElementById('com-apps-searchbox').addEventListener('keypress', ({ which }) => { - if (which === 13) { + document.getElementById('com-apps-searchbox').addEventListener('keydown', ({ code }) => { + if (code === 'Enter') { this.initiateSearch(); } }); diff --git a/build/media_source/plg_system_guidedtours/js/guidedtours.es6.js b/build/media_source/plg_system_guidedtours/js/guidedtours.es6.js index 363dfb08d0f23..decc52bacfe4a 100644 --- a/build/media_source/plg_system_guidedtours/js/guidedtours.es6.js +++ b/build/media_source/plg_system_guidedtours/js/guidedtours.es6.js @@ -66,6 +66,17 @@ function setFocus(primaryButton, secondaryButton, cancelButton) { } } +function enableButton(eventElement) { + const element = eventElement instanceof Event ? document.querySelector(`.step-next-button-${eventElement.currentTarget.step_id}`) : eventElement; + element.removeAttribute('disabled'); + element.classList.remove('disabled'); +} +function disableButton(eventElement) { + const element = eventElement instanceof Event ? document.querySelector(`.step-next-button-${eventElement.currentTarget.step_id}`) : eventElement; + element.setAttribute('disabled', 'disabled'); + element.classList.add('disabled'); +} + function addStepToTourButton(tour, stepObj, buttons) { const step = new Shepherd.Step(tour, { title: stepObj.title, @@ -74,6 +85,7 @@ function addStepToTourButton(tour, stepObj, buttons) { buttons, id: stepObj.id, arrow: true, + params: stepObj.params, beforeShowPromise() { return new Promise((resolve) => { // Set graceful fallbacks in case there is an issue with the target. @@ -116,6 +128,14 @@ function addStepToTourButton(tour, stepObj, buttons) { const element = this.getElement(); const target = this.getTarget(); + // if target element doesn't exist e.g. because we have navigated to a new page mid-tour then end the tour here! + // Take care though since some steps have no target to we check for these too + if (!target && this.options.attachTo.element) { + emptyStorage(); + this.cancel(); + return; + } + // Force the screen reader to only read the content of the popup after a refresh element.setAttribute('aria-live', 'assertive'); @@ -127,19 +147,66 @@ function addStepToTourButton(tour, stepObj, buttons) { const primaryButton = element.querySelector('.shepherd-button-primary'); const secondaryButton = element.querySelector('.shepherd-button-secondary'); - // The 'next' button should always be enabled if the target input field of type 'text' has a value - if ( - target.tagName.toLowerCase() === 'input' - && target.hasAttribute('required') - && (['email', 'password', 'search', 'tel', 'text', 'url'].includes(target.type)) - ) { - if (target.value.trim().length) { - primaryButton.removeAttribute('disabled'); - primaryButton.classList.remove('disabled'); - } else { - primaryButton.setAttribute('disabled', 'disabled'); - primaryButton.classList.add('disabled'); - } + // Check to see if the 'next' button should be enabled before showing the step based on being required or + // matching the required value + switch (this.options.attachTo.interactive_type) { + case 'text': + if ( + (target.hasAttribute('required') || (this.options.params.required || 0)) + && ( + (target.tagName.toLowerCase() === 'input' && ['email', 'password', 'search', 'tel', 'text', 'url'].includes(target.type)) + || target.tagName.toLowerCase() === 'textarea' + ) + ) { + if ((this.options.params.requiredvalue || '') !== '') { + if (target.value.trim() === this.options.params.requiredvalue) { + enableButton(primaryButton); + } else { + disableButton(primaryButton); + } + } else if (target.value.trim().length) { + enableButton(primaryButton); + } else { + disableButton(primaryButton); + } + } + break; + + case 'checkbox_radio': + if ( + target.tagName.toLowerCase() === 'input' + && (target.hasAttribute('required') || (this.options.params.required || 0)) + && ['checkbox', 'radio'].includes(target.type) + ) { + if (target.checked) { + enableButton(primaryButton); + } else { + disableButton(primaryButton); + } + } + break; + + case 'select': + if ( + target.tagName.toLowerCase() === 'select' + && (target.hasAttribute('required') || (this.options.params.required || 0)) + ) { + if ((this.options.params.requiredvalue || '') !== '') { + if (target.value.trim() === this.options.params.requiredvalue) { + enableButton(primaryButton); + } else { + disableButton(primaryButton); + } + } else if (target.value.trim().length) { + enableButton(primaryButton); + } else { + disableButton(primaryButton); + } + } + break; + + default: + break; } cancelButton.addEventListener('keydown', (event) => { @@ -206,6 +273,7 @@ function addStepToTourButton(tour, stepObj, buttons) { url: stepObj.url, type: stepObj.type, interactive_type: stepObj.interactive_type, + params: stepObj.params, }, }); } else { @@ -214,6 +282,7 @@ function addStepToTourButton(tour, stepObj, buttons) { url: stepObj.url, type: stepObj.type, interactive_type: stepObj.interactive_type, + params: stepObj.params, }, }); } @@ -292,17 +361,6 @@ function addBackButton(buttons, step) { }); } -function enableButton(event) { - const element = document.querySelector(`.step-next-button-${event.currentTarget.step_id}`); - element.removeAttribute('disabled'); - element.classList.remove('disabled'); -} -function disableButton(event) { - const element = document.querySelector(`.step-next-button-${event.currentTarget.step_id}`); - element.setAttribute('disabled', 'disabled'); - element.classList.add('disabled'); -} - function startTour(obj) { // We store the tour id to restart on site refresh sessionStorage.setItem('tourId', obj.id); @@ -342,7 +400,7 @@ function startTour(obj) { ind = 1; } - // Now let's add all follow up steps + // Now let's add all followup steps const len = obj.steps.length; let buttons; @@ -362,6 +420,12 @@ function startTour(obj) { && obj.steps[index].target && obj.steps[index].type === 'interactive' ) { + if (typeof obj.steps[index].params === 'string' && obj.steps[index].params !== '') { + obj.steps[index].params = JSON.parse(obj.steps[index].params); + } else { + obj.steps[index].params = []; + } + const ele = document.querySelector(obj.steps[index].target); if (ele) { if (obj && obj.steps && obj.steps[index] && obj.steps[index].interactive_type) { @@ -377,12 +441,63 @@ function startTour(obj) { case 'text': ele.step_id = index; - if (ele.hasAttribute('required') && ['email', 'password', 'search', 'tel', 'text', 'url'].includes(ele.type)) { + if ( + (ele.hasAttribute('required') || (obj.steps[index].params.required || 0)) + && ( + (ele.tagName.toLowerCase() === 'input' && ['email', 'password', 'search', 'tel', 'text', 'url'].includes(ele.type)) + || ele.tagName.toLowerCase() === 'textarea' + ) + ) { ['input', 'focus'].forEach((eventName) => ele.addEventListener(eventName, (event) => { if (!sessionStorage.getItem('tourId')) { return; } - if (event.target.value.trim().length) { + if ((obj.steps[index].params.requiredvalue || '') !== '') { + if (event.target.value.trim() === obj.steps[index].params.requiredvalue) { + enableButton(event); + } else { + disableButton(event); + } + } else if (event.target.value.trim().length) { + enableButton(event); + } else { + disableButton(event); + } + })); + } + break; + + case 'checkbox_radio': + ele.step_id = index; + if ( + ele.tagName.toLowerCase() === 'input' + && (ele.hasAttribute('required') || (obj.steps[index].params.required || 0)) + && ['checkbox', 'radio'].includes(ele.type) + ) { + ['click'].forEach((eventName) => ele.addEventListener(eventName, (event) => { + if (event.target.checked) { + enableButton(event); + } else { + disableButton(event); + } + })); + } + break; + + case 'select': + ele.step_id = index; + if ( + ele.tagName.toLowerCase() === 'select' + && (ele.hasAttribute('required') || (obj.steps[index].params.required || 0)) + ) { + ['change'].forEach((eventName) => ele.addEventListener(eventName, (event) => { + if ((obj.steps[index].params.requiredvalue || '') !== '') { + if (event.target.value.trim() === obj.steps[index].params.requiredvalue) { + enableButton(event); + } else { + disableButton(event); + } + } else if (event.target.value.trim().length) { enableButton(event); } else { disableButton(event); @@ -410,8 +525,7 @@ function startTour(obj) { if (index < len - 1) { if ( (obj && obj.steps[index].type !== 'interactive') - || (obj && obj.steps[index].interactive_type === 'text') - || (obj && obj.steps[index].interactive_type === 'other') + || (obj && ['text', 'checkbox_radio', 'select', 'other'].includes(obj.steps[index].interactive_type)) ) { pushNextButton(buttons, obj.steps[index]); } diff --git a/build/media_source/plg_system_jooa11y/joomla.asset.json b/build/media_source/plg_system_jooa11y/joomla.asset.json index 4f39991313bae..7ca6fa5ecbcd6 100644 --- a/build/media_source/plg_system_jooa11y/joomla.asset.json +++ b/build/media_source/plg_system_jooa11y/joomla.asset.json @@ -10,7 +10,9 @@ "type": "script", "uri": "plg_system_jooa11y/jooa11y.min.js", "dependencies": [ - "core" + "core", + "sa11y", + "sa11y-lang" ], "attributes": { "type": "module" @@ -19,7 +21,12 @@ { "name": "plg_system_jooa11y.jooa11y", "type": "style", - "uri": "plg_system_jooa11y/jooa11y.min.css" + "uri": "", + "deprecated": true, + "deprecatedMsg": "Use 'sa11y' style asset instead", + "dependencies": [ + "sa11y" + ] } ] } diff --git a/build/media_source/plg_system_jooa11y/js/jooa11y.es6.js b/build/media_source/plg_system_jooa11y/js/jooa11y.es6.js index a244ba011caa1..b79cdd3e86a5c 100644 --- a/build/media_source/plg_system_jooa11y/js/jooa11y.es6.js +++ b/build/media_source/plg_system_jooa11y/js/jooa11y.es6.js @@ -1,17 +1,11 @@ -import { Jooa11y, Lang } from '@joomla/joomla-a11y-checker/dist/js/joomla-a11y-checker.esm.js'; +// eslint-disable-next-line import/no-unresolved +import { Sa11y, Lang } from 'sa11y'; +// eslint-disable-next-line import/no-unresolved +import Sa11yLang from 'sa11y-lang'; -if (!Joomla) { - throw new Error('Joomla API is not properly initialised'); -} - -const stringPrefix = 'PLG_SYSTEM_JOOA11Y_'; - -Lang.translate = (string) => Joomla.Text._(stringPrefix + string, string); - -const options = Joomla.getOptions('jooa11yOptions'); +Lang.addI18n(Sa11yLang.strings); window.addEventListener('load', () => { - // Instantiate - const checker = new Jooa11y(options); - checker.doInitialCheck(); + // eslint-disable-next-line no-new + new Sa11y(Joomla.getOptions('jooa11yOptions', {})); }); diff --git a/build/media_source/plg_system_jooa11y/scss/jooa11y.scss b/build/media_source/plg_system_jooa11y/scss/jooa11y.scss deleted file mode 100644 index 187e9f18d634a..0000000000000 --- a/build/media_source/plg_system_jooa11y/scss/jooa11y.scss +++ /dev/null @@ -1 +0,0 @@ -@import "../../../../node_modules/@joomla/joomla-a11y-checker/dist/css/joomla-a11y-checker"; diff --git a/build/media_source/system/joomla.asset.json b/build/media_source/system/joomla.asset.json index bb848037170c3..8c45d17173a25 100644 --- a/build/media_source/system/joomla.asset.json +++ b/build/media_source/system/joomla.asset.json @@ -670,6 +670,14 @@ "attributes": { "type": "module" } + }, + { + "name": "joomla.treeselectmenu", + "type": "script", + "uri": "system/treeselectmenu.min.js", + "attributes": { + "type": "module" + } } ] } diff --git a/build/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js b/build/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js index 1f39e8f914e54..1ca3c7fd720c9 100644 --- a/build/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js +++ b/build/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js @@ -276,7 +276,7 @@ case "%b": case "%B": for (j = 0; j < 12; ++j) { - if (localStrings.months[j].substr(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { + if (localStrings.months[j].substring(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { m = j; break; } @@ -319,7 +319,7 @@ if (a[i].search(/[a-zA-Z]+/) != -1) { var t = -1; for (j = 0; j < 12; ++j) { - if (localStrings.months[j].substr(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { + if (localStrings.months[j].substring(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { t = j; break; } @@ -402,7 +402,7 @@ s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) // FIXME: %x : preferred date representation for the current locale without the time // FIXME: %X : preferred time representation for the current locale without the date - s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) + s["%y"] = ('' + y).substring(2); // year without the century (range 00 to 99) s["%Y"] = y; // year with the century s["%%"] = "%"; // a literal '%' character diff --git a/build/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js b/build/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js index 8909fb1f2afb6..55f0cdfdbe413 100644 --- a/build/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js +++ b/build/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js @@ -356,7 +356,7 @@ Date.prototype.print = function (str, dateType, translate, localStrings) { s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) // FIXME: %x : preferred date representation for the current locale without the time // FIXME: %X : preferred time representation for the current locale without the date - s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) + s["%y"] = ('' + y).substring(2); // year without the century (range 00 to 99) s["%Y"] = y; // year with the century s["%%"] = "%"; // a literal '%' character @@ -405,7 +405,7 @@ Date.parseFieldDate = function(str, fmt, dateType, localStrings) { case "%b": case "%B": for (j = 0; j < 12; ++j) { - if (localStrings.months[j].substr(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { m = j; break; } + if (localStrings.months[j].substring(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { m = j; break; } } break; @@ -444,7 +444,7 @@ Date.parseFieldDate = function(str, fmt, dateType, localStrings) { if (a[i].search(/[a-zA-Z]+/) != -1) { var t = -1; for (j = 0; j < 12; ++j) { - if (localStrings.months[j].substr(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { t = j; break; } + if (localStrings.months[j].substring(0, a[i].length).toLowerCase() === a[i].toLowerCase()) { t = j; break; } } if (t != -1) { if (m != -1) { diff --git a/build/media_source/system/js/fields/calendar.es5.js b/build/media_source/system/js/fields/calendar.es5.js index b4bc2721020b4..d3ccfc20e1e2f 100644 --- a/build/media_source/system/js/fields/calendar.es5.js +++ b/build/media_source/system/js/fields/calendar.es5.js @@ -509,45 +509,40 @@ /** Method to handle keyboard click events **/ JoomlaCalendar.prototype._handleCalKeyEvent = function (ev) { var self = this, - K = ev.keyCode; + code = ev.code; // Get value from input - if (ev.target === this.inputField && (K === 13 || K === 9)) { + if (ev.target === this.inputField && (code === 'Enter' || code === 'Tab')) { this.close(); } if (self.params.direction === 'rtl') { - if (K === 37) { - K = 39; - } else if (K === 39) { - K = 37; + if (code === 'ArrowLeft') { + code = 'ArrowRight'; + } else if (code === 'ArrowRight') { + code = 'ArrowLeft'; } } - if (K === 32) { // KEY Shift + space (now) - if (ev.shiftKey) { - ev.preventDefault(); - this.cellClick(self._nav_now, ev); - self.close(); - } + if (ev.shiftKey && code === 'Space') { + ev.preventDefault(); + this.cellClick(self._nav_now, ev); + self.close(); } - if (K === 27) { // KEY esc (close); + if (code === 'Escape') { this.close(); } - if (K === 38) { // KEY up (previous week) + if (code === 'ArrowUp') { this.moveCursorBy(7); } - if (K === 40) { // KEY down (next week) - this.moveCursorBy( -7); + if (code === 'ArrowDown') { + this.moveCursorBy(-7); } - if (K === 37) { // KEY left (previous day) + if (code === 'ArrowLeft') { this.moveCursorBy(1); } - if (K === 39) { // KEY right (next day) - this.moveCursorBy( -1); - } - if (ev.target === this.inputField && !(K>48 || K<57 || K===186 || K===189 || K===190 || K===32)) { - return stopCalEvent(ev); + if (code === 'ArrowRight') { + this.moveCursorBy(-1); } }; diff --git a/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js index dea9a903b953c..ddf06fa06a643 100644 --- a/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js +++ b/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js @@ -264,7 +264,7 @@ this.icon.setAttribute('class', clss); } - const uniqueId = `simple-color-${Math.random().toString(36).substr(2, 10)}`; + const uniqueId = `simple-color-${Math.random().toString(36).substring(2, 12)}`; this.icon.setAttribute('type', 'button'); this.icon.setAttribute('tabindex', '0'); this.icon.style.backgroundColor = color; diff --git a/build/media_source/system/js/fields/joomla-field-subform.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-subform.w-c.es6.js index 12de2790a5fd0..eaafaf052aea8 100644 --- a/build/media_source/system/js/fields/joomla-field-subform.w-c.es6.js +++ b/build/media_source/system/js/fields/joomla-field-subform.w-c.es6.js @@ -3,587 +3,611 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -((customElements) => { - 'use strict'; +const KEYCODE = { + SPACE: 'Space', + ESC: 'Escape', + ENTER: 'Enter', +}; - const KEYCODE = { - SPACE: 32, - ESC: 27, - ENTER: 13, - }; +/** + * Helper for testing whether a selection modifier is pressed + * @param {Event} event + * + * @returns {boolean|*} + */ +function hasModifier(event) { + return (event.ctrlKey || event.metaKey || event.shiftKey); +} - /** - * Helper for testing whether a selection modifier is pressed - * @param {Event} event - * - * @returns {boolean|*} - */ - function hasModifier(event) { - return (event.ctrlKey || event.metaKey || event.shiftKey); - } +class JoomlaFieldSubform extends HTMLElement { + // Attribute getters + get buttonAdd() { return this.getAttribute('button-add'); } - class JoomlaFieldSubform extends HTMLElement { - // Attribute getters - get buttonAdd() { return this.getAttribute('button-add'); } + get buttonRemove() { return this.getAttribute('button-remove'); } - get buttonRemove() { return this.getAttribute('button-remove'); } + get buttonMove() { return this.getAttribute('button-move'); } - get buttonMove() { return this.getAttribute('button-move'); } + get rowsContainer() { return this.getAttribute('rows-container'); } - get rowsContainer() { return this.getAttribute('rows-container'); } + get repeatableElement() { return this.getAttribute('repeatable-element'); } - get repeatableElement() { return this.getAttribute('repeatable-element'); } + get minimum() { return this.getAttribute('minimum'); } - get minimum() { return this.getAttribute('minimum'); } + get maximum() { return this.getAttribute('maximum'); } - get maximum() { return this.getAttribute('maximum'); } + get name() { return this.getAttribute('name'); } - get name() { return this.getAttribute('name'); } + set name(value) { + // Update the template + this.template = this.template.replace(new RegExp(` name="${this.name.replace(/[[\]]/g, '\\$&')}`, 'g'), ` name="${value}`); - set name(value) { - // Update the template - this.template = this.template.replace(new RegExp(` name="${this.name.replace(/[[\]]/g, '\\$&')}`, 'g'), ` name="${value}`); + this.setAttribute('name', value); + } - this.setAttribute('name', value); - } + constructor() { + super(); - constructor() { - super(); + const that = this; - const that = this; + // Get the rows container + this.containerWithRows = this; - // Get the rows container - this.containerWithRows = this; + if (this.rowsContainer) { + const allContainers = this.querySelectorAll(this.rowsContainer); - if (this.rowsContainer) { - const allContainers = this.querySelectorAll(this.rowsContainer); + // Find closest, and exclude nested + Array.from(allContainers).forEach((container) => { + if (container.closest('joomla-field-subform') === this) { + this.containerWithRows = container; + } + }); + } - // Find closest, and exclude nested - Array.from(allContainers).forEach((container) => { - if (container.closest('joomla-field-subform') === this) { - this.containerWithRows = container; - } - }); - } + // Keep track of row index, this is important to avoid a name duplication + // Note: php side should reset the indexes each time, eg: $value = array_values($value); + this.lastRowIndex = this.getRows().length - 1; - // Keep track of row index, this is important to avoid a name duplication - // Note: php side should reset the indexes each time, eg: $value = array_values($value); - this.lastRowIndex = this.getRows().length - 1; + // Template for the repeating group + this.template = ''; - // Template for the repeating group - this.template = ''; + // Prepare a row template, and find available field names + this.prepareTemplate(); - // Prepare a row template, and find available field names - this.prepareTemplate(); + // Bind buttons + if (this.buttonAdd || this.buttonRemove) { + this.addEventListener('click', (event) => { + let btnAdd = null; + let btnRem = null; - // Bind buttons - if (this.buttonAdd || this.buttonRemove) { - this.addEventListener('click', (event) => { - let btnAdd = null; - let btnRem = null; + if (that.buttonAdd) { + btnAdd = event.target.closest(that.buttonAdd); + } - if (that.buttonAdd) { - btnAdd = event.target.matches(that.buttonAdd) - ? event.target - : event.target.closest(that.buttonAdd); - } + if (that.buttonRemove) { + btnRem = event.target.closest(that.buttonRemove); + } - if (that.buttonRemove) { - btnRem = event.target.matches(that.buttonRemove) - ? event.target - : event.target.closest(that.buttonRemove); - } + // Check active, with extra check for nested joomla-field-subform + if (btnAdd && btnAdd.closest('joomla-field-subform') === that) { + let row = btnAdd.closest(that.repeatableElement); + row = row && row.closest('joomla-field-subform') === that ? row : null; + that.addRow(row); + event.preventDefault(); + } else if (btnRem && btnRem.closest('joomla-field-subform') === that) { + const row = btnRem.closest(that.repeatableElement); + that.removeRow(row); + event.preventDefault(); + } + }); - // Check active, with extra check for nested joomla-field-subform - if (btnAdd && btnAdd.closest('joomla-field-subform') === that) { - let row = btnAdd.closest(that.repeatableElement); - row = row && row.closest('joomla-field-subform') === that ? row : null; - that.addRow(row); - event.preventDefault(); - } else if (btnRem && btnRem.closest('joomla-field-subform') === that) { - const row = btnRem.closest(that.repeatableElement); - that.removeRow(row); - event.preventDefault(); - } - }); - - this.addEventListener('keydown', (event) => { - if (event.keyCode !== KEYCODE.SPACE) return; - const isAdd = that.buttonAdd && event.target.matches(that.buttonAdd); - const isRem = that.buttonRemove && event.target.matches(that.buttonRemove); - - if ((isAdd || isRem) && event.target.closest('joomla-field-subform') === that) { - let row = event.target.closest(that.repeatableElement); - row = row && row.closest('joomla-field-subform') === that ? row : null; - - if (isRem && row) { - that.removeRow(row); - } else if (isAdd) { - that.addRow(row); - } - event.preventDefault(); - } - }); - } + this.addEventListener('keydown', (event) => { + if (event.code !== KEYCODE.SPACE) return; + const isAdd = that.buttonAdd && event.target.matches(that.buttonAdd); + const isRem = that.buttonRemove && event.target.matches(that.buttonRemove); - // Sorting - if (this.buttonMove) { - this.setUpDragSort(); - } - } + if ((isAdd || isRem) && event.target.closest('joomla-field-subform') === that) { + let row = event.target.closest(that.repeatableElement); + row = row && row.closest('joomla-field-subform') === that ? row : null; - /** - * Search for existing rows - * @returns {HTMLElement[]} - */ - getRows() { - const rows = Array.from(this.containerWithRows.children); - const result = []; - - // Filter out the rows - rows.forEach((row) => { - if (row.matches(this.repeatableElement)) { - result.push(row); + if (isRem && row) { + that.removeRow(row); + } else if (isAdd) { + that.addRow(row); + } + event.preventDefault(); } }); - - return result; } - /** - * Prepare a row template - */ - prepareTemplate() { - const tmplElement = [].slice.call(this.children).filter((el) => el.classList.contains('subform-repeatable-template-section')); - - if (tmplElement[0]) { - this.template = tmplElement[0].innerHTML; - } - - if (!this.template) { - throw new Error('The row template is required for the subform element to work'); - } + // Sorting + if (this.buttonMove) { + this.setUpDragSort(); } + } - /** - * Add new row - * @param {HTMLElement} after - * @returns {HTMLElement} - */ - addRow(after) { - // Count how many we already have - const count = this.getRows().length; - if (count >= this.maximum) { - return null; + /** + * Search for existing rows + * @returns {HTMLElement[]} + */ + getRows() { + const rows = Array.from(this.containerWithRows.children); + const result = []; + + // Filter out the rows + rows.forEach((row) => { + if (row.matches(this.repeatableElement)) { + result.push(row); } + }); - // Make a new row from the template - let tmpEl; - if (this.containerWithRows.nodeName === 'TBODY' || this.containerWithRows.nodeName === 'TABLE') { - tmpEl = document.createElement('tbody'); - } else { - tmpEl = document.createElement('div'); - } - tmpEl.innerHTML = this.template; - const row = tmpEl.children[0]; + return result; + } - // Add to container - if (after) { - after.parentNode.insertBefore(row, after.nextSibling); - } else { - this.containerWithRows.append(row); - } + /** + * Prepare a row template + */ + prepareTemplate() { + const tmplElement = [].slice.call(this.children).filter((el) => el.classList.contains('subform-repeatable-template-section')); - // Add draggable attributes - if (this.buttonMove) { - row.setAttribute('draggable', 'false'); - row.setAttribute('aria-grabbed', 'false'); - row.setAttribute('tabindex', '0'); - } + if (tmplElement[0]) { + this.template = tmplElement[0].innerHTML; + } - // Marker that it is new - row.setAttribute('data-new', '1'); - // Fix names and ids, and reset values - this.fixUniqueAttributes(row, count); + if (!this.template) { + throw new Error('The row template is required for the subform element to work'); + } + } - // Tell about the new row - this.dispatchEvent(new CustomEvent('subform-row-add', { - detail: { row }, - bubbles: true, - })); + /** + * Add new row + * @param {HTMLElement} after + * @returns {HTMLElement} + */ + addRow(after) { + // Count how many we already have + const count = this.getRows().length; + if (count >= this.maximum) { + return null; + } - row.dispatchEvent(new CustomEvent('joomla:updated', { - bubbles: true, - cancelable: true, - })); + // Make a new row from the template + let tmpEl; + if (this.containerWithRows.nodeName === 'TBODY' || this.containerWithRows.nodeName === 'TABLE') { + tmpEl = document.createElement('tbody'); + } else { + tmpEl = document.createElement('div'); + } + tmpEl.innerHTML = this.template; + const row = tmpEl.children[0]; + + // Add to container + if (after) { + after.parentNode.insertBefore(row, after.nextSibling); + } else { + this.containerWithRows.append(row); + } - return row; + // Add draggable attributes + if (this.buttonMove) { + row.setAttribute('draggable', 'false'); + row.setAttribute('aria-grabbed', 'false'); + row.setAttribute('tabindex', '0'); } - /** - * Remove the row - * @param {HTMLElement} row - */ - removeRow(row) { - // Count how much we have - const count = this.getRows().length; - if (count <= this.minimum) { - return; - } + // Marker that it is new + row.setAttribute('data-new', '1'); + // Fix names and ids, and reset values + this.fixUniqueAttributes(row, count); - // Tell about the row will be removed - this.dispatchEvent(new CustomEvent('subform-row-remove', { - detail: { row }, - bubbles: true, - })); + // Tell about the new row + this.dispatchEvent(new CustomEvent('subform-row-add', { + detail: { row }, + bubbles: true, + })); - row.dispatchEvent(new CustomEvent('joomla:removed', { - bubbles: true, - cancelable: true, - })); + row.dispatchEvent(new CustomEvent('joomla:updated', { + bubbles: true, + cancelable: true, + })); - row.parentNode.removeChild(row); + return row; + } + + /** + * Remove the row + * @param {HTMLElement} row + */ + removeRow(row) { + // Count how much we have + const count = this.getRows().length; + if (count <= this.minimum) { + return; } - /** - * Fix name and id for fields that are in the row - * @param {HTMLElement} row - * @param {Number} count - */ - fixUniqueAttributes(row, count) { - const countTmp = count || 0; - const group = row.getAttribute('data-group'); // current group name - const basename = row.getAttribute('data-base-name'); - const countnew = Math.max(this.lastRowIndex, countTmp); - const groupnew = basename + countnew; // new group name - - this.lastRowIndex = countnew + 1; - row.setAttribute('data-group', groupnew); - - // Fix inputs that have a "name" attribute - let haveName = row.querySelectorAll('[name]'); - const ids = {}; // Collect id for fix checkboxes and radio - - // Filter out nested - haveName = [].slice.call(haveName).filter((el) => { - if (el.nodeName === 'JOOMLA-FIELD-SUBFORM') { - // Skip self in .closest() call - return el.parentElement.closest('joomla-field-subform') === this; - } + // Tell about the row will be removed + this.dispatchEvent(new CustomEvent('subform-row-remove', { + detail: { row }, + bubbles: true, + })); - return el.closest('joomla-field-subform') === this; - }); + row.dispatchEvent(new CustomEvent('joomla:removed', { + bubbles: true, + cancelable: true, + })); - haveName.forEach((elem) => { - const $el = elem; - const name = $el.getAttribute('name'); - const aria = $el.getAttribute('aria-describedby'); - const id = name - .replace(/(\[\]$)/g, '') - .replace(/(\]\[)/g, '__') - .replace(/\[/g, '_') - .replace(/\]/g, ''); // id from name - const nameNew = name.replace(`[${group}][`, `[${groupnew}][`); // New name - let idNew = id.replace(group, groupnew).replace(/\W/g, '_'); // Count new id - let countMulti = 0; // count for multiple radio/checkboxes - let forOldAttr = id; // Fix "for" in the labels - - if ($el.type === 'checkbox' && name.match(/\[\]$/)) { // fix - // Recount id - countMulti = ids[id] ? ids[id].length : 0; - if (!countMulti) { - // Set the id for fieldset and group label - const fieldset = $el.closest('fieldset.checkboxes'); - - const elLbl = row.querySelector(`label[for="${id}"]`); - - if (fieldset) { - fieldset.setAttribute('id', idNew); - } - - if (elLbl) { - elLbl.setAttribute('for', idNew); - elLbl.setAttribute('id', `${idNew}-lbl`); - } - } - forOldAttr += countMulti; - idNew += countMulti; - } else if ($el.type === 'radio') { // fix - // Recount id - countMulti = ids[id] ? ids[id].length : 0; - if (!countMulti) { - // Set the id for fieldset and group label - const fieldset = $el.closest('fieldset.radio'); - - const elLbl = row.querySelector(`label[for="${id}"]`); - - if (fieldset) { - fieldset.setAttribute('id', idNew); - } - - if (elLbl) { - elLbl.setAttribute('for', idNew); - elLbl.setAttribute('id', `${idNew}-lbl`); - } + row.parentNode.removeChild(row); + } + + /** + * Fix name and id for fields that are in the row + * @param {HTMLElement} row + * @param {Number} count + */ + fixUniqueAttributes(row, count) { + const countTmp = count || 0; + const group = row.getAttribute('data-group'); // current group name + const basename = row.getAttribute('data-base-name'); + const countnew = Math.max(this.lastRowIndex, countTmp); + const groupnew = basename + countnew; // new group name + + this.lastRowIndex = countnew + 1; + row.setAttribute('data-group', groupnew); + + // Fix inputs that have a "name" attribute + let haveName = row.querySelectorAll('[name]'); + const ids = {}; // Collect id for fix checkboxes and radio + + // Filter out nested + haveName = [].slice.call(haveName).filter((el) => { + if (el.nodeName === 'JOOMLA-FIELD-SUBFORM') { + // Skip self in .closest() call + return el.parentElement.closest('joomla-field-subform') === this; + } + + return el.closest('joomla-field-subform') === this; + }); + + haveName.forEach((elem) => { + const $el = elem; + const name = $el.getAttribute('name'); + const aria = $el.getAttribute('aria-describedby'); + const id = name + .replace(/(\[\]$)/g, '') + .replace(/(\]\[)/g, '__') + .replace(/\[/g, '_') + .replace(/\]/g, ''); // id from name + const nameNew = name.replace(`[${group}][`, `[${groupnew}][`); // New name + let idNew = id.replace(group, groupnew).replace(/\W/g, '_'); // Count new id + let countMulti = 0; // count for multiple radio/checkboxes + let forOldAttr = id; // Fix "for" in the labels + + if ($el.type === 'checkbox' && name.match(/\[\]$/)) { // fix + // Recount id + countMulti = ids[id] ? ids[id].length : 0; + if (!countMulti) { + // Set the id for fieldset and group label + const fieldset = $el.closest('fieldset.checkboxes'); + + const elLbl = row.querySelector(`label[for="${id}"]`); + + if (fieldset) { + fieldset.setAttribute('id', idNew); } - forOldAttr += countMulti; - idNew += countMulti; - } - // Cache already used id - if (ids[id]) { - ids[id].push(true); - } else { - ids[id] = [true]; + if (elLbl) { + elLbl.setAttribute('for', idNew); + elLbl.setAttribute('id', `${idNew}-lbl`); + } } + forOldAttr += countMulti; + idNew += countMulti; + } else if ($el.type === 'radio') { // fix + // Recount id + countMulti = ids[id] ? ids[id].length : 0; + if (!countMulti) { + // Set the id for fieldset and group label + const fieldset = $el.closest('fieldset.radio'); + + const elLbl = row.querySelector(`label[for="${id}"]`); + + if (fieldset) { + fieldset.setAttribute('id', idNew); + } - // Replace the name to new one - $el.name = nameNew; - if ($el.id) { - $el.id = idNew; + if (elLbl) { + elLbl.setAttribute('for', idNew); + elLbl.setAttribute('id', `${idNew}-lbl`); + } } + forOldAttr += countMulti; + idNew += countMulti; + } - if (aria) { - $el.setAttribute('aria-describedby', `${nameNew}-desc`); - } + // Cache already used id + if (ids[id]) { + ids[id].push(true); + } else { + ids[id] = [true]; + } - // Check if there is a label for this input - const lbl = row.querySelector(`label[for="${forOldAttr}"]`); - if (lbl) { - lbl.setAttribute('for', idNew); - lbl.setAttribute('id', `${idNew}-lbl`); - } - }); - } + // Replace the name to new one + $el.name = nameNew; + if ($el.id) { + $el.id = idNew; + } - /** - * Use of HTML Drag and Drop API - * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API - * https://www.sitepoint.com/accessible-drag-drop/ - */ - setUpDragSort() { - const that = this; // Self reference - let item = null; // Storing the selected item - let touched = false; // We have a touch events - - // Find all existing rows and add draggable attributes - const rows = Array.from(this.getRows()); - - rows.forEach((row) => { - row.setAttribute('draggable', 'false'); - row.setAttribute('aria-grabbed', 'false'); - row.setAttribute('tabindex', '0'); - }); + if (aria) { + $el.setAttribute('aria-describedby', `${nameNew}-desc`); + } - // Helper method to test whether Handler was clicked - function getMoveHandler(element) { - return !element.form // This need to test whether the element is :input - && element.matches(that.buttonMove) ? element : element.closest(that.buttonMove); + // Check if there is a label for this input + const lbl = row.querySelector(`label[for="${forOldAttr}"]`); + if (lbl) { + lbl.setAttribute('for', idNew); + lbl.setAttribute('id', `${idNew}-lbl`); } + }); + } - // Helper method to move row to selected position - function switchRowPositions(src, dest) { - let isRowBefore = false; - if (src.parentNode === dest.parentNode) { - for (let cur = src; cur; cur = cur.previousSibling) { - if (cur === dest) { - isRowBefore = true; - break; - } - } - } + /** + * Use of HTML Drag and Drop API + * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API + * https://www.sitepoint.com/accessible-drag-drop/ + */ + setUpDragSort() { + const that = this; // Self reference + let item = null; // Storing the selected item + let touched = false; // We have a touch events + + // Find all existing rows and add draggable attributes + this.getRows().forEach((row) => { + row.setAttribute('draggable', 'false'); + row.setAttribute('aria-grabbed', 'false'); + row.setAttribute('tabindex', '0'); + }); + + // Helper method to test whether Handler was clicked + function getMoveHandler(element) { + return !element.form // This need to test whether the element is :input + && element.matches(that.buttonMove) ? element : element.closest(that.buttonMove); + } - if (isRowBefore) { - dest.parentNode.insertBefore(src, dest); - } else { - dest.parentNode.insertBefore(src, dest.nextSibling); + // Helper method to move row to selected position + function switchRowPositions(src, dest) { + let isRowBefore = false; + if (src.parentNode === dest.parentNode) { + for (let cur = src; cur; cur = cur.previousSibling) { + if (cur === dest) { + isRowBefore = true; + break; + } } } - /** - * Touch interaction: - * - * - a touch of "move button" marks a row draggable / "selected", - * or deselect previous selected - * - * - a touch of "move button" in the destination row will move - * a selected row to a new position - */ - this.addEventListener('touchstart', (event) => { - touched = true; + if (isRowBefore) { + dest.parentNode.insertBefore(src, dest); + } else { + dest.parentNode.insertBefore(src, dest.nextSibling); + } + } - // Check for .move button - const handler = getMoveHandler(event.target); + /** + * Touch interaction: + * + * - a touch of "move button" marks a row draggable / "selected", + * or deselect previous selected + * + * - a touch of "move button" in the destination row will move + * a selected row to a new position + */ + this.addEventListener('touchstart', (event) => { + touched = true; - const row = handler ? handler.closest(that.repeatableElement) : null; + // Check for .move button + const handler = getMoveHandler(event.target); - if (!row || row.closest('joomla-field-subform') !== that) { - return; - } + const row = handler ? handler.closest(that.repeatableElement) : null; - // First selection - if (!item) { - row.setAttribute('draggable', 'true'); - row.setAttribute('aria-grabbed', 'true'); - item = row; - } else { // Second selection - // Move to selected position - if (row !== item) { - switchRowPositions(item, row); - } + if (!row || row.closest('joomla-field-subform') !== that) { + return; + } - item.setAttribute('draggable', 'false'); - item.setAttribute('aria-grabbed', 'false'); - item = null; + // First selection + if (!item) { + row.setAttribute('draggable', 'true'); + row.setAttribute('aria-grabbed', 'true'); + item = row; + } else { // Second selection + // Move to selected position + if (row !== item) { + switchRowPositions(item, row); } - event.preventDefault(); - }); + item.setAttribute('draggable', 'false'); + item.setAttribute('aria-grabbed', 'false'); + item = null; + } - // Mouse interaction - // - mouse down, enable "draggable" and allow to drag the row, - // - mouse up, disable "draggable" - this.addEventListener('mousedown', ({ target }) => { - if (touched) return; + event.preventDefault(); + }); - // Check for .move button - const handler = getMoveHandler(target); + // Mouse interaction + // - mouse down, enable "draggable" and allow to drag the row, + // - mouse up, disable "draggable" + this.addEventListener('mousedown', ({ target }) => { + if (touched) return; - const row = handler ? handler.closest(that.repeatableElement) : null; + // Check for .move button + const handler = getMoveHandler(target); - if (!row || row.closest('joomla-field-subform') !== that) { - return; - } + const row = handler ? handler.closest(that.repeatableElement) : null; - row.setAttribute('draggable', 'true'); - row.setAttribute('aria-grabbed', 'true'); - item = row; - }); + if (!row || row.closest('joomla-field-subform') !== that) { + return; + } - this.addEventListener('mouseup', () => { - if (item && !touched) { - item.setAttribute('draggable', 'false'); - item.setAttribute('aria-grabbed', 'false'); - item = null; - } - }); + row.setAttribute('draggable', 'true'); + row.setAttribute('aria-grabbed', 'true'); + item = row; + }); - // Keyboard interaction - // - "tab" to navigate to needed row, - // - modifier (ctr,alt,shift) + "space" select the row, - // - "tab" to select destination, - // - "enter" to place selected row in to destination - // - "esc" to cancel selection - this.addEventListener('keydown', (event) => { - if ((event.keyCode !== KEYCODE.ESC - && event.keyCode !== KEYCODE.SPACE - && event.keyCode !== KEYCODE.ENTER) || event.target.form - || !event.target.matches(that.repeatableElement)) { - return; - } + this.addEventListener('mouseup', () => { + if (item && !touched) { + item.setAttribute('draggable', 'false'); + item.setAttribute('aria-grabbed', 'false'); + item = null; + } + }); + + // Keyboard interaction + // - "tab" to navigate to needed row, + // - modifier (ctr,alt,shift) + "space" select the row, + // - "tab" to select destination, + // - "enter" to place selected row in to destination + // - "esc" to cancel selection + this.addEventListener('keydown', (event) => { + if ((event.code !== KEYCODE.ESC + && event.code !== KEYCODE.SPACE + && event.code !== KEYCODE.ENTER) || event.target.form + || !event.target.matches(that.repeatableElement)) { + return; + } - const row = event.target; + const row = event.target; - // Make sure we handle correct children - if (!row || row.closest('joomla-field-subform') !== that) { - return; - } + // Make sure we handle correct children + if (!row || row.closest('joomla-field-subform') !== that) { + return; + } - // Space is the selection or unselection keystroke - if (event.keyCode === KEYCODE.SPACE && hasModifier(event)) { - // Unselect previously selected - if (row.getAttribute('aria-grabbed') === 'true') { - row.setAttribute('draggable', 'false'); - row.setAttribute('aria-grabbed', 'false'); + // Space is the selection or unselection keystroke + if (event.code === KEYCODE.SPACE && hasModifier(event)) { + // Unselect previously selected + if (row.getAttribute('aria-grabbed') === 'true') { + row.setAttribute('draggable', 'false'); + row.setAttribute('aria-grabbed', 'false'); + item = null; + } else { // Select new + // If there was previously selected + if (item) { + item.setAttribute('draggable', 'false'); + item.setAttribute('aria-grabbed', 'false'); item = null; - } else { // Select new - // If there was previously selected - if (item) { - item.setAttribute('draggable', 'false'); - item.setAttribute('aria-grabbed', 'false'); - item = null; - } - - // Mark new selection - row.setAttribute('draggable', 'true'); - row.setAttribute('aria-grabbed', 'true'); - item = row; } - // Prevent default to suppress any native actions - event.preventDefault(); + // Mark new selection + row.setAttribute('draggable', 'true'); + row.setAttribute('aria-grabbed', 'true'); + item = row; } - // Escape is the cancel keystroke (for any target element) - if (event.keyCode === KEYCODE.ESC && item) { - item.setAttribute('draggable', 'false'); - item.setAttribute('aria-grabbed', 'false'); + // Prevent default to suppress any native actions + event.preventDefault(); + } + + // Escape is the cancel keystroke (for any target element) + if (event.code === KEYCODE.ESC && item) { + item.setAttribute('draggable', 'false'); + item.setAttribute('aria-grabbed', 'false'); + item = null; + } + + // Enter, to place selected item in selected position + if (event.code === KEYCODE.ENTER && item) { + item.setAttribute('draggable', 'false'); + item.setAttribute('aria-grabbed', 'false'); + + // Do nothing here + if (row === item) { item = null; + return; } - // Enter, to place selected item in selected position - if (event.keyCode === KEYCODE.ENTER && item) { - item.setAttribute('draggable', 'false'); - item.setAttribute('aria-grabbed', 'false'); + // Move the item to selected position + switchRowPositions(item, row); - // Do nothing here - if (row === item) { - item = null; - return; - } + event.preventDefault(); + item = null; + } + }); - // Move the item to selected position - switchRowPositions(item, row); + // dragstart event to initiate mouse dragging + this.addEventListener('dragstart', ({ dataTransfer }) => { + if (item) { + // We going to move the row + dataTransfer.effectAllowed = 'move'; - event.preventDefault(); - item = null; - } - }); + // This need to work in Firefox and IE10+ + dataTransfer.setData('text', ''); + } + }); - // dragstart event to initiate mouse dragging - this.addEventListener('dragstart', ({ dataTransfer }) => { - if (item) { - // We going to move the row - dataTransfer.effectAllowed = 'move'; + this.addEventListener('dragover', (event) => { + if (item) { + event.preventDefault(); + } + }); - // This need to work in Firefox and IE10+ - dataTransfer.setData('text', ''); - } - }); + // Handle drag action, move element to hovered position + this.addEventListener('dragenter', ({ target }) => { + // Make sure the target in the correct container + if (!item || target.parentElement.closest('joomla-field-subform') !== that) { + return; + } - this.addEventListener('dragover', (event) => { - if (item) { - event.preventDefault(); - } - }); + // Find a hovered row + const row = target.closest(that.repeatableElement); - // Handle drag action, move element to hovered position - this.addEventListener('dragenter', ({ target }) => { - // Make sure the target in the correct container - if (!item || target.parentElement.closest('joomla-field-subform') !== that) { - return; - } + // One more check for correct parent + if (!row || row.closest('joomla-field-subform') !== that) return; - // Find a hovered row - const row = target.closest(that.repeatableElement); + switchRowPositions(item, row); + }); - // One more check for correct parent - if (!row || row.closest('joomla-field-subform') !== that) return; + // dragend event to clean-up after drop or cancelation + // which fires whether or not the drop target was valid + this.addEventListener('dragend', () => { + if (item) { + item.setAttribute('draggable', 'false'); + item.setAttribute('aria-grabbed', 'false'); + item = null; + } + }); - switchRowPositions(item, row); - }); + /** + * Move UP, Move Down sorting + */ + const btnUp = `${that.buttonMove}-up`; + const btnDown = `${that.buttonMove}-down`; + this.addEventListener('click', ({ target }) => { + if (target.closest('joomla-field-subform') !== this) { + return; + } + const btnUpEl = target.closest(btnUp); + const btnDownEl = !btnUpEl ? target.closest(btnDown) : null; + if (!btnUpEl && !btnDownEl) { + return; + } + let row = (btnUpEl || btnDownEl).closest(that.repeatableElement); + row = row && row.closest('joomla-field-subform') === this ? row : null; + if (!row) { + return; + } + const rows = this.getRows(); + const curIdx = rows.indexOf(row); + let dstIdx = 0; - // dragend event to clean-up after drop or cancelation - // which fires whether or not the drop target was valid - this.addEventListener('dragend', () => { - if (item) { - item.setAttribute('draggable', 'false'); - item.setAttribute('aria-grabbed', 'false'); - item = null; - } - }); - } + if (btnUpEl) { + dstIdx = curIdx - 1; + dstIdx = dstIdx < 0 ? rows.length - 1 : dstIdx; + } else { + dstIdx = curIdx + 1; + dstIdx = dstIdx > rows.length - 1 ? 0 : dstIdx; + } + + switchRowPositions(row, rows[dstIdx]); + }); } +} - customElements.define('joomla-field-subform', JoomlaFieldSubform); -})(customElements); +customElements.define('joomla-field-subform', JoomlaFieldSubform); diff --git a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js index 13b68ba96856b..dbb5fd741194a 100644 --- a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js +++ b/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js @@ -143,6 +143,9 @@ class JoomlaFieldUser extends HTMLElement { window.removeEventListener('message', msgListener); dialog.destroy(); this.dialog = null; + // Focus on the input field to re-trigger the validation + this.inputName.focus(); + this.buttonSelect.focus(); }); this.dialog = dialog; diff --git a/build/media_source/system/js/fields/passwordstrength.es6.js b/build/media_source/system/js/fields/passwordstrength.es6.js index b5771d4cc5df6..1ca7f259f6bec 100644 --- a/build/media_source/system/js/fields/passwordstrength.es6.js +++ b/build/media_source/system/js/fields/passwordstrength.es6.js @@ -50,7 +50,7 @@ class PasswordStrength { // eslint-disable-next-line no-useless-escape score += this.constructor.calc( value, - /[$!#?=;:*\-_€%&()`´]/g, + /[@$!#?=;:*\-_€%&()`´]/g, this.special, mods, ); diff --git a/build/media_source/system/js/inlinehelp.es6.js b/build/media_source/system/js/inlinehelp.es6.js index 6236b9581f02c..e9387b36fae65 100644 --- a/build/media_source/system/js/inlinehelp.es6.js +++ b/build/media_source/system/js/inlinehelp.es6.js @@ -16,7 +16,7 @@ Joomla.toggleInlineHelp = (toggleClass) => { // The ID of the description whose visibility is toggled. const myId = elDiv.id; // The ID of the control described by this node (same ID, minus the '-desc' suffix). - const controlId = myId ? myId.substr(0, myId.length - 5) : null; + const controlId = myId ? myId.substring(0, myId.length - 5) : null; // Get the control described by this node. const elControl = controlId ? document.getElementById(controlId) : null; // Is this node hidden? diff --git a/build/media_source/system/js/joomla-dialog-autocreate.es6.js b/build/media_source/system/js/joomla-dialog-autocreate.es6.js index 57a2330232d63..f3ac1ba331a89 100644 --- a/build/media_source/system/js/joomla-dialog-autocreate.es6.js +++ b/build/media_source/system/js/joomla-dialog-autocreate.es6.js @@ -52,13 +52,40 @@ document.addEventListener('click', (event) => { triggerEl.JoomlaDialogInstance = popup; } + // Perform close when received any message + if ('closeOnMessage' in triggerEl.dataset) { + window.addEventListener('message', (message) => { + // Close when source Window match the iframe Window (for iframe) or current Window (for other popups) + if (message.source === (popup.getBodyContent().contentWindow || window)) { + popup.close(); + } + }); + } + + // Perform post-close actions popup.addEventListener('joomla-dialog:close', () => { + // Clean up after close Joomla.Modal.setCurrent(null); if (!cacheable) { popup.destroy(); } + + // Perform checkin request and page reload after close when needed + const { checkinUrl } = triggerEl.dataset; + const reloadOnClose = 'reloadOnClose' in triggerEl.dataset; + if (checkinUrl) { + Joomla.request({ url: checkinUrl, method: 'POST', promise: true }).then(() => { + if (reloadOnClose) { + window.location.reload(); + } + }); + } else if (reloadOnClose) { + window.location.reload(); + } }); + // Show the popup + popup.JoomlaDialogTrigger = triggerEl; Joomla.Modal.setCurrent(popup); popup.show(); }); diff --git a/build/media_source/system/js/joomla-dialog.w-c.es6.js b/build/media_source/system/js/joomla-dialog.w-c.es6.js index 8ddb0b3e9c376..b92d3903f2d3c 100644 --- a/build/media_source/system/js/joomla-dialog.w-c.es6.js +++ b/build/media_source/system/js/joomla-dialog.w-c.es6.js @@ -127,9 +127,17 @@ class JoomlaDialog extends HTMLElement { } }); + // Check class name if (config.className) { this.classList.add(...config.className.split(' ')); } + + // Check dataset properties + if (config.data) { + Object.entries(config.data).forEach(([k, v]) => { + this.dataset[k] = v; + }); + } } /** diff --git a/build/media_source/system/js/treeselectmenu.es6.js b/build/media_source/system/js/treeselectmenu.es6.js new file mode 100644 index 0000000000000..5f4326582319a --- /dev/null +++ b/build/media_source/system/js/treeselectmenu.es6.js @@ -0,0 +1,148 @@ +/** + * @copyright (C) 2012 Open Source Matters, Inc. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +const treeselectmenu = document.getElementById('treeselectmenu').innerHTML; +const direction = (document.dir !== undefined) ? document.dir : document.documentElement.dir; + +document.querySelectorAll('.treeselect li').forEach((li) => { + // Add icons + const icon = document.createElement('span'); + icon.classList.add('icon-'); + li.prepend(icon); + + if (li.querySelector('ul.treeselect-sub')) { + // Add classes to Expand/Collapse icons + li.querySelector('span.icon-').classList.add('treeselect-toggle', 'icon-chevron-down'); + + // Append drop down menu in nodes + li.querySelector('div.treeselect-item label').insertAdjacentHTML('afterend', treeselectmenu); + + const sub = li.querySelector('ul.treeselect-sub'); + if (!sub.querySelector('ul.treeselect-sub')) { + li.querySelector('div.treeselect-menu-expand').remove(); + } + } +}); + +// Takes care of the Expand/Collapse of a node +document.querySelectorAll('span.treeselect-toggle').forEach((toggle) => { + toggle.addEventListener('click', ({ target }) => { + const chevron = direction === 'rtl' ? 'icon-chevron-left' : 'icon-chevron-right'; + + // Take care of parent UL + const { parentNode } = target; + if (parentNode.querySelector('ul.treeselect-sub').classList.contains('hidden')) { + target.classList.remove(chevron); + target.classList.add('icon-chevron-down'); + parentNode.querySelectorAll('ul.treeselect-sub').forEach((item) => item.classList.remove('hidden')); + parentNode.querySelectorAll('ul.treeselect-sub i.treeselect-toggle').forEach((item) => { + item.classList.add('icon-chevron-down'); + item.classList.remove(chevron); + }); + } else { + target.classList.add(chevron); + target.classList.remove('icon-chevron-down'); + + parentNode.querySelectorAll('ul.treeselect-sub').forEach((item) => item.classList.add('hidden')); + parentNode.querySelectorAll('ul.treeselect-sub i.treeselect-toggle').forEach((item) => { + item.classList.remove('icon-chevron-down'); + item.classList.add(chevron); + }); + } + }); +}); + +// Takes care of the filtering +document.getElementById('treeselectfilter').addEventListener('keyup', ({ target }) => { + const noResults = document.getElementById('noresultsfound'); + const text = target.value.toLowerCase(); + let hidden = 0; + + noResults.classList.add('hidden'); + + const listItems = document.querySelectorAll('.treeselect li'); + listItems.forEach((item) => { + if (item.innerText.toLowerCase().includes(text)) { + item.classList.remove('d-none'); + } else { + item.classList.add('d-none'); + hidden += 1; + } + }); + + if (hidden === listItems.length) { + noResults.classList.remove('hidden'); + } +}); + +// Checks all checkboxes the tree +document.getElementById('treeCheckAll').addEventListener('click', () => { + document.querySelectorAll('.treeselect input').forEach((input) => { + input.checked = true; + }); +}); + +// Unchecks all checkboxes the tree +document.getElementById('treeUncheckAll').addEventListener('click', () => { + document.querySelectorAll('.treeselect input').forEach((input) => { + input.checked = false; + }); +}); + +// Expands all subtrees +document.getElementById('treeExpandAll').addEventListener('click', () => { + document.querySelectorAll('ul.treeselect ul.treeselect-sub').forEach((input) => input.classList.remove('hidden')); + document.querySelectorAll('ul.treeselect span.treeselect-toggle').forEach((item) => { + item.classList.remove('icon-chevron-right'); + item.classList.add('icon-chevron-down'); + }); +}); + +// Collapses all subtrees +document.getElementById('treeCollapseAll').addEventListener('click', () => { + document.querySelectorAll('ul.treeselect ul.treeselect-sub').forEach((input) => input.classList.add('hidden')); + document.querySelectorAll('ul.treeselect span.treeselect-toggle').forEach((item) => { + item.classList.remove('icon-chevron-down'); + item.classList.add('icon-chevron-right'); + }); +}); + +// Take care of children check/uncheck all +document.querySelectorAll('a.checkall').forEach((item) => { + item.addEventListener('click', ({ target }) => { + target.closest('li').querySelectorAll('ul.treeselect-sub input').forEach((input) => { + input.checked = true; + }); + }); +}); +document.querySelectorAll('a.uncheckall').forEach((item) => { + item.addEventListener('click', ({ target }) => { + target.closest('li').querySelectorAll('ul.treeselect-sub input').forEach((input) => { + input.checked = false; + }); + }); +}); + +// Take care of children toggle all +document.querySelectorAll('a.expandall').forEach((item) => { + item.addEventListener('click', ({ target }) => { + const parent = target.closest('ul'); + parent.querySelectorAll('ul.treeselect-sub').forEach((input) => input.classList.remove('hidden')); + parent.querySelectorAll('ul.treeselect-sub .treeselect-toggle').forEach((toggle) => { + toggle.classList.remove('icon-chevron-right'); + toggle.classList.add('icon-chevron-down'); + }); + }); +}); +document.querySelectorAll('a.collapseall').forEach((item) => { + item.addEventListener('click', ({ target }) => { + const parent = target.closest('ul'); + parent.querySelectorAll('ul.treeselect-sub').forEach((input) => input.classList.add('hidden')); + parent.querySelectorAll('ul.treeselect-sub .treeselect-toggle').forEach((toggle) => { + toggle.classList.remove('icon-chevron-down'); + toggle.classList.add('icon-chevron-right'); + }); + }); +}); diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss b/build/media_source/templates/administrator/atum/scss/blocks/_form.scss index 562d7757bdcc2..b86634cf04f2a 100644 --- a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss +++ b/build/media_source/templates/administrator/atum/scss/blocks/_form.scss @@ -194,13 +194,27 @@ div.subform-repeatable-group { top: 50%; right: 100%; padding: 0; - margin-top: -27px; border-radius: $border-radius 0 0 $border-radius; + transform: translateY(-50%); span { padding: 1.5rem .5rem; } } + &.group-move-up { + top: 50%; + right: 100%; + margin-top: -45px; + border-radius: 0; + transform: translateY(-50%); + } + &.group-move-down { + top: 50%; + right: 100%; + margin-top: 45px; + border-radius: 0; + transform: translateY(-50%); + } } } } diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss b/build/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss index 4aa0ad776c95d..2ad8727c176a9 100644 --- a/build/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss +++ b/build/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss @@ -12,8 +12,13 @@ padding: 2.5rem ($cassiopeia-grid-gutter * .5); } - a { + a:not(.btn), .btn-link { color: currentColor; + + &:hover, + &:focus { + color: var(--gray-200); + } } .mod-menu { diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss b/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss index c204209c31423..438cb3f7a2c16 100644 --- a/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss +++ b/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss @@ -148,3 +148,76 @@ fieldset { } } } + +// Subform - non table layout +div.subform-repeatable-group { + position: relative; + padding: 32px 32px 16px 28px; + margin-top: 20px; + margin-left: 32px; + border: $input-border-width solid $input-border-color; + @include border-radius($border-radius); + + > .control-group { + margin-top: 0; + } + + > .btn-toolbar { + + .btn-group { + position: static; + margin: 0; + } + + .btn { + position: absolute; + + &.group-add { + right: -1px; + bottom: -1px; + border-radius: $border-radius 0 $border-radius 0; + } + &.group-remove { + top: -1px; + right: -1px; + border-radius: 0 $border-radius 0 $border-radius; + } + &.group-move { + top: 50%; + right: 100%; + padding: 0; + border-radius: $border-radius 0 0 $border-radius; + transform: translateY(-50%); + + span { + padding: 1.5rem .5rem; + } + } + &.group-move-up { + top: 50%; + right: 100%; + margin-top: -45px; + border-radius: 0; + transform: translateY(-50%); + } + &.group-move-down { + top: 50%; + right: 100%; + margin-top: 45px; + border-radius: 0; + transform: translateY(-50%); + } + } + } +} + +// Highlight draggable section +.subform-repeatable-group[draggable="true"] { + // For non table layout + background-color: $teal; + + // For table layout + > td { + background-color: $teal; + } +} diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_global.scss b/build/media_source/templates/site/cassiopeia/scss/blocks/_global.scss index 091c61db051eb..0591114c5f42e 100644 --- a/build/media_source/templates/site/cassiopeia/scss/blocks/_global.scss +++ b/build/media_source/templates/site/cassiopeia/scss/blocks/_global.scss @@ -60,11 +60,6 @@ a { text-decoration: underline; } - &:not(.btn):hover, - &:not(.btn):focus { - color: var(--cassiopeia-color-hover); - } - &.navbar-brand { color: var(--cassiopeia-color-brand); } diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_header.scss b/build/media_source/templates/site/cassiopeia/scss/blocks/_header.scss index 19f6ccf2b6326..ece7792b12ba3 100644 --- a/build/media_source/templates/site/cassiopeia/scss/blocks/_header.scss +++ b/build/media_source/templates/site/cassiopeia/scss/blocks/_header.scss @@ -213,7 +213,7 @@ .mod-finder { color: $white; - a { + a:not(.jmodedit) { color: $white; &:hover, &:focus { diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss b/build/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss index ca9419b0cf57c..4162e96444b1f 100644 --- a/build/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss +++ b/build/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss @@ -15,8 +15,14 @@ .container-topbar, .container-below-top { color: $white; - a { + + a:not(.btn), .btn-link { color: currentColor; + + &:hover, + &:focus { + color: var(--gray-200); + } } } diff --git a/components/com_ajax/ajax.php b/components/com_ajax/ajax.php index f8aaceb484b36..4c06d66bf8cf5 100644 --- a/components/com_ajax/ajax.php +++ b/components/com_ajax/ajax.php @@ -204,14 +204,14 @@ // Return the results in the desired format switch ($format) { - // JSONinzed case 'json': + // JSONinzed echo new JsonResponse($results, null, false, $input->get('ignoreMessages', true, 'bool')); break; - // Handle as raw format default: + // Handle as raw format // Output exception if ($results instanceof Exception) { // Log an error @@ -222,7 +222,7 @@ // Echo exception type and message $out = \get_class($results) . ': ' . $results->getMessage(); - } elseif (is_scalar($results)) { + } elseif (\is_scalar($results)) { // Output string/ null $out = (string) $results; } else { diff --git a/components/com_contact/forms/form.xml b/components/com_contact/forms/form.xml index 55bbce03b3398..aef6261228901 100644 --- a/components/com_contact/forms/form.xml +++ b/components/com_contact/forms/form.xml @@ -111,6 +111,9 @@ diff --git a/components/com_contact/src/Model/CategoryModel.php b/components/com_contact/src/Model/CategoryModel.php index ca35c872dc04a..49db203cd8c5d 100644 --- a/components/com_contact/src/Model/CategoryModel.php +++ b/components/com_contact/src/Model/CategoryModel.php @@ -177,7 +177,37 @@ protected function getListQuery() ->whereIn($db->quoteName('a.access'), $groups); // Filter by category. - if ($categoryId = $this->getState('category.id')) { + $categoryId = (int) $this->getState('category.id'); + $includeSubcategories = (int) $this->getState('filter.max_category_levels', 1) !== 0; + + if ($includeSubcategories) { + $levels = (int) $this->getState('filter.max_category_levels', 1); + + // Create a subquery for the subcategory list + $subQuery = $db->getQuery(true) + ->select($db->quoteName('sub.id')) + ->from($db->quoteName('#__categories', 'sub')) + ->join( + 'INNER', + $db->quoteName('#__categories', 'this'), + $db->quoteName('sub.lft') . ' > ' . $db->quoteName('this.lft') + . ' AND ' . $db->quoteName('sub.rgt') . ' < ' . $db->quoteName('this.rgt') + ) + ->where($db->quoteName('this.id') . ' = :subCategoryId'); + + $query->bind(':subCategoryId', $categoryId, ParameterType::INTEGER); + + if ($levels >= 0) { + $subQuery->where($db->quoteName('sub.level') . ' <= ' . $db->quoteName('this.level') . ' + :levels'); + $query->bind(':levels', $levels, ParameterType::INTEGER); + } + + // Add the subquery to the main query + $query->where( + '(' . $db->quoteName('a.catid') . ' = :categoryId OR ' . $db->quoteName('a.catid') . ' IN (' . $subQuery . '))' + ); + $query->bind(':categoryId', $categoryId, ParameterType::INTEGER); + } else { $query->where($db->quoteName('a.catid') . ' = :acatid') ->whereIn($db->quoteName('c.access'), $groups); $query->bind(':acatid', $categoryId, ParameterType::INTEGER); @@ -302,6 +332,7 @@ protected function populateState($ordering = null, $direction = null) $id = $input->get('id', 0, 'int'); $this->setState('category.id', $id); + $this->setState('filter.max_category_levels', $params->get('maxLevel', 1)); $user = $this->getCurrentUser(); diff --git a/components/com_contact/tmpl/contact/default_address.php b/components/com_contact/tmpl/contact/default_address.php index 5c858ff9d4730..f90fee3ecfb28 100644 --- a/components/com_contact/tmpl/contact/default_address.php +++ b/components/com_contact/tmpl/contact/default_address.php @@ -152,7 +152,7 @@
    - item->webpage); ?> + escape(PunycodeHelper::urlToUTF8($this->item->webpage)); ?>
    diff --git a/components/com_contact/tmpl/contact/default_links.php b/components/com_contact/tmpl/contact/default_links.php index e1cb32b65cd8e..845307f0cd65d 100644 --- a/components/com_contact/tmpl/contact/default_links.php +++ b/components/com_contact/tmpl/contact/default_links.php @@ -10,8 +10,6 @@ defined('_JEXEC') or die; -use Joomla\CMS\Language\Text; - ?> + + category->getParams()->get('access-create')) : ?> + category, $this->category->params); ?> + params->def('show_pagination', 1) == 1 || ($this->params->get('show_pagination') == 2)) && ($this->pagination->pagesTotal > 1)) : ?>
    diff --git a/libraries/src/Application/BaseApplication.php b/libraries/src/Application/BaseApplication.php index 365bf91eb7662..fd5c8c081da2d 100644 --- a/libraries/src/Application/BaseApplication.php +++ b/libraries/src/Application/BaseApplication.php @@ -11,8 +11,6 @@ use Joomla\Application\AbstractApplication; use Joomla\CMS\Input\Input; -use Joomla\Event\DispatcherAwareInterface; -use Joomla\Event\DispatcherAwareTrait; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects @@ -30,9 +28,8 @@ * Application classes should directly be based on \Joomla\Application\AbstractApplication * don't use this class anymore */ -abstract class BaseApplication extends AbstractApplication implements DispatcherAwareInterface +abstract class BaseApplication extends AbstractApplication { - use DispatcherAwareTrait; use EventAware; use IdentityAware; diff --git a/libraries/src/Application/CMSApplication.php b/libraries/src/Application/CMSApplication.php index 6332f1e3e2906..2ea7735bbee92 100644 --- a/libraries/src/Application/CMSApplication.php +++ b/libraries/src/Application/CMSApplication.php @@ -312,7 +312,7 @@ public function execute() } // If gzip compression is enabled in configuration and the server is compliant, compress the output. - if ($this->get('gzip') && !ini_get('zlib.output_compression') && ini_get('output_handler') !== 'ob_gzhandler') { + if ($this->get('gzip') && !\ini_get('zlib.output_compression') && \ini_get('output_handler') !== 'ob_gzhandler') { $this->compress(); // Trigger the onAfterCompress event. @@ -1190,7 +1190,7 @@ public function setUserState($key, $value) public function toString($compress = false) { // Don't compress something if the server is going to do it anyway. Waste of time. - if ($compress && !ini_get('zlib.output_compression') && ini_get('output_handler') !== 'ob_gzhandler') { + if ($compress && !\ini_get('zlib.output_compression') && \ini_get('output_handler') !== 'ob_gzhandler') { $this->compress(); } diff --git a/libraries/src/Application/CliApplication.php b/libraries/src/Application/CliApplication.php index dfe6d2512b561..265087a1c0ae7 100644 --- a/libraries/src/Application/CliApplication.php +++ b/libraries/src/Application/CliApplication.php @@ -20,8 +20,6 @@ use Joomla\CMS\Language\Language; use Joomla\DI\Container; use Joomla\DI\ContainerAwareTrait; -use Joomla\Event\DispatcherAwareInterface; -use Joomla\Event\DispatcherAwareTrait; use Joomla\Event\DispatcherInterface; use Joomla\Input\Input; use Joomla\Registry\Registry; @@ -39,9 +37,8 @@ * @deprecated 4.0 will be removed in 6.0 * Use the ConsoleApplication instead */ -abstract class CliApplication extends AbstractApplication implements DispatcherAwareInterface, CMSApplicationInterface +abstract class CliApplication extends AbstractApplication implements CMSApplicationInterface { - use DispatcherAwareTrait; use EventAware; use IdentityAware; use ContainerAwareTrait; diff --git a/libraries/src/Application/ConsoleApplication.php b/libraries/src/Application/ConsoleApplication.php index f4f7ef722d1f2..a4f0e1f0e3bfd 100644 --- a/libraries/src/Application/ConsoleApplication.php +++ b/libraries/src/Application/ConsoleApplication.php @@ -21,8 +21,6 @@ use Joomla\Database\DatabaseAwareTrait; use Joomla\DI\Container; use Joomla\DI\ContainerAwareTrait; -use Joomla\Event\DispatcherAwareInterface; -use Joomla\Event\DispatcherAwareTrait; use Joomla\Event\DispatcherInterface; use Joomla\Input\Input; use Joomla\Registry\Registry; @@ -42,9 +40,8 @@ * * @since 4.0.0 */ -class ConsoleApplication extends Application implements DispatcherAwareInterface, CMSApplicationInterface +class ConsoleApplication extends Application implements CMSApplicationInterface { - use DispatcherAwareTrait; use EventAware; use IdentityAware; use ContainerAwareTrait; @@ -303,6 +300,7 @@ protected function getDefaultCommands(): array [ new Console\CleanCacheCommand(), new Console\CheckUpdatesCommand(), + new Console\CheckJoomlaUpdatesCommand(), new Console\RemoveOldFilesCommand(), new Console\AddUserCommand($this->getDatabase()), new Console\AddUserToGroupCommand($this->getDatabase()), diff --git a/libraries/src/Application/WebApplication.php b/libraries/src/Application/WebApplication.php index 5e1635ae9355f..968b31d6e3488 100644 --- a/libraries/src/Application/WebApplication.php +++ b/libraries/src/Application/WebApplication.php @@ -193,7 +193,7 @@ public function execute() } // If gzip compression is enabled in configuration and the server is compliant, compress the output. - if ($this->get('gzip') && !ini_get('zlib.output_compression') && (ini_get('output_handler') !== 'ob_gzhandler')) { + if ($this->get('gzip') && !\ini_get('zlib.output_compression') && (\ini_get('output_handler') !== 'ob_gzhandler')) { $this->compress(); } @@ -404,7 +404,7 @@ protected function loadSystemUris($requestUri = null) $uri = Uri::getInstance($this->get('uri.request')); // If we are working from a CGI SAPI with the 'cgi.fix_pathinfo' directive disabled we use PHP_SELF. - if (strpos(PHP_SAPI, 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI'])) { + if (strpos(PHP_SAPI, 'cgi') !== false && !\ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI'])) { // We aren't expecting PATH_INFO within PHP_SELF so this should work. $path = \dirname($_SERVER['PHP_SELF']); } else { diff --git a/libraries/src/Cache/Storage/ApcuStorage.php b/libraries/src/Cache/Storage/ApcuStorage.php index 1d701dc334831..3c34139445ede 100644 --- a/libraries/src/Cache/Storage/ApcuStorage.php +++ b/libraries/src/Cache/Storage/ApcuStorage.php @@ -220,11 +220,11 @@ public function gc() */ public static function isSupported() { - $supported = \extension_loaded('apcu') && ini_get('apc.enabled'); + $supported = \extension_loaded('apcu') && \ini_get('apc.enabled'); // If on the CLI interface, the `apc.enable_cli` option must also be enabled if ($supported && PHP_SAPI === 'cli') { - $supported = ini_get('apc.enable_cli'); + $supported = \ini_get('apc.enable_cli'); } return (bool) $supported; diff --git a/libraries/src/Component/Router/RouterLegacy.php b/libraries/src/Component/Router/RouterLegacy.php index cbdee4c6a834f..112f53cc4b7d9 100644 --- a/libraries/src/Component/Router/RouterLegacy.php +++ b/libraries/src/Component/Router/RouterLegacy.php @@ -17,6 +17,9 @@ * Default routing class for missing or legacy component routers * * @since 3.3 + * @deprecated 5.1 will be removed in 7.0 + * Will be removed without replacement. Use the class based router + * implementing the RouterInterface */ class RouterLegacy implements RouterInterface { diff --git a/libraries/src/Console/CheckJoomlaUpdatesCommand.php b/libraries/src/Console/CheckJoomlaUpdatesCommand.php index 46e78b141553b..12c02ec6ae865 100644 --- a/libraries/src/Console/CheckJoomlaUpdatesCommand.php +++ b/libraries/src/Console/CheckJoomlaUpdatesCommand.php @@ -9,6 +9,8 @@ namespace Joomla\CMS\Console; +use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Version; use Joomla\Component\Joomlaupdate\Administrator\Model\UpdateModel; use Joomla\Console\Command\AbstractCommand; use Symfony\Component\Console\Command\Command; @@ -33,7 +35,7 @@ class CheckJoomlaUpdatesCommand extends AbstractCommand * @var string * @since 4.0.0 */ - protected static $defaultName = 'core:check-updates'; + protected static $defaultName = 'core:update:check'; /** * Stores the Update Information @@ -43,6 +45,23 @@ class CheckJoomlaUpdatesCommand extends AbstractCommand */ private $updateInfo; + /** + * Command constructor (overridden to include the alias) + * + * @param string|null $name The name of the command; if the name is empty and no default is set, a name must be set in the configure() method + * + * @since 5.1.0 + * @deprecated 5.1.0 will be removed in 6.0 + * Use core:update:check instead of core:check-updates + * + */ + public function __construct(?string $name = null) + { + $this->setAliases(['core:check-updates']); + + parent::__construct($name); + } + /** * Initialise the command. * @@ -124,9 +143,25 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in { $symfonyStyle = new SymfonyStyle($input, $output); - $model = $this->getUpdateInfo(); - $data = $model->getUpdateInformation(); - $symfonyStyle->title('Joomla! Updates'); + $model = $this->getUpdateInfo(); + $data = $model->getUpdateInformation(); + $config = ComponentHelper::getParams('com_joomlaupdate'); + + $symfonyStyle->title('Joomla! Update Status'); + + switch ($config->get('updatesource', 'default')) { + case 'default': + case 'next': + case 'testing': + $symfonyStyle->writeln('You are on the ' . $config->get('updatesource', 'default') . ' update channel.'); + break; + case 'custom': + $symfonyStyle->writeln('You are on a custom update channel with the URL ' . $config->get('customurl') . '.'); + break; + } + + $version = new Version(); + $symfonyStyle->writeln('Your current Joomla version is ' . $version->getShortVersion() . '.'); if (!$data['hasUpdate']) { $symfonyStyle->success('You already have the latest Joomla version ' . $data['latest']); diff --git a/libraries/src/Console/CoreUpdateChannelCommand.php b/libraries/src/Console/CoreUpdateChannelCommand.php new file mode 100644 index 0000000000000..86a0ac44ac285 --- /dev/null +++ b/libraries/src/Console/CoreUpdateChannelCommand.php @@ -0,0 +1,156 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Console; + +use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Table\Table; +use Joomla\Component\Joomlaupdate\Administrator\Model\UpdateModel; +use Joomla\Console\Command\AbstractCommand; +use Joomla\Database\DatabaseInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Console command for managing the update channel for Joomla + * + * @since 5.1.0 + */ +class CoreUpdateChannelCommand extends AbstractCommand +{ + /** + * The default command name + * + * @var string + * @since 5.1.0 + */ + protected static $defaultName = 'core:update:channel'; + + /** + * @var DatabaseInterface + * @since 5.1.0 + */ + private $db; + + /** + * CoreUpdateChannelCommand constructor. + * + * @param DatabaseInterface $db Database Instance + * + * @since 5.1.0 + */ + public function __construct(DatabaseInterface $db) + { + $this->db = $db; + + parent::__construct(); + } + + /** + * Initialise the command. + * + * @return void + * + * @since 5.1.0 + */ + protected function configure(): void + { + $help = "%command.name% allows to manage the update channel for Joomla core updates. Returns the currently selected channel when called without any parameters, otherwise sets it. + \nUsage: php %command.full_name%"; + + $this->setDescription('Manage the update channel for Joomla core updates'); + $this->setHelp($help); + + $this->addArgument('channel', InputArgument::OPTIONAL, 'Name of the update channel [default, next, testing, custom]'); + $this->addOption('url', null, InputOption::VALUE_OPTIONAL, 'URL to update source. Only for custom update channel'); + } + + /** + * Internal function to execute the command. + * + * @param InputInterface $input The input to inject into the command. + * @param OutputInterface $output The output to inject into the command. + * + * @return integer The command exit code + * + * @since 5.1.0 + */ + protected function doExecute(InputInterface $input, OutputInterface $output): int + { + $symfonyStyle = new SymfonyStyle($input, $output); + + $params = ComponentHelper::getParams('com_joomlaupdate'); + $channel = $input->getArgument('channel'); + + if (!$channel) { + switch ($params->get('updatesource', 'default')) { + case 'default': + case 'next': + case 'testing': + $symfonyStyle->writeln('You are on the "' . $params->get('updatesource', 'default') . '" update channel.'); + break; + case 'custom': + $symfonyStyle->writeln('You are on a "custom" update channel with the URL ' . $params->get('customurl') . '.'); + break; + default: + $symfonyStyle->error('The update channel is set to the invalid value \'' . $params->get('updatesource') . '\'!'); + return Command::FAILURE; + } + + return Command::SUCCESS; + } + + if (!\in_array($channel, ['default', 'next', 'testing', 'custom'])) { + $symfonyStyle->error('The given update channel is invalid. Please only choose from [default, next, testing, custom].'); + + return Command::FAILURE; + } + + $params->set('updatesource', $channel); + + if ($channel == 'custom') { + $url = $input->getOption('url'); + + if (!$url) { + $symfonyStyle->error('When using the custom update channel, you have to provide a valid URL.'); + + return Command::FAILURE; + } + + $params->set('customurl', $url); + } + + // Storing the parameters in the DB + $table = Table::getInstance('extension'); + $table->load(['type' => 'component', 'element' => 'com_joomlaupdate']); + $table->params = $params->toString(); + $table->store(); + + /** @var UpdateModel $updatemodel */ + $app = $this->getApplication(); + $updatemodel = $app->bootComponent('com_joomlaupdate')->getMVCFactory($app)->createModel('Update', 'Administrator'); + $updatemodel->applyUpdateSite(); + + if ($channel == 'custom') { + $symfonyStyle->success('The update channel for this site has been set to the custom url "' . $params->get('customurl') . '".'); + } else { + $symfonyStyle->success('The update channel for this site has been set to "' . $params->get('updatesource', 'default') . '".'); + } + + return Command::SUCCESS; + } +} diff --git a/libraries/src/Console/UpdateCoreCommand.php b/libraries/src/Console/UpdateCoreCommand.php index 787ecd1ad1031..8a28fe15aab31 100644 --- a/libraries/src/Console/UpdateCoreCommand.php +++ b/libraries/src/Console/UpdateCoreCommand.php @@ -128,9 +128,7 @@ public function __construct(DatabaseInterface $db) */ private function configureIO(InputInterface $input, OutputInterface $output) { - ProgressBar::setFormatDefinition('custom', ' %current%/%max% -- %message%'); - $this->progressBar = new ProgressBar($output, 8); - $this->progressBar->setFormat('custom'); + $this->progressBar = new ProgressBar($output, 9); $this->cliInput = $input; $this->ioStyle = new SymfonyStyle($input, $output); @@ -157,7 +155,7 @@ public function doExecute(InputInterface $input, OutputInterface $output): int $this->configureIO($input, $output); $this->ioStyle->title('Updating Joomla'); - $this->progressBar->setMessage("Starting up ..."); + $this->ioStyle->writeln("Starting up ..."); $this->progressBar->start(); $model = $this->getUpdateModel(); @@ -175,8 +173,11 @@ public function doExecute(InputInterface $input, OutputInterface $output): int $this->setUpdateInfo($model->getUpdateInformation()); + $this->progressBar->clear(); + $this->ioStyle->writeln('Running checks ...'); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage('Running checks ...'); + if (!$this->updateInfo['hasUpdate']) { $this->progressBar->finish(); @@ -185,8 +186,11 @@ public function doExecute(InputInterface $input, OutputInterface $output): int return self::ERR_CHECKS_FAILED; } + $this->progressBar->clear(); + $this->ioStyle->writeln('Check Database Table Structure...'); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage('Check Database Table Structure...'); + $errors = $this->checkSchema(); @@ -198,8 +202,10 @@ public function doExecute(InputInterface $input, OutputInterface $output): int return self::ERR_CHECKS_FAILED; } + $this->progressBar->clear(); + $this->ioStyle->writeln('Starting Joomla! update ...'); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage('Starting Joomla! update ...'); if ($this->updateJoomlaCore($model)) { $this->progressBar->finish(); @@ -251,17 +257,25 @@ private function updateJoomlaCore($updatemodel): bool $updateInformation = $this->updateInfo; if (!empty($updateInformation['hasUpdate'])) { + $this->progressBar->clear(); + $this->ioStyle->writeln("Processing update package ..."); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage("Processing update package ..."); + $package = $this->processUpdatePackage($updateInformation); + $this->progressBar->clear(); + $this->ioStyle->writeln("Finalizing update ..."); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage("Finalizing update ..."); + $result = $updatemodel->finaliseUpgrade(); if ($result) { + $this->progressBar->clear(); + $this->ioStyle->writeln("Cleaning up ..."); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage("Cleaning up ..."); // Remove the administrator/cache/autoload_psr4.php file $autoloadFile = JPATH_CACHE . '/autoload_psr4.php'; @@ -357,19 +371,28 @@ public function processUpdatePackage($updateInformation) return false; } + $this->progressBar->clear(); + $this->ioStyle->writeln("Downloading update package ..."); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage("Downloading update package ..."); + $file = $this->downloadFile($updateInformation['object']->downloadurl->_data); $tmpPath = $this->getApplication()->get('tmp_path'); $updatePackage = $tmpPath . '/' . $file; + $this->progressBar->clear(); + $this->ioStyle->writeln("Extracting update package ..."); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage("Extracting update package ..."); + $package = $this->extractFile($updatePackage); + $this->progressBar->clear(); + $this->ioStyle->writeln("Copying files ..."); + $this->progressBar->display(); $this->progressBar->advance(); - $this->progressBar->setMessage("Copying files ..."); + $this->copyFileTo($package['extractdir'], JPATH_BASE); return ['file' => $updatePackage, 'extractdir' => $package['extractdir']]; diff --git a/libraries/src/Document/Renderer/Feed/AtomRenderer.php b/libraries/src/Document/Renderer/Feed/AtomRenderer.php index 3598db8a3e3a9..3519cb4f7a567 100644 --- a/libraries/src/Document/Renderer/Feed/AtomRenderer.php +++ b/libraries/src/Document/Renderer/Feed/AtomRenderer.php @@ -86,7 +86,7 @@ public function render($name = '', $params = null, $content = null) $feed .= ">\n"; $feed .= " " . $feed_title . "\n"; - $feed .= " " . htmlspecialchars($data->getDescription(), ENT_COMPAT, 'UTF-8') . "\n"; + $feed .= " " . htmlspecialchars($data->getDescription() ?? '', ENT_COMPAT, 'UTF-8') . "\n"; if (!empty($data->category)) { if (\is_array($data->category)) { diff --git a/libraries/src/Document/Renderer/Html/MetasRenderer.php b/libraries/src/Document/Renderer/Html/MetasRenderer.php index 5c924eeea7364..26b0b082e8595 100644 --- a/libraries/src/Document/Renderer/Html/MetasRenderer.php +++ b/libraries/src/Document/Renderer/Html/MetasRenderer.php @@ -14,7 +14,7 @@ use Joomla\CMS\Factory; use Joomla\CMS\Helper\TagsHelper; use Joomla\CMS\Uri\Uri; -use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface; +use Joomla\CMS\WebAsset\WebAssetManager; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects @@ -51,12 +51,12 @@ public function render($head, $params = [], $content = null) $app = Factory::getApplication(); $wa = $this->_doc->getWebAssetManager(); - // Check for AttachBehavior and web components - foreach ($wa->getAssets('script', true) as $asset) { - if ($asset instanceof WebAssetAttachBehaviorInterface) { - $asset->onAttachCallback($this->_doc); - } - } + // Add a dummy asset for script options, this will prevent WebAssetManager from extra re-calculation later on. + $scriptOptionsAsset = $wa->addInline('script', '', ['name' => 'joomla.script.options'], [], ['core']) + ->getAsset('script', 'joomla.script.options'); + + // Check for AttachBehavior + $onAttachCallCache = WebAssetManager::callOnAttachCallback($wa->getAssets('script', true), $this->_doc); // Trigger the onBeforeCompileHead event $app->getDispatcher()->dispatch( @@ -64,20 +64,28 @@ public function render($head, $params = [], $content = null) new BeforeCompileHeadEvent('onBeforeCompileHead', ['subject' => $app, 'document' => $this->_doc]) ); + // Re-Check for AttachBehavior for newly added assets + WebAssetManager::callOnAttachCallback($wa->getAssets('script', true), $this->_doc, $onAttachCallCache); + // Add Script Options as inline asset $scriptOptions = $this->_doc->getScriptOptions(); if ($scriptOptions) { + // Overriding ScriptOptions asset is not allowed + if ($scriptOptionsAsset !== $wa->getAsset('script', 'joomla.script.options')) { + throw new \RuntimeException('Detected an override for "joomla.script.options" asset'); + } + $jsonFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | (JDEBUG ? JSON_PRETTY_PRINT : 0); $jsonOptions = json_encode($scriptOptions, $jsonFlags); - $jsonOptions = $jsonOptions ?: '{}'; - - $wa->addInlineScript( - $jsonOptions, - ['name' => 'joomla.script.options', 'position' => 'before'], - ['type' => 'application/json', 'class' => 'joomla-script-options new'], - ['core'] - ); + + // Set content and update attributes of dummy asset to correct ones + $scriptOptionsAsset->setOption('content', $jsonOptions ?: '{}'); + $scriptOptionsAsset->setOption('position', 'before'); + $scriptOptionsAsset->setAttribute('type', 'application/json'); + $scriptOptionsAsset->setAttribute('class', 'joomla-script-options new'); + } else { + $wa->disableScript('joomla.script.options'); } // Lock the AssetManager diff --git a/libraries/src/Document/Renderer/Html/ScriptsRenderer.php b/libraries/src/Document/Renderer/Html/ScriptsRenderer.php index a9ffb25cf069b..65cc0674444d5 100644 --- a/libraries/src/Document/Renderer/Html/ScriptsRenderer.php +++ b/libraries/src/Document/Renderer/Html/ScriptsRenderer.php @@ -315,7 +315,7 @@ private function renderAttributes(array $attributes): string if (!($this->_doc->isHtml5() && $isNoValueAttrib)) { // Json encode value if it's an array. - $value = !is_scalar($value) ? json_encode($value) : $value; + $value = !\is_scalar($value) ? json_encode($value) : $value; $buffer .= '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"'; } diff --git a/libraries/src/Document/Renderer/Html/StylesRenderer.php b/libraries/src/Document/Renderer/Html/StylesRenderer.php index 39cef83b2a4ec..e1cd1a98aefa3 100644 --- a/libraries/src/Document/Renderer/Html/StylesRenderer.php +++ b/libraries/src/Document/Renderer/Html/StylesRenderer.php @@ -313,7 +313,7 @@ private function renderAttributes(array $attributes): string if (!($this->_doc->isHtml5() && $isNoValueAttrib)) { // Json encode value if it's an array. - $value = !is_scalar($value) ? json_encode($value) : $value; + $value = !\is_scalar($value) ? json_encode($value) : $value; $buffer .= '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"'; } diff --git a/libraries/src/Error/JsonApi/AuthenticationFailedExceptionHandler.php b/libraries/src/Error/JsonApi/AuthenticationFailedExceptionHandler.php index 2658b36e80f3f..8286b308d6710 100644 --- a/libraries/src/Error/JsonApi/AuthenticationFailedExceptionHandler.php +++ b/libraries/src/Error/JsonApi/AuthenticationFailedExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\Access\Exception\AuthenticationFailed; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/CheckinCheckoutExceptionHandler.php b/libraries/src/Error/JsonApi/CheckinCheckoutExceptionHandler.php index dafb3523a214f..87d949991d8ae 100644 --- a/libraries/src/Error/JsonApi/CheckinCheckoutExceptionHandler.php +++ b/libraries/src/Error/JsonApi/CheckinCheckoutExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\MVC\Controller\Exception\CheckinCheckout; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/InvalidParameterExceptionHandler.php b/libraries/src/Error/JsonApi/InvalidParameterExceptionHandler.php index 73f8c0b312b45..41cce1572de3a 100644 --- a/libraries/src/Error/JsonApi/InvalidParameterExceptionHandler.php +++ b/libraries/src/Error/JsonApi/InvalidParameterExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Tobscure\JsonApi\Exception\Handler\ResponseBag; // phpcs:disable PSR1.Files.SideEffects diff --git a/libraries/src/Error/JsonApi/InvalidRouteExceptionHandler.php b/libraries/src/Error/JsonApi/InvalidRouteExceptionHandler.php index f47dc12c6607d..05501b5f8841f 100644 --- a/libraries/src/Error/JsonApi/InvalidRouteExceptionHandler.php +++ b/libraries/src/Error/JsonApi/InvalidRouteExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\Router\Exception\RouteNotFoundException; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/NotAcceptableExceptionHandler.php b/libraries/src/Error/JsonApi/NotAcceptableExceptionHandler.php index 75e8e1f8474c0..98bdf1580f891 100644 --- a/libraries/src/Error/JsonApi/NotAcceptableExceptionHandler.php +++ b/libraries/src/Error/JsonApi/NotAcceptableExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\Application\Exception\NotAcceptable; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/NotAllowedExceptionHandler.php b/libraries/src/Error/JsonApi/NotAllowedExceptionHandler.php index 662d153fedefd..23fde71a0cb15 100644 --- a/libraries/src/Error/JsonApi/NotAllowedExceptionHandler.php +++ b/libraries/src/Error/JsonApi/NotAllowedExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\Access\Exception\NotAllowed; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/ResourceNotFoundExceptionHandler.php b/libraries/src/Error/JsonApi/ResourceNotFoundExceptionHandler.php index 238ab9642a4a0..d05952a4c6ebe 100644 --- a/libraries/src/Error/JsonApi/ResourceNotFoundExceptionHandler.php +++ b/libraries/src/Error/JsonApi/ResourceNotFoundExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\MVC\Controller\Exception\ResourceNotFound; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/SaveExceptionHandler.php b/libraries/src/Error/JsonApi/SaveExceptionHandler.php index 7a203b4a64f1c..b29f80397b83d 100644 --- a/libraries/src/Error/JsonApi/SaveExceptionHandler.php +++ b/libraries/src/Error/JsonApi/SaveExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\MVC\Controller\Exception\Save; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Error/JsonApi/SendEmailExceptionHandler.php b/libraries/src/Error/JsonApi/SendEmailExceptionHandler.php index 44ca11f2a8f00..d8f3200424e7a 100644 --- a/libraries/src/Error/JsonApi/SendEmailExceptionHandler.php +++ b/libraries/src/Error/JsonApi/SendEmailExceptionHandler.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Error\JsonApi; -use Exception; use Joomla\CMS\MVC\Controller\Exception\SendEmail; use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface; use Tobscure\JsonApi\Exception\Handler\ResponseBag; diff --git a/libraries/src/Event/CoreEventAware.php b/libraries/src/Event/CoreEventAware.php index 89db25e349884..f72cafcbbfbc8 100644 --- a/libraries/src/Event/CoreEventAware.php +++ b/libraries/src/Event/CoreEventAware.php @@ -193,6 +193,10 @@ trait CoreEventAware 'onPrivacyExportRequest' => Privacy\ExportRequestEvent::class, 'onPrivacyCanRemoveData' => Privacy\CanRemoveDataEvent::class, 'onPrivacyRemoveData' => Privacy\RemoveDataEvent::class, + // PageCache + 'onPageCacheSetCaching' => PageCache\SetCachingEvent::class, + 'onPageCacheGetKey' => PageCache\GetKeyEvent::class, + 'onPageCacheIsExcluded' => PageCache\IsExcludedEvent::class, ]; /** diff --git a/libraries/src/Event/PageCache/GetKeyEvent.php b/libraries/src/Event/PageCache/GetKeyEvent.php new file mode 100644 index 0000000000000..7bd4d2244c842 --- /dev/null +++ b/libraries/src/Event/PageCache/GetKeyEvent.php @@ -0,0 +1,29 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Event\PageCache; + +use Joomla\CMS\Event\Result\ResultAware; +use Joomla\CMS\Event\Result\ResultAwareInterface; +use Joomla\CMS\Event\Result\ResultTypeStringAware; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for PageCache events + * + * @since __DEPLOY_VERSION__ + */ +class GetKeyEvent extends PageCacheEvent implements ResultAwareInterface +{ + use ResultAware; + use ResultTypeStringAware; +} diff --git a/libraries/src/Event/PageCache/IsExcludedEvent.php b/libraries/src/Event/PageCache/IsExcludedEvent.php new file mode 100644 index 0000000000000..bfa6d1db7cd4a --- /dev/null +++ b/libraries/src/Event/PageCache/IsExcludedEvent.php @@ -0,0 +1,29 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Event\PageCache; + +use Joomla\CMS\Event\Result\ResultAware; +use Joomla\CMS\Event\Result\ResultAwareInterface; +use Joomla\CMS\Event\Result\ResultTypeBooleanAware; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for PageCache events + * + * @since __DEPLOY_VERSION__ + */ +class IsExcludedEvent extends PageCacheEvent implements ResultAwareInterface +{ + use ResultAware; + use ResultTypeBooleanAware; +} diff --git a/libraries/src/Event/PageCache/PageCacheEvent.php b/libraries/src/Event/PageCache/PageCacheEvent.php new file mode 100644 index 0000000000000..d7662c30d55f6 --- /dev/null +++ b/libraries/src/Event/PageCache/PageCacheEvent.php @@ -0,0 +1,25 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Event\PageCache; + +use Joomla\CMS\Event\AbstractImmutableEvent; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for PageCache events + * + * @since __DEPLOY_VERSION__ + */ +abstract class PageCacheEvent extends AbstractImmutableEvent +{ +} diff --git a/libraries/src/Event/PageCache/SetCachingEvent.php b/libraries/src/Event/PageCache/SetCachingEvent.php new file mode 100644 index 0000000000000..7c8f380a71303 --- /dev/null +++ b/libraries/src/Event/PageCache/SetCachingEvent.php @@ -0,0 +1,29 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Event\PageCache; + +use Joomla\CMS\Event\Result\ResultAware; +use Joomla\CMS\Event\Result\ResultAwareInterface; +use Joomla\CMS\Event\Result\ResultTypeBooleanAware; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for PageCache events + * + * @since __DEPLOY_VERSION__ + */ +class SetCachingEvent extends PageCacheEvent implements ResultAwareInterface +{ + use ResultAware; + use ResultTypeBooleanAware; +} diff --git a/libraries/src/Event/Plugin/AjaxEvent.php b/libraries/src/Event/Plugin/AjaxEvent.php index 06b3efa3defca..2db78c940983d 100644 --- a/libraries/src/Event/Plugin/AjaxEvent.php +++ b/libraries/src/Event/Plugin/AjaxEvent.php @@ -86,7 +86,7 @@ public function addResult($data): void if (\is_array($this->arguments['result'])) { $this->arguments['result'][] = $data; - } elseif (is_scalar($this->arguments['result']) && is_scalar($data)) { + } elseif (\is_scalar($this->arguments['result']) && \is_scalar($data)) { $this->arguments['result'] .= $data; } else { throw new \UnexpectedValueException('Mixed data in the result for the event ' . $this->getName()); diff --git a/libraries/src/Event/Result/ResultAware.php b/libraries/src/Event/Result/ResultAware.php index 66c2be1b4f3ca..07c528c259aac 100644 --- a/libraries/src/Event/Result/ResultAware.php +++ b/libraries/src/Event/Result/ResultAware.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Event\Result; -use BadMethodCallException; use Joomla\Event\Event as BaseEvent; // phpcs:disable PSR1.Files.SideEffects diff --git a/libraries/src/Event/Router/AfterInitialiseRouterEvent.php b/libraries/src/Event/Router/AfterInitialiseRouterEvent.php new file mode 100644 index 0000000000000..2da380b55219f --- /dev/null +++ b/libraries/src/Event/Router/AfterInitialiseRouterEvent.php @@ -0,0 +1,24 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Event\Router; + +// phpcs:disable PSR1.Files.SideEffects + +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Event class for AfterInitialiseRouter event + * + * @since __DEPLOY_VERSION__ + */ +class AfterInitialiseRouterEvent extends RouterEvent +{ +} diff --git a/libraries/src/Event/Router/RouterEvent.php b/libraries/src/Event/Router/RouterEvent.php new file mode 100644 index 0000000000000..67ecf297da5c5 --- /dev/null +++ b/libraries/src/Event/Router/RouterEvent.php @@ -0,0 +1,70 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\Event\Router; + +use Joomla\CMS\Event\AbstractImmutableEvent; +use Joomla\CMS\Router\Router; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for Application's Router events + * + * @since __DEPLOY_VERSION__ + */ +abstract class RouterEvent extends AbstractImmutableEvent +{ + /** + * Constructor. + * + * @param string $name The event name. + * @param array $arguments The event arguments. + * + * @throws \BadMethodCallException + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($name, array $arguments = []) + { + if (!\array_key_exists('router', $arguments)) { + throw new \BadMethodCallException("Argument 'router' of event {$name} is required but has not been provided"); + } + + parent::__construct($name, $arguments); + } + + /** + * Setter for the router argument. + * + * @param Router $value The value to set + * + * @return Router + * + * @since __DEPLOY_VERSION__ + */ + protected function onSetRouter(Router $value): Router + { + return $value; + } + + /** + * Get the event's router object + * + * @return Router + * + * @since __DEPLOY_VERSION__ + */ + public function getRouter(): Router + { + return $this->arguments['router']; + } +} diff --git a/libraries/src/Event/Table/AfterMoveEvent.php b/libraries/src/Event/Table/AfterMoveEvent.php index a892d6ea35115..97d6a5bbc8595 100644 --- a/libraries/src/Event/Table/AfterMoveEvent.php +++ b/libraries/src/Event/Table/AfterMoveEvent.php @@ -9,8 +9,6 @@ namespace Joomla\CMS\Event\Table; -use stdClass; - // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects diff --git a/libraries/src/Extension/ExtensionHelper.php b/libraries/src/Extension/ExtensionHelper.php index bbe6bc2f5ee9a..752c51f24bc9b 100644 --- a/libraries/src/Extension/ExtensionHelper.php +++ b/libraries/src/Extension/ExtensionHelper.php @@ -277,8 +277,10 @@ class ExtensionHelper ['plugin', 'multilang', 'sampledata', 0], // Core plugin extensions - schemaorg + ['plugin', 'article', 'schemaorg', 0], ['plugin', 'blogposting', 'schemaorg', 0], ['plugin', 'book', 'schemaorg', 0], + ['plugin', 'custom', 'schemaorg', 0], ['plugin', 'event', 'schemaorg', 0], ['plugin', 'jobposting', 'schemaorg', 0], ['plugin', 'organization', 'schemaorg', 0], @@ -401,15 +403,26 @@ public static function getCoreExtensionIds() ->select($db->quoteName('extension_id')) ->from($db->quoteName('#__extensions')); + $values = []; + foreach (self::$coreExtensions as $extension) { - $values = $query->bindArray($extension, [ParameterType::STRING, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER]); - $query->where( - '(' . $db->quoteName('type') . ' = ' . $values[0] . ' AND ' . $db->quoteName('element') . ' = ' . $values[1] - . ' AND ' . $db->quoteName('folder') . ' = ' . $values[2] . ' AND ' . $db->quoteName('client_id') . ' = ' . $values[3] . ')', - 'OR' - ); + $values[] = $extension[0] . '|' . $extension[1] . '|' . $extension[2] . '|' . $extension[3]; } + $query->whereIn( + $query->concatenate( + [ + $db->quoteName('type'), + $db->quoteName('element'), + $db->quoteName('folder'), + $db->quoteName('client_id'), + ], + '|' + ), + $values, + ParameterType::STRING + ); + $db->setQuery($query); self::$coreExtensionIds = $db->loadColumn(); diff --git a/libraries/src/Factory.php b/libraries/src/Factory.php index fba5557f9d0de..36ada209a87c1 100644 --- a/libraries/src/Factory.php +++ b/libraries/src/Factory.php @@ -614,6 +614,7 @@ protected static function createContainer(): Container ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Dispatcher()) ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Document()) ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Form()) + ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Http()) ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Input()) ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Logger()) ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Language()) diff --git a/libraries/src/Filesystem/File.php b/libraries/src/Filesystem/File.php index 38be4f957cef6..020d7506d6a28 100644 --- a/libraries/src/Filesystem/File.php +++ b/libraries/src/Filesystem/File.php @@ -228,9 +228,9 @@ public static function canFlushFileCache() } if ( - ini_get('opcache.enable') + \ini_get('opcache.enable') && \function_exists('opcache_invalidate') - && (!ini_get('opcache.restrict_api') || stripos(realpath($_SERVER['SCRIPT_FILENAME']), ini_get('opcache.restrict_api')) === 0) + && (!\ini_get('opcache.restrict_api') || stripos(realpath($_SERVER['SCRIPT_FILENAME']), \ini_get('opcache.restrict_api')) === 0) ) { static::$canFlushFileCache = true; } else { @@ -404,7 +404,7 @@ public static function move($src, $dest, $path = '', $useStreams = false) public static function write($file, $buffer, $useStreams = false) { if (\function_exists('set_time_limit')) { - set_time_limit(ini_get('max_execution_time')); + set_time_limit(\ini_get('max_execution_time')); } // If the destination directory doesn't exist we need to create it @@ -465,7 +465,7 @@ public static function write($file, $buffer, $useStreams = false) public static function append($file, $buffer, $useStreams = false) { if (\function_exists('set_time_limit')) { - set_time_limit(ini_get('max_execution_time')); + set_time_limit(\ini_get('max_execution_time')); } // If the file doesn't exist, just write instead of append diff --git a/libraries/src/Filesystem/FilesystemHelper.php b/libraries/src/Filesystem/FilesystemHelper.php index 032c8cd64cd10..9d70f3c273e10 100644 --- a/libraries/src/Filesystem/FilesystemHelper.php +++ b/libraries/src/Filesystem/FilesystemHelper.php @@ -309,8 +309,8 @@ public static function fileUploadMaxSize($unitOutput = true) static $output_type = true; if ($max_size === false || $output_type != $unitOutput) { - $max_size = self::parseSize(ini_get('post_max_size')); - $upload_max = self::parseSize(ini_get('upload_max_filesize')); + $max_size = self::parseSize(\ini_get('post_max_size')); + $upload_max = self::parseSize(\ini_get('upload_max_filesize')); if ($upload_max > 0 && ($upload_max < $max_size || $max_size == 0)) { $max_size = $upload_max; diff --git a/libraries/src/Filesystem/Folder.php b/libraries/src/Filesystem/Folder.php index e126b3f14c3f9..73a27b5da87d0 100644 --- a/libraries/src/Filesystem/Folder.php +++ b/libraries/src/Filesystem/Folder.php @@ -47,7 +47,7 @@ abstract class Folder public static function copy($src, $dest, $path = '', $force = false, $useStreams = false) { if (\function_exists('set_time_limit')) { - set_time_limit(ini_get('max_execution_time')); + set_time_limit(\ini_get('max_execution_time')); } $FTPOptions = ClientHelper::getCredentials('ftp'); @@ -219,7 +219,7 @@ public static function create($path = '', $mode = 0755) $ftp->chmod($path, $mode); } else { // We need to get and explode the open_basedir paths - $obd = ini_get('open_basedir'); + $obd = \ini_get('open_basedir'); // If open_basedir is set we need to get the open_basedir that the path is in if ($obd != null) { @@ -288,7 +288,7 @@ public static function create($path = '', $mode = 0755) public static function delete($path) { if (\function_exists('set_time_limit')) { - set_time_limit(ini_get('max_execution_time')); + set_time_limit(\ini_get('max_execution_time')); } // Sanity check @@ -571,7 +571,7 @@ public static function folders( protected static function _items($path, $filter, $recurse, $full, $exclude, $excludeFilterString, $findFiles) { if (\function_exists('set_time_limit')) { - set_time_limit(ini_get('max_execution_time')); + set_time_limit(\ini_get('max_execution_time')); } $arr = []; diff --git a/libraries/src/Filesystem/Path.php b/libraries/src/Filesystem/Path.php index 744dd87b49735..365028bb4c92b 100644 --- a/libraries/src/Filesystem/Path.php +++ b/libraries/src/Filesystem/Path.php @@ -62,7 +62,7 @@ public static function check($path, $basePath = '') public static function isOwner($path) { $tmp = md5(random_bytes(16)); - $ssp = ini_get('session.save_path'); + $ssp = \ini_get('session.save_path'); $jtp = JPATH_SITE . '/tmp'; // Try to find a writable directory diff --git a/libraries/src/Filesystem/Stream.php b/libraries/src/Filesystem/Stream.php index c934813bb2402..a0d57fe1c3856 100644 --- a/libraries/src/Filesystem/Stream.php +++ b/libraries/src/Filesystem/Stream.php @@ -254,24 +254,24 @@ public function open( // Capture PHP errors $php_errormsg = 'Error Unknown whilst opening a file'; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); // Decide which context to use: switch ($this->processingmethod) { - // Gzip doesn't support contexts or streams case 'gz': + // Gzip doesn't support contexts or streams $this->fh = gzopen($filename, $mode, $useIncludePath); break; - // Bzip2 is much like gzip except it doesn't use the include path case 'bz': + // Bzip2 is much like gzip except it doesn't use the include path $this->fh = bzopen($filename, $mode); break; - // Fopen can handle streams case 'f': default: + // Fopen can handle streams // One supplied at open; overrides everything if ($context) { $this->fh = fopen($filename, $mode, $useIncludePath, $context); @@ -324,7 +324,7 @@ public function close() // Capture PHP errors $php_errormsg = 'Error Unknown'; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); switch ($this->processingmethod) { @@ -382,7 +382,7 @@ public function eof() // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); switch ($this->processingmethod) { @@ -430,7 +430,7 @@ public function filesize() // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $res = @filesize($this->filename); @@ -493,7 +493,7 @@ public function gets($length = 0) // Capture PHP errors $php_errormsg = 'Error Unknown'; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); switch ($this->processingmethod) { @@ -560,7 +560,7 @@ public function read($length = 0) // Capture PHP errors $php_errormsg = 'Error Unknown'; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $remaining = $length; @@ -639,7 +639,7 @@ public function seek($offset, $whence = SEEK_SET) // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); switch ($this->processingmethod) { @@ -688,7 +688,7 @@ public function tell() // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); switch ($this->processingmethod) { @@ -760,7 +760,7 @@ public function write(&$string, $length = 0, $chunk = 0) // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $remaining = $length; $start = 0; @@ -828,7 +828,7 @@ public function chmod($filename = '', $mode = 0) // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $sch = parse_url($filename, PHP_URL_SCHEME); @@ -994,7 +994,7 @@ public function applyContextToStream() if ($this->fh) { // Capture PHP errors $php_errormsg = 'Unknown error setting context option'; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $retval = @stream_context_set_option($this->fh, $this->contextOptions); @@ -1032,7 +1032,7 @@ public function appendFilter($filterName, $readWrite = STREAM_FILTER_READ, $para if ($this->fh) { // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $res = @stream_filter_append($this->fh, $filterName, $readWrite, $params); @@ -1072,7 +1072,7 @@ public function prependFilter($filterName, $readWrite = STREAM_FILTER_READ, $par if ($this->fh) { // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $res = @stream_filter_prepend($this->fh, $filterName, $readWrite, $params); @@ -1109,7 +1109,7 @@ public function removeFilter(&$resource, $byindex = false) { // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); if ($byindex) { @@ -1148,7 +1148,7 @@ public function copy($src, $dest, $context = null, $usePrefix = true, $relative { // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $chmodDest = $this->_getFilename($dest, 'w', $usePrefix, $relative); @@ -1201,7 +1201,7 @@ public function move($src, $dest, $context = null, $usePrefix = true, $relative { // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $src = $this->_getFilename($src, 'w', $usePrefix, $relative); @@ -1249,7 +1249,7 @@ public function delete($filename, $context = null, $usePrefix = true, $relative { // Capture PHP errors $php_errormsg = ''; - $track_errors = ini_get('track_errors'); + $track_errors = \ini_get('track_errors'); ini_set('track_errors', true); $filename = $this->_getFilename($filename, 'w', $usePrefix, $relative); diff --git a/libraries/src/Form/Field/CalendarField.php b/libraries/src/Form/Field/CalendarField.php index c1a839ab225b6..0c776581af4e8 100644 --- a/libraries/src/Form/Field/CalendarField.php +++ b/libraries/src/Form/Field/CalendarField.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Form\Field; -use DateTime; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\Language\Text; @@ -327,7 +326,7 @@ protected function getInput() $this->value = ''; } - return $this->getRenderer($this->layout)->render($this->getLayoutData()); + return $this->getRenderer($this->layout)->render($this->collectLayoutData()); } /** @@ -415,8 +414,8 @@ public function filter($value, $group = null, Registry $input = null) $return = Factory::getDate($value, $app->get('offset'))->toSql(); break; - // Convert a date to UTC based on the user timezone offset. case 'USER_UTC': + // Convert a date to UTC based on the user timezone offset. // Get the user timezone setting defaulting to the server timezone setting. $offset = $app->getIdentity()->getParam('timezone', $app->get('offset')); diff --git a/libraries/src/Form/Field/CheckboxesField.php b/libraries/src/Form/Field/CheckboxesField.php index 34af4fbd2a528..ee904ac49271c 100644 --- a/libraries/src/Form/Field/CheckboxesField.php +++ b/libraries/src/Form/Field/CheckboxesField.php @@ -110,7 +110,7 @@ protected function getInput() throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } - return $this->getRenderer($this->layout)->render($this->getLayoutData()); + return $this->getRenderer($this->layout)->render($this->collectLayoutData()); } /** diff --git a/libraries/src/Form/Field/ChromestyleField.php b/libraries/src/Form/Field/ChromestyleField.php index 8a874191fd61b..ad945d5e7ced0 100644 --- a/libraries/src/Form/Field/ChromestyleField.php +++ b/libraries/src/Form/Field/ChromestyleField.php @@ -10,11 +10,12 @@ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Application\ApplicationHelper; -use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Form\Form; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; +use Joomla\Filesystem\Folder; +use Joomla\Filesystem\Path; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; @@ -189,7 +190,7 @@ protected function getTemplateModuleStyles() foreach ($templates as $template) { $chromeLayoutPath = $path . '/templates/' . $template->element . '/html/layouts/chromes'; - if (!Folder::exists($chromeLayoutPath)) { + if (!is_dir(Path::clean($chromeLayoutPath))) { continue; } diff --git a/libraries/src/Form/Field/ColorField.php b/libraries/src/Form/Field/ColorField.php index 2448cf35e5eae..f740ba0d3686d 100644 --- a/libraries/src/Form/Field/ColorField.php +++ b/libraries/src/Form/Field/ColorField.php @@ -232,7 +232,7 @@ protected function getInput() } // Trim the trailing line in the layout file - return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); + return rtrim($this->getRenderer($this->layout)->render($this->collectLayoutData()), PHP_EOL); } /** diff --git a/libraries/src/Form/Field/ComboField.php b/libraries/src/Form/Field/ComboField.php index 38e7c38a3b912..24d57b55e261a 100644 --- a/libraries/src/Form/Field/ComboField.php +++ b/libraries/src/Form/Field/ComboField.php @@ -50,7 +50,7 @@ protected function getInput() throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } - return $this->getRenderer($this->layout)->render($this->getLayoutData()); + return $this->getRenderer($this->layout)->render($this->collectLayoutData()); } /** diff --git a/libraries/src/Form/Field/ContenthistoryField.php b/libraries/src/Form/Field/ContenthistoryField.php index 68a9476ec8bcd..68f192f12159b 100644 --- a/libraries/src/Form/Field/ContenthistoryField.php +++ b/libraries/src/Form/Field/ContenthistoryField.php @@ -77,6 +77,6 @@ protected function getInput() throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } - return $this->getRenderer($this->layout)->render($this->getLayoutData()); + return $this->getRenderer($this->layout)->render($this->collectLayoutData()); } } diff --git a/libraries/src/Form/Field/EmailField.php b/libraries/src/Form/Field/EmailField.php index 318690ba2c86e..2b42a1189e59f 100644 --- a/libraries/src/Form/Field/EmailField.php +++ b/libraries/src/Form/Field/EmailField.php @@ -49,7 +49,7 @@ class EmailField extends TextField protected function getInput() { // Trim the trailing line in the layout file - return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); + return rtrim($this->getRenderer($this->layout)->render($this->collectLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. diff --git a/libraries/src/Form/Field/FileField.php b/libraries/src/Form/Field/FileField.php index c9e6ee7f93b50..e68c2f079b7e7 100644 --- a/libraries/src/Form/Field/FileField.php +++ b/libraries/src/Form/Field/FileField.php @@ -126,7 +126,7 @@ public function setup(\SimpleXMLElement $element, $value, $group = null) */ protected function getInput() { - return $this->getRenderer($this->layout)->render($this->getLayoutData()); + return $this->getRenderer($this->layout)->render($this->collectLayoutData()); } /** diff --git a/libraries/src/Form/Field/GroupedlistField.php b/libraries/src/Form/Field/GroupedlistField.php index a56ea8568a29f..87088919b6c83 100644 --- a/libraries/src/Form/Field/GroupedlistField.php +++ b/libraries/src/Form/Field/GroupedlistField.php @@ -56,8 +56,8 @@ protected function getGroups() foreach ($this->element->children() as $element) { switch ($element->getName()) { - // The element is an