diff --git a/administrator/components/com_menus/controller.php b/administrator/components/com_menus/controller.php index 21823c69557a0..eed32b70bdb53 100644 --- a/administrator/components/com_menus/controller.php +++ b/administrator/components/com_menus/controller.php @@ -30,6 +30,39 @@ public function display($cachable = false, $urlparams = false) { JLoader::register('MenusHelper', JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php'); + // Check custom administrator menu modules + if (JLanguageMultilang::isAdminEnabled()) + { + $languages = JLanguageHelper::getInstalledLanguages(1, true); + $langCodes = array(); + + foreach ($languages as $language) + { + $langCodes[$language->metadata['tag']] = $language->metadata['nativeName']; + } + + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + $query->select($db->qn('m.language')) + ->from($db->qn('#__modules', 'm')) + ->where($db->qn('m.module') . ' = ' . $db->quote('mod_menu')) + ->where($db->qn('m.published') . ' = 1') + ->where($db->qn('m.client_id') . ' = 1') + ->group($db->qn('m.language')); + + $mLanguages = $db->setQuery($query)->loadColumn(); + + // Check if we have a mod_menu module set to All languages or a mod_menu module for each admin language. + if (!in_array('*', $mLanguages) && count($langMissing = array_diff(array_keys($langCodes), $mLanguages))) + { + $app = JFactory::getApplication(); + $langMissing = array_intersect_key($langCodes, array_flip($langMissing)); + + $app->enqueueMessage(JText::sprintf('JMENU_MULTILANG_WARNING_MISSING_MODULES', implode(', ', $langMissing)), 'warning'); + } + } + return parent::display(); } } diff --git a/administrator/components/com_modules/config.xml b/administrator/components/com_modules/config.xml index 4f7f55b2ea54f..3eb9b198ebcf4 100644 --- a/administrator/components/com_modules/config.xml +++ b/administrator/components/com_modules/config.xml @@ -17,6 +17,25 @@ + +
+ + + + +
+
input->get('view', 'modules')); + // Check custom administrator menu modules + if (JLanguageMultilang::isAdminEnabled()) + { + $languages = JLanguageHelper::getInstalledLanguages(1, true); + $langCodes = array(); + + foreach ($languages as $language) + { + $langCodes[$language->metadata['tag']] = $language->metadata['nativeName']; + } + + $db = JFactory::getDbo(); + $query = $db->getQuery(true); + + $query->select($db->qn('m.language')) + ->from($db->qn('#__modules', 'm')) + ->where($db->qn('m.module') . ' = ' . $db->quote('mod_menu')) + ->where($db->qn('m.published') . ' = 1') + ->where($db->qn('m.client_id') . ' = 1') + ->group($db->qn('m.language')); + + $mLanguages = $db->setQuery($query)->loadColumn(); + + // Check if we have a mod_menu module set to All languages or a mod_menu module for each admin language. + if (!in_array('*', $mLanguages) && count($langMissing = array_diff(array_keys($langCodes), $mLanguages))) + { + $app = JFactory::getApplication(); + $langMissing = array_intersect_key($langCodes, array_flip($langMissing)); + + $app->enqueueMessage(JText::sprintf('JMENU_MULTILANG_WARNING_MISSING_MODULES', implode(', ', $langMissing)), 'warning'); + } + } + return parent::display(); } } diff --git a/administrator/components/com_modules/models/forms/filter_modulesadmin.xml b/administrator/components/com_modules/models/forms/filter_modulesadmin.xml new file mode 100644 index 0000000000000..0166cb5e53652 --- /dev/null +++ b/administrator/components/com_modules/models/forms/filter_modulesadmin.xml @@ -0,0 +1,109 @@ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/administrator/components/com_modules/models/forms/moduleadmin.xml b/administrator/components/com_modules/models/forms/moduleadmin.xml index 06d1ad3bd7be5..5857a1723c9de 100644 --- a/administrator/components/com_modules/models/forms/moduleadmin.xml +++ b/administrator/components/com_modules/models/forms/moduleadmin.xml @@ -103,6 +103,17 @@ label="JFIELD_ORDERING_LABEL" /> + + + + loadForm('com_modules.module.admin', 'moduleadmin', array('control' => 'jform', 'load_data' => $loadData), true); + + // Display language field to filter admin custom menus per language + if (!JLanguageMultilang::isAdminEnabled()) + { + $form->setFieldAttribute('language', 'type', 'hidden'); + } } else { diff --git a/administrator/components/com_modules/models/modules.php b/administrator/components/com_modules/models/modules.php index 942fcdab6383b..5eec9a16f248d 100644 --- a/administrator/components/com_modules/models/modules.php +++ b/administrator/components/com_modules/models/modules.php @@ -111,6 +111,12 @@ protected function populateState($ordering = 'a.position', $direction = 'asc') $this->setState('client_id', $clientId); } + // Use a different filter file when client is administrator + if ($clientId == 1) + { + $this->filterFormName = 'filter_modulesadmin'; + } + // Load the parameters. $params = JComponentHelper::getParams('com_modules'); $this->setState('params', $params); diff --git a/administrator/components/com_modules/views/modules/tmpl/default.php b/administrator/components/com_modules/views/modules/tmpl/default.php index a7bdfbafd6526..d6b30171378b3 100644 --- a/administrator/components/com_modules/views/modules/tmpl/default.php +++ b/administrator/components/com_modules/views/modules/tmpl/default.php @@ -69,6 +69,10 @@ + + + + @@ -187,6 +191,16 @@ + + + language == ''):?> + + language == '*'):?> + + + escape($item->language); ?> + + id; ?> diff --git a/administrator/components/com_modules/views/modules/tmpl/default_batch_body.php b/administrator/components/com_modules/views/modules/tmpl/default_batch_body.php index 93e72eafd1e2f..fdc24284b67f2 100644 --- a/administrator/components/com_modules/views/modules/tmpl/default_batch_body.php +++ b/administrator/components/com_modules/views/modules/tmpl/default_batch_body.php @@ -33,11 +33,19 @@

-
-
- + +
+
+ +
-
+ +
+
+ +
+
+
diff --git a/administrator/components/com_modules/views/modules/view.html.php b/administrator/components/com_modules/views/modules/view.html.php index 974e320131428..f3502b5437cb9 100644 --- a/administrator/components/com_modules/views/modules/view.html.php +++ b/administrator/components/com_modules/views/modules/view.html.php @@ -39,6 +39,7 @@ public function display($tpl = null) $this->total = $this->get('Total'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); + $this->clientId = $this->state->get('client_id'); // Check for errors. if (count($errors = $this->get('Errors'))) @@ -46,12 +47,9 @@ public function display($tpl = null) throw new Exception(implode("\n", $errors), 500); } - // We do not need the Page and the Language filters when filtering by administrator - if ($this->state->get('client_id') == 1) + // We do not need the Language filter when modules are not filtered + if ($this->clientId == 1 && !JLanguageMultilang::isAdminEnabled()) { - unset($this->activeFilters['menuitem']); - $this->filterForm->removeField('menuitem', 'filter'); - unset($this->activeFilters['language']); $this->filterForm->removeField('language', 'filter'); } @@ -176,11 +174,26 @@ protected function addToolbar() */ protected function getSortFields() { - if ($this->getLayout() == 'default') + $this->state = $this->get('State'); + + if ($this->state->get('client_id') == 0) { + if ($this->getLayout() == 'default') + { + return array( + 'ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'position' => JText::_('COM_MODULES_HEADING_POSITION'), + 'name' => JText::_('COM_MODULES_HEADING_MODULE'), + 'pages' => JText::_('COM_MODULES_HEADING_PAGES'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'language_title' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } + return array( - 'ordering' => JText::_('JGRID_HEADING_ORDERING'), - 'a.published' => JText::_('JSTATUS'), 'a.title' => JText::_('JGLOBAL_TITLE'), 'position' => JText::_('COM_MODULES_HEADING_POSITION'), 'name' => JText::_('COM_MODULES_HEADING_MODULE'), @@ -190,15 +203,30 @@ protected function getSortFields() 'a.id' => JText::_('JGRID_HEADING_ID') ); } + else + { + if ($this->getLayout() == 'default') + { + return array( + 'ordering' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'position' => JText::_('COM_MODULES_HEADING_POSITION'), + 'name' => JText::_('COM_MODULES_HEADING_MODULE'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'a.language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } - return array( - 'a.title' => JText::_('JGLOBAL_TITLE'), - 'position' => JText::_('COM_MODULES_HEADING_POSITION'), - 'name' => JText::_('COM_MODULES_HEADING_MODULE'), - 'pages' => JText::_('COM_MODULES_HEADING_PAGES'), - 'a.access' => JText::_('JGRID_HEADING_ACCESS'), - 'language_title' => JText::_('JGRID_HEADING_LANGUAGE'), - 'a.id' => JText::_('JGRID_HEADING_ID') - ); + return array( + 'a.title' => JText::_('JGLOBAL_TITLE'), + 'position' => JText::_('COM_MODULES_HEADING_POSITION'), + 'name' => JText::_('COM_MODULES_HEADING_MODULE'), + 'a.access' => JText::_('JGRID_HEADING_ACCESS'), + 'a.language' => JText::_('JGRID_HEADING_LANGUAGE'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } } } diff --git a/administrator/language/en-GB/en-GB.com_modules.ini b/administrator/language/en-GB/en-GB.com_modules.ini index a1463cd8b9540..e0d430dfe5fec 100644 --- a/administrator/language/en-GB/en-GB.com_modules.ini +++ b/administrator/language/en-GB/en-GB.com_modules.ini @@ -6,6 +6,9 @@ COM_MODULES="Modules Manager" COM_MODULES_ACTION_EDITFRONTEND="Frontend Editing" COM_MODULES_ACTION_EDITFRONTEND_COMPONENT_DESC="Allows users in the group to edit in Frontend." +COM_MODULES_ADMIN_LANG_FILTER_FIELDSET_LABEL="Administrator Modules" +COM_MODULES_ADMIN_LANG_FILTER_DESC="Allows filtering administrator modules per administrator language." +COM_MODULES_ADMIN_LANG_FILTER_LABEL="Language Filtering" COM_MODULES_ADVANCED_FIELDSET_LABEL="Advanced" COM_MODULES_ASSIGNED_VARIES_EXCEPT="All except selected" COM_MODULES_ASSIGNED_VARIES_ONLY="Selected" diff --git a/administrator/language/en-GB/en-GB.ini b/administrator/language/en-GB/en-GB.ini index 1afc2be0b04cb..af3322b33369b 100644 --- a/administrator/language/en-GB/en-GB.ini +++ b/administrator/language/en-GB/en-GB.ini @@ -87,6 +87,7 @@ JINVALID_TOKEN="The most recent request was denied because it contained an inval JINVALID_TOKEN_NOTICE="The security token did not match. The request was aborted to prevent any security breach. Please try again." JLOGIN="Log in" JLOGOUT="Log out" +JMENU_MULTILANG_WARNING_MISSING_MODULES="An administrator menu module for %s does not exist.
Create a custom administrator menu and module for each administrator language or publish a menu module set to All languages." JMODIFY="Modify" JNEVER="Never" JNEXT="Next" diff --git a/layouts/joomla/html/batch/adminlanguage.php b/layouts/joomla/html/batch/adminlanguage.php new file mode 100644 index 0000000000000..ebb1221fe084c --- /dev/null +++ b/layouts/joomla/html/batch/adminlanguage.php @@ -0,0 +1,44 @@ +addScriptDeclaration( + ' + jQuery(document).ready(function($){ + if ($("#batch-category-id").length){var batchSelector = $("#batch-category-id");} + if ($("#batch-menu-id").length){var batchSelector = $("#batch-menu-id");} + if ($("#batch-position-id").length){var batchSelector = $("#batch-position-id");} + if ($("#batch-copy-move").length && batchSelector) { + $("#batch-copy-move").hide(); + batchSelector.on("change", function(){ + if (batchSelector.val() != 0 || batchSelector.val() != "") { + $("#batch-copy-move").show(); + } else { + $("#batch-copy-move").hide(); + } + }); + } + }); + ' +); +?> + + diff --git a/libraries/cms/html/adminlanguage.php b/libraries/cms/html/adminlanguage.php new file mode 100644 index 0000000000000..a9230ecd28eda --- /dev/null +++ b/libraries/cms/html/adminlanguage.php @@ -0,0 +1,65 @@ + $language) + { + $languages[$tag] = $language['nativeName']; + } + + ksort($languages); + + static::$items = $languages; + } + + if ($all) + { + $all_option = array(new JObject(array('value' => '*', 'text' => $translate ? JText::alt('JALL', 'language') : 'JALL_LANGUAGE'))); + + return array_merge($all_option, static::$items); + } + else + { + return static::$items; + } + } +} diff --git a/libraries/src/Joomla/CMS/Helper/ModuleHelper.php b/libraries/src/Joomla/CMS/Helper/ModuleHelper.php index 6cdfd998b79ac..10605a9dd8179 100644 --- a/libraries/src/Joomla/CMS/Helper/ModuleHelper.php +++ b/libraries/src/Joomla/CMS/Helper/ModuleHelper.php @@ -413,6 +413,12 @@ public static function getModuleList() $cacheId .= $lang . '*'; } + if ($app->isClient('administrator') && \JLanguageMultilang::isAdminEnabled()) + { + $query->where('m.language IN (' . $db->quote($lang) . ',' . $db->quote('*') . ')'); + $cacheId .= $lang . '*'; + } + $query->order('m.position, m.ordering'); // Set the query diff --git a/libraries/src/Joomla/CMS/Language/Multilanguage.php b/libraries/src/Joomla/CMS/Language/Multilanguage.php index d6d92b79d32e6..cff02e8b39e0b 100644 --- a/libraries/src/Joomla/CMS/Language/Multilanguage.php +++ b/libraries/src/Joomla/CMS/Language/Multilanguage.php @@ -109,4 +109,23 @@ public static function getSiteHomePages() return $multilangSiteHomePages; } + + /** + * Method to determine if filtering by language is enabled in back-end for custom menus. + * + * @return boolean True if admin is supporting multiple languages; false otherwise. + * + * @since 3.8.0 + */ + public static function isAdminEnabled() + { + static $enabled = false; + + if (count(\JLanguageHelper::getInstalledLanguages(1)) > 1) + { + $enabled = \JComponentHelper::getParams('com_modules')->get('adminlangfilter', 0); + } + + return (bool) $enabled; + } }