diff --git a/administrator/components/com_admin/script.php b/administrator/components/com_admin/script.php
index 0889043887e3c..67b97a8825308 100644
--- a/administrator/components/com_admin/script.php
+++ b/administrator/components/com_admin/script.php
@@ -1618,6 +1618,10 @@ public function deleteUnexistingFiles()
'/administrator/components/com_modules/layouts/joomla/searchtools/default.php',
'/administrator/components/com_templates/layouts/joomla/searchtools/default/bar.php',
'/administrator/components/com_templates/layouts/joomla/searchtools/default.php',
+ // Joomla __DEPLOY_VERSION__
+ '/administrator/modules/mod_menu/tmpl/default_enabled.php',
+ '/administrator/modules/mod_menu/tmpl/default_disabled.php',
+ '/administrator/templates/hathor/html/mod_menu/default_enabled.php',
);
// TODO There is an issue while deleting folders using the ftp mode
@@ -1746,6 +1750,8 @@ public function deleteUnexistingFiles()
'/administrator/components/com_templates/layouts/joomla/searchtools',
'/administrator/components/com_templates/layouts/joomla',
'/administrator/components/com_templates/layouts',
+ // Joomla! __DEPLOY_VERSION__
+ '/administrator/templates/hathor/html/mod_menu',
);
jimport('joomla.filesystem.file');
diff --git a/administrator/components/com_admin/sql/updates/mysql/3.7.0-2016-11-19.sql b/administrator/components/com_admin/sql/updates/mysql/3.7.0-2016-11-19.sql
new file mode 100644
index 0000000000000..4b2cabfb8b5ec
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/mysql/3.7.0-2016-11-19.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `#__menu_types` ADD `client_id` int(11) NOT NULL DEFAULT 0;
+
+UPDATE `#__menu` SET `published` = 1 WHERE `menutype` = 'main' OR `menutype` = 'menu';
diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.7.0-2016-11-19.sql b/administrator/components/com_admin/sql/updates/postgresql/3.7.0-2016-11-19.sql
new file mode 100644
index 0000000000000..da2b368041418
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/postgresql/3.7.0-2016-11-19.sql
@@ -0,0 +1,3 @@
+ALTER TABLE "#__menu_types" ADD "client_id" int DEFAULT 0 NOT NULL;
+
+UPDATE "#__menu" SET "published" = 1 WHERE "menutype" = 'main' OR "menutype" = 'menu';
diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.7.0-2016-11-19.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.7.0-2016-11-19.sql
new file mode 100644
index 0000000000000..01bd65750ac80
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/sqlazure/3.7.0-2016-11-19.sql
@@ -0,0 +1,3 @@
+ALTER TABLE [#__menu_types] ADD [client_id] [tinyint] NOT NULL DEFAULT 0;
+
+UPDATE [#__menu] SET [published] = 1 WHERE [menutype] = 'main' OR [menutype] = 'menu';
diff --git a/administrator/components/com_admin/views/help/tmpl/default.xml b/administrator/components/com_admin/views/help/tmpl/default.xml
new file mode 100755
index 0000000000000..098e8f184d6e2
--- /dev/null
+++ b/administrator/components/com_admin/views/help/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default.xml b/administrator/components/com_admin/views/sysinfo/tmpl/default.xml
new file mode 100755
index 0000000000000..479fa92087a8c
--- /dev/null
+++ b/administrator/components/com_admin/views/sysinfo/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_cache/views/cache/tmpl/default.xml b/administrator/components/com_cache/views/cache/tmpl/default.xml
new file mode 100755
index 0000000000000..82466a2128618
--- /dev/null
+++ b/administrator/components/com_cache/views/cache/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_cache/views/purge/tmpl/default.xml b/administrator/components/com_cache/views/purge/tmpl/default.xml
new file mode 100755
index 0000000000000..98fcff1baed46
--- /dev/null
+++ b/administrator/components/com_cache/views/purge/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_categories/views/categories/tmpl/default.xml b/administrator/components/com_categories/views/categories/tmpl/default.xml
new file mode 100755
index 0000000000000..d1eadb14baa6d
--- /dev/null
+++ b/administrator/components/com_categories/views/categories/tmpl/default.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_categories/views/category/tmpl/edit.xml b/administrator/components/com_categories/views/category/tmpl/edit.xml
new file mode 100755
index 0000000000000..3bdf3cee46f20
--- /dev/null
+++ b/administrator/components/com_categories/views/category/tmpl/edit.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_checkin/views/checkin/tmpl/default.xml b/administrator/components/com_checkin/views/checkin/tmpl/default.xml
new file mode 100755
index 0000000000000..e0086bef3983c
--- /dev/null
+++ b/administrator/components/com_checkin/views/checkin/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_config/view/application/tmpl/default.xml b/administrator/components/com_config/view/application/tmpl/default.xml
new file mode 100755
index 0000000000000..2cd0ed3287f1b
--- /dev/null
+++ b/administrator/components/com_config/view/application/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_config/view/component/tmpl/default.xml b/administrator/components/com_config/view/component/tmpl/default.xml
new file mode 100755
index 0000000000000..2ddf42d8b8967
--- /dev/null
+++ b/administrator/components/com_config/view/component/tmpl/default.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_content/views/article/tmpl/edit.xml b/administrator/components/com_content/views/article/tmpl/edit.xml
new file mode 100755
index 0000000000000..f5efd601bb092
--- /dev/null
+++ b/administrator/components/com_content/views/article/tmpl/edit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_content/views/articles/tmpl/default.xml b/administrator/components/com_content/views/articles/tmpl/default.xml
new file mode 100755
index 0000000000000..b3dec7f7be330
--- /dev/null
+++ b/administrator/components/com_content/views/articles/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_content/views/featured/tmpl/default.xml b/administrator/components/com_content/views/featured/tmpl/default.xml
new file mode 100755
index 0000000000000..4697ce1704542
--- /dev/null
+++ b/administrator/components/com_content/views/featured/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_cpanel/views/cpanel/tmpl/default.xml b/administrator/components/com_cpanel/views/cpanel/tmpl/default.xml
new file mode 100755
index 0000000000000..f9c3fdac00aea
--- /dev/null
+++ b/administrator/components/com_cpanel/views/cpanel/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/database/tmpl/default.xml b/administrator/components/com_installer/views/database/tmpl/default.xml
new file mode 100755
index 0000000000000..c028598367863
--- /dev/null
+++ b/administrator/components/com_installer/views/database/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/discover/tmpl/default.xml b/administrator/components/com_installer/views/discover/tmpl/default.xml
new file mode 100755
index 0000000000000..350dddaf66f10
--- /dev/null
+++ b/administrator/components/com_installer/views/discover/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/install/tmpl/default.xml b/administrator/components/com_installer/views/install/tmpl/default.xml
new file mode 100755
index 0000000000000..e6fd86b3287f9
--- /dev/null
+++ b/administrator/components/com_installer/views/install/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/languages/tmpl/default.xml b/administrator/components/com_installer/views/languages/tmpl/default.xml
new file mode 100755
index 0000000000000..4f52293ea226d
--- /dev/null
+++ b/administrator/components/com_installer/views/languages/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/manage/tmpl/default.xml b/administrator/components/com_installer/views/manage/tmpl/default.xml
new file mode 100755
index 0000000000000..13dc66fc7c92c
--- /dev/null
+++ b/administrator/components/com_installer/views/manage/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/update/tmpl/default.xml b/administrator/components/com_installer/views/update/tmpl/default.xml
new file mode 100755
index 0000000000000..d262a8a9750b2
--- /dev/null
+++ b/administrator/components/com_installer/views/update/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/updatesites/tmpl/default.xml b/administrator/components/com_installer/views/updatesites/tmpl/default.xml
new file mode 100755
index 0000000000000..f9cf92a6b36fe
--- /dev/null
+++ b/administrator/components/com_installer/views/updatesites/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_installer/views/warnings/tmpl/default.xml b/administrator/components/com_installer/views/warnings/tmpl/default.xml
new file mode 100755
index 0000000000000..8e6472cdea1e9
--- /dev/null
+++ b/administrator/components/com_installer/views/warnings/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_joomlaupdate/views/default/tmpl/default.xml b/administrator/components/com_joomlaupdate/views/default/tmpl/default.xml
new file mode 100755
index 0000000000000..61f8dafe9a76b
--- /dev/null
+++ b/administrator/components/com_joomlaupdate/views/default/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_languages/views/installed/tmpl/default.xml b/administrator/components/com_languages/views/installed/tmpl/default.xml
new file mode 100755
index 0000000000000..3c92e7d97662c
--- /dev/null
+++ b/administrator/components/com_languages/views/installed/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_languages/views/languages/tmpl/default.xml b/administrator/components/com_languages/views/languages/tmpl/default.xml
new file mode 100755
index 0000000000000..4c7a003f386bc
--- /dev/null
+++ b/administrator/components/com_languages/views/languages/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_languages/views/overrides/tmpl/default.xml b/administrator/components/com_languages/views/overrides/tmpl/default.xml
new file mode 100755
index 0000000000000..54b63dcf72c9c
--- /dev/null
+++ b/administrator/components/com_languages/views/overrides/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_media/views/media/tmpl/default.xml b/administrator/components/com_media/views/media/tmpl/default.xml
new file mode 100755
index 0000000000000..6aa1cbb202034
--- /dev/null
+++ b/administrator/components/com_media/views/media/tmpl/default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/administrator/components/com_menus/controllers/item.php b/administrator/components/com_menus/controllers/item.php
index c473d4881eb89..5b5f42b78e52d 100644
--- a/administrator/components/com_menus/controllers/item.php
+++ b/administrator/components/com_menus/controllers/item.php
@@ -69,6 +69,12 @@ protected function allowEdit($data = array(), $key = 'id')
if (!empty($item->menutype))
{
+ // Protected menutype, do not allow edit
+ if ($item->menutype == 'main' || $item->menutype == 'menu')
+ {
+ return false;
+ }
+
$menutypeID = (int) $this->getMenuTypeId($item->menutype);
}
}
@@ -113,10 +119,6 @@ public function add()
{
$app->setUserState($context . '.type', null);
$app->setUserState($context . '.link', null);
-
- $menuType = $app->getUserStateFromRequest($this->context . '.filter.menutype', 'menutype', 'mainmenu', 'cmd');
-
- $this->setRedirect(JRoute::_('index.php?option=com_menus&view=item&menutype=' . $menuType . $this->getRedirectToItemAppend(), false));
}
return $result;
@@ -204,6 +206,38 @@ public function edit($key = null, $urlVar = null)
return $result;
}
+ /**
+ * Gets the URL arguments to append to an item redirect.
+ *
+ * @param integer $recordId The primary key id for the item.
+ * @param string $urlVar The name of the URL variable for the id.
+ *
+ * @return string The arguments to append to the redirect URL.
+ *
+ * @since 12.2
+ */
+ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id')
+ {
+ $append = parent::getRedirectToItemAppend($recordId, $urlVar);
+
+ if ($recordId)
+ {
+ $model = $this->getModel();
+ $item = $model->getItem($recordId);
+ $clientId = $item->client_id;
+ $append = '&client_id=' . $clientId . $append;
+ }
+ else
+ {
+ $app = JFactory::getApplication();
+ $clientId = $app->input->get('client_id', '0', 'int');
+ $menuType = $app->input->get('menutype', 'mainmenu', 'cmd');
+ $append = '&client_id=' . $clientId . ($menuType ? '&menutype=' . $menuType : '') . $append;
+ }
+
+ return $append;
+ }
+
/**
* Method to save a record.
*
@@ -429,7 +463,6 @@ public function save($key = null, $urlVar = null)
$app->setUserState('com_menus.edit.item.data', null);
$app->setUserState('com_menus.edit.item.type', null);
$app->setUserState('com_menus.edit.item.link', null);
- $app->setUserState('com_menus.edit.item.menutype', $model->getState('item.menutype'));
// Redirect back to the edit screen.
$this->setRedirect(JRoute::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend(), false));
@@ -532,21 +565,26 @@ public function getParentItem()
{
$app = JFactory::getApplication();
+ $results = array();
$menutype = $this->input->get->get('menutype');
- $model = $this->getModel('Items', '', array());
- $model->getState();
- $model->setState('filter.menutype', $menutype);
- $model->setState('list.select', 'a.id, a.title, a.level');
- $model->setState('list.start', 0);
- $model->setState('list.limit', 0);
-
- $results = $model->getItems();
-
- // Pad the option text with spaces using depth level as a multiplier.
- for ($i = 0, $n = count($results); $i < $n; $i++)
+ if ($menutype)
{
- $results[$i]->title = str_repeat('- ', $results[$i]->level) . $results[$i]->title;
+ $model = $this->getModel('Items', '', array());
+ $model->getState();
+ $model->setState('filter.menutype', $menutype);
+ $model->setState('list.select', 'a.id, a.title, a.level');
+ $model->setState('list.start', '0');
+ $model->setState('list.limit', '0');
+
+ /** @var MenusModelItems $model */
+ $results = $model->getItems();
+
+ // Pad the option text with spaces using depth level as a multiplier.
+ for ($i = 0, $n = count($results); $i < $n; $i++)
+ {
+ $results[$i]->title = str_repeat(' - ', $results[$i]->level) . $results[$i]->title;
+ }
}
// Output a JSON object
diff --git a/administrator/components/com_menus/controllers/menu.php b/administrator/components/com_menus/controllers/menu.php
index 2891d6947eaa1..341584a7073f1 100644
--- a/administrator/components/com_menus/controllers/menu.php
+++ b/administrator/components/com_menus/controllers/menu.php
@@ -52,17 +52,6 @@ public function save($key = null, $urlVar = null)
$task = $this->getTask();
$recordId = $this->input->getInt('id');
- // Make sure we are not trying to modify an administrator menu.
- if (isset($data['client_id']) && $data['client_id'] == 1)
- {
- JError::raiseNotice(0, JText::_('COM_MENUS_MENU_TYPE_NOT_ALLOWED'));
-
- // Redirect back to the edit screen.
- $this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit', false));
-
- return false;
- }
-
// Prevent using 'menu' or 'main' as menutype as this is reserved for backend menus
if (strtolower($data['menutype']) == 'menu' || strtolower($data['menutype']) == 'main')
{
diff --git a/administrator/components/com_menus/layouts/joomla/searchtools/default.php b/administrator/components/com_menus/layouts/joomla/searchtools/default.php
new file mode 100644
index 0000000000000..d44a0870e910f
--- /dev/null
+++ b/administrator/components/com_menus/layouts/joomla/searchtools/default.php
@@ -0,0 +1,83 @@
+addStyleDeclaration("
+ /* Fixed filter field in search bar */
+ .js-stools .js-stools-menutype,
+ .js-stools .js-stools-client_id {
+ float: left;
+ margin-right: 10px;
+ min-width: 220px;
+ }
+ html[dir=rtl] .js-stools .js-stools-menutype,
+ html[dir=rtl] .js-stools .js-stools-client_id {
+ float: right;
+ margin-left: 10px
+ margin-right: 0;
+ }
+ .js-stools .js-stools-container-bar .js-stools-field-filter .chzn-container {
+ padding: 3px 0;
+ }
+ ");
+
+ // Client selector doesn't have to activate the filter bar.
+ unset($data['view']->activeFilters['client_id']);
+
+ // Menutype filter doesn't have to activate the filter bar
+ unset($data['view']->activeFilters['menutype']);
+}
+
+// Set some basic options
+$customOptions = array(
+ 'filtersHidden' => isset($data['options']['filtersHidden']) ? $data['options']['filtersHidden'] : empty($data['view']->activeFilters),
+ 'defaultLimit' => isset($data['options']['defaultLimit']) ? $data['options']['defaultLimit'] : JFactory::getApplication()->get('list_limit', 20),
+ 'searchFieldSelector' => '#filter_search',
+ 'orderFieldSelector' => '#list_fullordering',
+ 'totalResults' => isset($data['options']['totalResults']) ? $data['options']['totalResults'] : -1,
+ 'noResultsText' => isset($data['options']['noResultsText']) ? $data['options']['noResultsText'] : JText::_('JGLOBAL_NO_MATCHING_RESULTS'),
+);
+
+$data['options'] = array_merge($customOptions, $data['options']);
+
+$formSelector = !empty($data['options']['formSelector']) ? $data['options']['formSelector'] : '#adminForm';
+
+// Load search tools
+JHtml::_('searchtools.form', $formSelector, $data['options']);
+
+$filtersClass = isset($data['view']->activeFilters) && $data['view']->activeFilters ? ' js-stools-container-filters-visible' : '';
+?>
+
+
+
+
diff --git a/administrator/components/com_menus/layouts/joomla/searchtools/default/bar.php b/administrator/components/com_menus/layouts/joomla/searchtools/default/bar.php
new file mode 100644
index 0000000000000..916ea5459df3b
--- /dev/null
+++ b/administrator/components/com_menus/layouts/joomla/searchtools/default/bar.php
@@ -0,0 +1,46 @@
+filterForm->getField('menutype');
+
+ // Add the client selector before the form filters.
+ $clientIdField = $data['view']->filterForm->getField('client_id');
+
+ if ($clientIdField): ?>
+
+ input; ?>
+
+
+
+
+ filterForm->getField('client_id');
+ ?>
+
+ input; ?>
+
+ 'none'));
diff --git a/administrator/components/com_menus/models/fields/menuparent.php b/administrator/components/com_menus/models/fields/menuparent.php
index 3e2f95b593209..b59a9cd3993e4 100644
--- a/administrator/components/com_menus/models/fields/menuparent.php
+++ b/administrator/components/com_menus/models/fields/menuparent.php
@@ -49,7 +49,10 @@ protected function getOptions()
}
else
{
+ // Skip special menu types
$query->where('a.menutype != ' . $db->quote(''));
+ $query->where('a.menutype != ' . $db->quote('main'));
+ $query->where('a.menutype != ' . $db->quote('menu'));
}
// Filter by client id.
diff --git a/administrator/components/com_menus/models/fields/menutype.php b/administrator/components/com_menus/models/fields/menutype.php
index 0c374c0c9df68..df985c85de23a 100644
--- a/administrator/components/com_menus/models/fields/menutype.php
+++ b/administrator/components/com_menus/models/fields/menutype.php
@@ -39,14 +39,12 @@ protected function getInput()
{
$html = array();
$recordId = (int) $this->form->getValue('id');
- $size = ($v = $this->element['size']) ? ' size="' . $v . '"' : '';
- $class = ($v = $this->element['class']) ? ' class="' . $v . '"' : 'class="text_area"';
- $required = ($v = $this->element['required']) ? ' required="required"' : '';
+ $size = (string) ($v = $this->element['size']) ? ' size="' . $v . '"' : '';
+ $class = (string) ($v = $this->element['class']) ? ' class="' . $v . '"' : 'class="text_area"';
+ $required = (string) $this->element['required'] ? ' required="required"' : '';
+ $clientId = (int) $this->element['clientid'] ?: 0;
// Get a reverse lookup of the base link URL to Title
- $model = JModelLegacy::getInstance('menutypes', 'menusModel');
- $rlu = $model->getReverseLookup();
-
switch ($this->value)
{
case 'url':
@@ -68,10 +66,17 @@ protected function getInput()
default:
$link = $this->form->getValue('link');
+ /** @var MenusModelMenutypes $model */
+ $model = JModelLegacy::getInstance('Menutypes', 'MenusModel', array('ignore_request' => true));
+ $model->setState('client_id', $clientId);
+
+ $rlu = $model->getReverseLookup();
+
// Clean the link back to the option, view and layout
$value = JText::_(ArrayHelper::getValue($rlu, MenusHelper::getLinkKey($link)));
break;
}
+
// Include jQuery
JHtml::_('jquery.framework');
@@ -82,9 +87,9 @@ function jSelectPosition_' . $this->id . '(name) {
}
');
- $link = JRoute::_('index.php?option=com_menus&view=menutypes&tmpl=component&recordId=' . $recordId);
+ $link = JRoute::_('index.php?option=com_menus&view=menutypes&tmpl=component&client_id=' . $clientId . '&recordId=' . $recordId);
$html[] = '';
+ . '" value="' . $value . '" ' . $size . $class . ' />';
$html[] = ''
. ' '
. JText::_('JSELECT') . '';
diff --git a/administrator/components/com_menus/models/fields/modal/menu.php b/administrator/components/com_menus/models/fields/modal/menu.php
index 072a20bb95884..b5164459cf9b2 100644
--- a/administrator/components/com_menus/models/fields/modal/menu.php
+++ b/administrator/components/com_menus/models/fields/modal/menu.php
@@ -38,6 +38,7 @@ protected function getInput()
$allowEdit = ((string) $this->element['edit'] == 'true');
$allowClear = ((string) $this->element['clear'] != 'false');
$allowSelect = ((string) $this->element['select'] != 'false');
+ $clientId = (int) $this->element['clientid'];
// Load language
JFactory::getLanguage()->load('com_menus', JPATH_ADMINISTRATOR);
@@ -75,8 +76,9 @@ function jSelectMenu_" . $this->id . "(id, title, object) {
}
// Setup variables for display.
- $linkItems = 'index.php?option=com_menus&view=items&layout=modal&tmpl=component&' . JSession::getFormToken() . '=1';
- $linkItem = 'index.php?option=com_menus&view=item&layout=modal&tmpl=component&' . JSession::getFormToken() . '=1';
+ $linkSuffix = '&layout=modal&client_id=' . $clientId . '&tmpl=component&' . JSession::getFormToken() . '=1';
+ $linkItems = 'index.php?option=com_menus&view=items' . $linkSuffix;
+ $linkItem = 'index.php?option=com_menus&view=item' . $linkSuffix;
$modalTitle = JText::_('COM_MENUS_CHANGE_MENUITEM');
if (isset($this->element['language']))
diff --git a/administrator/components/com_menus/models/forms/filter_items.xml b/administrator/components/com_menus/models/forms/filter_items.xml
index c70e06bf9de1f..a946b172c97f1 100644
--- a/administrator/components/com_menus/models/forms/filter_items.xml
+++ b/administrator/components/com_menus/models/forms/filter_items.xml
@@ -1,11 +1,23 @@
diff --git a/administrator/components/com_menus/models/forms/itemadmin_alias.xml b/administrator/components/com_menus/models/forms/itemadmin_alias.xml
new file mode 100644
index 0000000000000..66e4aebe774a2
--- /dev/null
+++ b/administrator/components/com_menus/models/forms/itemadmin_alias.xml
@@ -0,0 +1,72 @@
+
+
diff --git a/administrator/components/com_menus/models/forms/itemadmin_component.xml b/administrator/components/com_menus/models/forms/itemadmin_component.xml
new file mode 100644
index 0000000000000..78741817a4869
--- /dev/null
+++ b/administrator/components/com_menus/models/forms/itemadmin_component.xml
@@ -0,0 +1,43 @@
+
+
diff --git a/administrator/components/com_menus/models/forms/itemadmin_heading.xml b/administrator/components/com_menus/models/forms/itemadmin_heading.xml
new file mode 100644
index 0000000000000..a13ca94055c55
--- /dev/null
+++ b/administrator/components/com_menus/models/forms/itemadmin_heading.xml
@@ -0,0 +1,81 @@
+
+
diff --git a/administrator/components/com_menus/models/forms/itemadmin_separator.xml b/administrator/components/com_menus/models/forms/itemadmin_separator.xml
new file mode 100644
index 0000000000000..dc0a4d2e8e4fc
--- /dev/null
+++ b/administrator/components/com_menus/models/forms/itemadmin_separator.xml
@@ -0,0 +1,18 @@
+
+
diff --git a/administrator/components/com_menus/models/forms/itemadmin_url.xml b/administrator/components/com_menus/models/forms/itemadmin_url.xml
new file mode 100644
index 0000000000000..5eba70717831c
--- /dev/null
+++ b/administrator/components/com_menus/models/forms/itemadmin_url.xml
@@ -0,0 +1,61 @@
+
+
diff --git a/administrator/components/com_menus/models/forms/menu.xml b/administrator/components/com_menus/models/forms/menu.xml
index a10aac513c04a..4f1855a388fd1 100644
--- a/administrator/components/com_menus/models/forms/menu.xml
+++ b/administrator/components/com_menus/models/forms/menu.xml
@@ -7,13 +7,13 @@
type="hidden"
default="0"
filter="int"
- readonly="true"/>
-
+ readonly="true"
+ />
-
+ filter="unset"
+ />
-
+ required="true"
+ />
-
+ required="true"
+ />
-
+ maxlength="255"
+ />
+
+
+
+
'batchAccess',
- 'language_id' => 'batchLanguage'
+ 'language_id' => 'batchLanguage'
);
/**
@@ -96,9 +96,10 @@ protected function canDelete($record)
if (!empty($record->id))
{
+ // Only delete trashed items
if ($record->published != -2)
{
- return;
+ return false;
}
$menuTypeId = 0;
@@ -110,6 +111,8 @@ protected function canDelete($record)
return $user->authorise('core.delete', 'com_menus.menu.' . (int) $menuTypeId);
}
+
+ return false;
}
/**
@@ -143,13 +146,13 @@ protected function canEditState($record)
protected function batchCopy($value, $pks, $contexts)
{
// $value comes as {menutype}.{parent_id}
- $parts = explode('.', $value);
+ $parts = explode('.', $value);
$menuType = $parts[0];
$parentId = ArrayHelper::getValue($parts, 1, 0, 'int');
- $table = $this->getTable();
- $db = $this->getDbo();
- $query = $db->getQuery(true);
+ $table = $this->getTable();
+ $db = $this->getDbo();
+ $query = $db->getQuery(true);
$newIds = array();
// Check that the parent exists
@@ -536,8 +539,17 @@ public function getForm($data = array(), $loadData = true)
$this->setState('item.type', ArrayHelper::getValue($data, 'type'));
}
+ $clientId = $this->getState('item.client_id');
+
// Get the form.
- $form = $this->loadForm('com_menus.item', 'item', array('control' => 'jform', 'load_data' => $loadData), true);
+ if ($clientId == 1)
+ {
+ $form = $this->loadForm('com_menus.item.admin', 'itemadmin', array('control' => 'jform', 'load_data' => $loadData), true);
+ }
+ else
+ {
+ $form = $this->loadForm('com_menus.item', 'item', array('control' => 'jform', 'load_data' => $loadData), true);
+ }
if (empty($form))
{
@@ -562,10 +574,11 @@ public function getForm($data = array(), $loadData = true)
$form->setFieldAttribute('published', 'filter', 'unset');
}
- // Filter available menues
+ // Filter available menus
$action = $this->getState('item.id') > 0 ? 'edit' : 'create';
$form->setFieldAttribute('menutype', 'accesstype', $action);
+ $form->setFieldAttribute('type', 'clientid', $clientId);
return $form;
}
@@ -653,7 +666,8 @@ public function getItem($pk = null)
if (empty($table->id))
{
$table->parent_id = $this->getState('item.parent_id');
- $table->menutype = $this->getState('item.menutype');
+ $table->menutype = $this->getState('item.menutype');
+ $table->client_id = $this->getState('item.client_id');
$table->params = '{}';
}
@@ -762,10 +776,8 @@ public function getItem($pk = null)
$result->params = array_merge($result->params, $args);
}
- // Load associated menu items
- $assoc = JLanguageAssociations::isEnabled();
-
- if ($assoc)
+ // Load associated menu items, only supported for frontend for now
+ if ($this->getState('item.client_id') == 0 && JLanguageAssociations::isEnabled())
{
if ($pk != null)
{
@@ -794,6 +806,12 @@ public function getModules()
$db = $this->getDbo();
$query = $db->getQuery(true);
+ // Currently any setting that affects target page for a backend menu is not supported, hence load no modules.
+ if ($this->getState('item.client_id') == 1)
+ {
+ return false;
+ }
+
/**
* Join on the module-to-menu mapping table.
* We are only interested if the module is displayed on ALL or THIS menu item (or the inverse ID number).
@@ -808,7 +826,7 @@ public function getModules()
$query->select('ag.title AS access_title')
->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access')
->where('a.published >= 0')
- ->where('a.client_id = 0')
+ ->where('a.client_id = ' . (int) $this->getState('item.client_id'))
->order('a.position, a.ordering');
$db->setQuery($query);
@@ -830,7 +848,7 @@ public function getModules()
/**
* Get the list of all view levels
*
- * @return array An array of all view levels (id, title).
+ * @return array|bool An array of all view levels (id, title).
*
* @since 3.4
*/
@@ -873,17 +891,17 @@ public function getViewLevels()
*/
protected function getReorderConditions($table)
{
- return 'menutype = ' . $this->_db->quote($table->menutype);
+ return 'menutype = ' . $this->_db->quote($table->get('menutype'));
}
/**
* Returns a Table object, always creating it
*
- * @param type $type The table type to instantiate.
+ * @param string $type The table type to instantiate.
* @param string $prefix A prefix for the table class name. Optional.
* @param array $config Configuration array for model. Optional.
*
- * @return JTable A database object.
+ * @return JTable|JTableNested A database object.
*
* @since 1.6
*/
@@ -916,25 +934,48 @@ protected function populateState()
$this->setState('item.parent_id', $parentId);
- $menuType = $app->getUserState('com_menus.edit.item.menutype');
+ $menuType = $app->getUserStateFromRequest('com_menus.items.menutype', 'menutype', '', 'string');
- if ($forcedMenuType = $app->input->get('menutype', '', 'string'))
+ // If we have a menutype we take client_id from there, unless forced otherwise
+ if ($menuType)
{
- $menuType = $forcedMenuType;
+ $menuTypeObj = $this->getMenuType($menuType);
- // Set the menu type on the list view state, so we return to this menu after saving.
- $app->setUserState('com_menus.items.menutype', $forcedMenuType);
+ // An invalid menutype will be handled as clientId = 0 and menuType = ''
+ $menuType = (string) $menuTypeObj->menutype;
+ $menuTypeId = (int) $menuTypeObj->client_id;
+ $clientId = (int) $menuTypeObj->client_id;
+ }
+ else
+ {
+ $menuTypeId = 0;
+ $clientId = $app->getUserState('com_menus.items.client_id', 0);
}
- $this->setState('item.menutype', $menuType);
+ // Forced client id will override/clear menuType if conflicted
+ $forcedClientId = $app->input->get('client_id', null, 'string');
- $menuTypeId = 0;
+ // Current item if not new, we don't allow changing client id at all
+ if ($pk)
+ {
+ $table = $this->getTable();
+ $table->load($pk);
+ $forcedClientId = $table->get('client_id', $forcedClientId);
+ }
- if ($menuType)
+ if (isset($forcedClientId) && $forcedClientId != $clientId)
{
- $menuTypeId = $this->getMenuTypeId($menuType);
+ $clientId = $forcedClientId;
+ $menuType = '';
+ $menuTypeId = 0;
}
+ // Set the menu type and client id on the list view state, so we return to this menu after saving.
+ $app->setUserState('com_menus.items.menutype', $menuType);
+ $app->setUserState('com_menus.items.client_id', $clientId);
+
+ $this->setState('item.menutype', $menuType);
+ $this->setState('item.client_id', $clientId);
$this->setState('item.menutypeid', $menuTypeId);
if (!($type = $app->getUserState('com_menus.edit.item.type')))
@@ -960,21 +1001,37 @@ protected function populateState()
}
/**
- * Loads the menutype ID by a given menutype string
+ * Loads the menutype object by a given menutype string
*
* @param string $menutype The given menutype
*
- * @return integer
+ * @return stdClass
*
- * @since 3.6
+ * @since __DEPLOY_VERSION__
*/
- protected function getMenuTypeId($menutype)
+ protected function getMenuType($menutype)
{
$table = $this->getTable('MenuType', 'JTable');
$table->load(array('menutype' => $menutype));
- return (int) $table->id;
+ return (object) $table->getProperties();
+ }
+
+ /**
+ * Loads the menutype ID by a given menutype string
+ *
+ * @param string $menutype The given menutype
+ *
+ * @return integer
+ *
+ * @since 3.6
+ */
+ protected function getMenuTypeId($menutype)
+ {
+ $menu = $this->getMenuType($menutype);
+
+ return (int) $menu->id;
}
/**
@@ -991,10 +1048,15 @@ protected function getMenuTypeId($menutype)
*/
protected function preprocessForm(JForm $form, $data, $group = 'content')
{
- $link = $this->getState('item.link');
- $type = $this->getState('item.type');
+ $link = $this->getState('item.link');
+ $type = $this->getState('item.type');
+ $clientId = $this->getState('item.client_id');
$formFile = false;
+ // Load the specific type file
+ $typeFile = $clientId == 1 ? 'itemadmin_' . $type : 'item_' . $type;
+ $clientInfo = JApplicationHelper::getClientInfo($clientId);
+
// Initialise form with component view params if available.
if ($type == 'component')
{
@@ -1012,7 +1074,7 @@ protected function preprocessForm(JForm $form, $data, $group = 'content')
{
// The option determines the base path to work with.
$option = $args['option'];
- $base = JPATH_SITE . '/components/' . $option;
+ $base = $clientInfo->path . '/components/' . $option;
}
if (isset($args['view']))
@@ -1045,8 +1107,9 @@ protected function preprocessForm(JForm $form, $data, $group = 'content')
// template folder is first part of file name -- template:folder
if (!$formFile && (strpos($layout, ':') > 0))
{
- $temp = explode(':', $layout);
- $templatePath = JPath::clean(JPATH_SITE . '/templates/' . $temp[0] . '/html/' . $option . '/' . $view . '/' . $temp[1] . '.xml');
+ list($altTmpl, $altLayout) = explode(':', $layout);
+
+ $templatePath = JPath::clean($clientInfo->path . '/templates/' . $altTmpl . '/html/' . $option . '/' . $view . '/' . $altLayout . '.xml');
if (is_file($templatePath))
{
@@ -1106,16 +1169,18 @@ protected function preprocessForm(JForm $form, $data, $group = 'content')
else
{
// We don't have a component. Load the form XML to get the help path
- $xmlFile = JPath::find(JPATH_ADMINISTRATOR . '/components/com_menus/models/forms', 'item_' . $type . '.xml');
+ $xmlFile = JPath::find(JPATH_ADMINISTRATOR . '/components/com_menus/models/forms', $typeFile . '.xml');
- // Attempt to load the xml file.
- if ($xmlFile && !$xml = simplexml_load_file($xmlFile))
+ if ($xmlFile)
{
- throw new Exception(JText::_('JERROR_LOADFILE_FAILED'));
- }
+ if (!$xml = simplexml_load_file($xmlFile))
+ {
+ throw new Exception(JText::_('JERROR_LOADFILE_FAILED'));
+ }
- // Get the help data from the XML file if present.
- $help = $xml->xpath('/form/help');
+ // Get the help data from the XML file if present.
+ $help = $xml->xpath('/form/help');
+ }
}
if (!empty($help))
@@ -1129,14 +1194,13 @@ protected function preprocessForm(JForm $form, $data, $group = 'content')
$this->helpLocal = (($helpLoc == 'true') || ($helpLoc == '1') || ($helpLoc == 'local')) ? true : false;
}
- // Load the specific type file
- if (!$form->loadFile('item_' . $type, false, false))
+ if (!$form->loadFile($typeFile, true, false))
{
throw new Exception(JText::_('JERROR_LOADFILE_FAILED'));
}
- // Association menu items
- if (JLanguageAssociations::isEnabled())
+ // Association menu items, we currently do not support this for admin menu… may be later
+ if ($clientId == 0 && JLanguageAssociations::isEnabled())
{
$languages = JLanguageHelper::getContentLanguages(false, true, null, 'ordering', 'asc');
@@ -1182,7 +1246,7 @@ protected function preprocessForm(JForm $form, $data, $group = 'content')
*/
public function rebuild()
{
- // Initialiase variables.
+ // Initialise variables.
$db = $this->getDbo();
$query = $db->getQuery(true);
$table = $this->getTable();
@@ -1262,8 +1326,8 @@ public function save($data)
$dispatcher = JEventDispatcher::getInstance();
$pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('item.id');
$isNew = true;
- $table = $this->getTable();
- $context = $this->option . '.' . $this->name;
+ $table = $this->getTable();
+ $context = $this->option . '.' . $this->name;
// Include the plugins for the on save events.
JPluginHelper::importPlugin($this->events_map['save']);
@@ -1310,6 +1374,10 @@ public function save($data)
// We have a new item, so it is not a change.
else
{
+ $menuType = $this->getMenuType($data['menutype']);
+
+ $data['client_id'] = $menuType->client_id;
+
$table->setLocation($data['parent_id'], 'last-child');
}
@@ -1325,10 +1393,11 @@ public function save($data)
if (!$isNew && $data['id'] == 0)
{
list($title, $alias) = $this->generateNewTitle($table->parent_id, $table->alias, $table->title);
- $table->title = $title;
- $table->alias = $alias;
+
+ $table->title = $title;
+ $table->alias = $alias;
$table->published = 0;
- $table->home = 0;
+ $table->home = 0;
}
// Check the data.
@@ -1364,10 +1433,8 @@ public function save($data)
$this->setState('item.id', $table->id);
$this->setState('item.menutype', $table->menutype);
- // Load associated menu items
- $assoc = JLanguageAssociations::isEnabled();
-
- if ($assoc)
+ // Load associated menu items, for now not supported for admin menu… may be later
+ if ($table->get('client_id') == 0 && JLanguageAssociations::isEnabled())
{
// Adding self to the association
$associations = isset($data['associations']) ? $data['associations'] : array();
@@ -1541,6 +1608,12 @@ public function setHome(&$pks, $value = 1)
unset($pks[$i]);
JError::raiseNotice(403, JText::_('COM_MENUS_ERROR_ALREADY_HOME'));
}
+ elseif ($table->menutype == 'main' || $table->menutype == 'menu')
+ {
+ // Prune items that you can't change.
+ unset($pks[$i]);
+ JError::raiseWarning(403, JText::_('COM_MENUS_ERROR_MENUTYPE_HOME'));
+ }
else
{
$table->home = $value;
diff --git a/administrator/components/com_menus/models/items.php b/administrator/components/com_menus/models/items.php
index 7fc2e735290f5..655c658071713 100644
--- a/administrator/components/com_menus/models/items.php
+++ b/administrator/components/com_menus/models/items.php
@@ -108,49 +108,58 @@ protected function populateState($ordering = 'a.lft', $direction = 'asc')
$level = $this->getUserStateFromRequest($this->context . '.filter.level', 'filter_level');
$this->setState('filter.level', $level);
+ // Watch changes in client_id and menutype and keep sync whenever needed.
+ $currentClientId = $app->getUserState($this->context . '.client_id', 0);
+ $clientId = $app->input->getInt('client_id', $currentClientId);
+
$currentMenuType = $app->getUserState($this->context . '.menutype', '');
$menuType = $app->input->getString('menutype', $currentMenuType);
- // If selected menu type different from current menu type reset pagination to 0
- if ($menuType != $currentMenuType)
+ // If client_id changed clear menutype and reset pagination
+ if ($clientId != $currentClientId)
{
+ $menuType = '';
+
$app->input->set('limitstart', 0);
+ $app->input->set('menutype', '');
}
- if ($menuType)
+ // If menutype changed reset pagination.
+ if ($menuType != $currentMenuType)
{
- $db = $this->getDbo();
- $query = $db->getQuery(true)
- ->select($db->qn(array('id', 'title')))
- ->from($db->qn('#__menu_types'))
- ->where($db->qn('menutype') . ' = ' . $db->q($menuType));
-
- $menuTypeItem = $db->setQuery($query)->loadObject();
-
- // Check if menu type exists.
- if (!$menuTypeItem)
- {
- $this->setError(JText::_('COM_MENUS_ERROR_MENUTYPE_NOT_FOUND'));
- }
- // Check if menu type was changed and if valid agains ACL
- elseif ($user->authorise('core.manage', 'com_menus.menu.' . $menuTypeItem->id))
- {
- $app->setUserState($this->context . '.menutype', $menuType);
- $this->setState('menutypetitle', !empty($menuTypeItem->title) ? $menuTypeItem->title : '');
- $this->setState('menutypeid', !empty($menuTypeItem->id) ? $menuTypeItem->id : '');
- }
- // Nope, not valid
- else
- {
- $this->setError(JText::_('JERROR_ALERTNOAUTHOR'));
- }
+ $app->input->set('limitstart', 0);
}
- else
+
+ if (!$menuType)
{
$app->setUserState($this->context . '.menutype', '');
$this->setState('menutypetitle', '');
$this->setState('menutypeid', '');
}
+ // Special menu types, if selected explicitly, will be allowed as a filter
+ elseif ($menuType == 'main' || $menuType == 'menu')
+ {
+ // Adjust client_id to match the menutype. This is safe as client_id was not changed in this request.
+ $app->input->set('client_id', 1);
+
+ $app->setUserState($this->context . '.menutype', $menuType);
+ $this->setState('menutypetitle', ucfirst($menuType));
+ $this->setState('menutypeid', -1);
+ }
+ // Get the menutype object with appropriate checks.
+ elseif ($cMenu = $this->getMenu($menuType, true))
+ {
+ // Adjust client_id to match the menutype. This is safe as client_id was not changed in this request.
+ $app->input->set('client_id', $cMenu->client_id);
+
+ $app->setUserState($this->context . '.menutype', $menuType);
+ $this->setState('menutypetitle', $cMenu->title);
+ $this->setState('menutypeid', $cMenu->id);
+ }
+
+ // Client id filter
+ $clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int');
+ $this->setState('filter.client_id', $clientId);
$this->setState('filter.menutype', $menuType);
@@ -193,6 +202,7 @@ protected function getStoreId($id = '')
$id .= ':' . $this->getState('filter.search');
$id .= ':' . $this->getState('filter.parent_id');
$id .= ':' . $this->getState('filter.menutype');
+ $id .= ':' . $this->getState('filter.client_id');
return parent::getStoreId($id);
}
@@ -282,7 +292,7 @@ protected function getListQuery()
// Exclude the root category.
$query->where('a.id > 1')
- ->where('a.client_id = 0');
+ ->where('a.client_id = ' . (int) $this->getState('filter.client_id'));
// Filter on the published state.
$published = $this->getState('filter.published');
@@ -293,7 +303,7 @@ protected function getListQuery()
}
elseif ($published === '')
{
- $query->where('(a.published IN (0, 1))');
+ $query->where('a.published IN (0, 1)');
}
// Filter by search in title, alias or id
@@ -329,30 +339,31 @@ protected function getListQuery()
// Filter the items over the menu id if set.
$menuType = $this->getState('filter.menutype');
- // "" means all
+ // A value "" means all
if ($menuType == '')
{
// Load all menu types we have manage access
$query2 = $this->getDbo()->getQuery(true)
->select($this->getDbo()->qn(array('id', 'menutype')))
->from('#__menu_types')
+ ->where('client_id = ' . (int) $this->getState('filter.client_id'))
->order('title');
$menuTypes = $this->getDbo()->setQuery($query2)->loadObjectList();
- $types = array();
-
- foreach ($menuTypes as $type)
+ if ($menuTypes)
{
- if ($user->authorise('core.manage', 'com_menus.menu.' . (int) $type->id))
+ $types = array();
+
+ foreach ($menuTypes as $type)
{
- $types[] = $query->q($type->menutype);
+ if ($user->authorise('core.manage', 'com_menus.menu.' . (int) $type->id))
+ {
+ $types[] = $query->q($type->menutype);
+ }
}
- }
- if (!empty($types))
- {
- $query->where('a.menutype IN(' . implode(',', $types) . ')');
+ $query->where($types ? 'a.menutype IN(' . implode(',', $types) . ')' : 0);
}
}
// Default behavior => load all items from a specific menu
@@ -400,4 +411,108 @@ protected function getListQuery()
return $query;
}
+
+ /**
+ * Method to allow derived classes to preprocess the form.
+ *
+ * @param JForm $form A JForm object.
+ * @param mixed $data The data expected for the form.
+ * @param string $group The name of the plugin group to import (defaults to "content").
+ *
+ * @return void
+ *
+ * @since 3.2
+ * @throws Exception if there is an error in the form event.
+ */
+ protected function preprocessForm(JForm $form, $data, $group = 'content')
+ {
+ $name = $form->getName();
+
+ if ($name == 'com_menus.items.filter')
+ {
+ $clientId = $this->getState('filter.client_id');
+ $form->setFieldAttribute('menutype', 'clientid', $clientId);
+ }
+ elseif (false !== strpos($name, 'com_menus.items.modal.'))
+ {
+ $form->removeField('client_id');
+
+ $clientId = $this->getState('filter.client_id');
+ $form->setFieldAttribute('menutype', 'clientid', $clientId);
+ }
+ }
+
+ /**
+ * Get the client id for a menu
+ *
+ * @param string $menuType The menutype identifier for the menu
+ * @param bool $check Flag whether to perform check against ACL as well as existence
+ *
+ * @return int
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function getMenu($menuType, $check = false)
+ {
+ $query = $this->_db->getQuery(true);
+
+ $query->select('a.*')
+ ->from($this->_db->qn('#__menu_types', 'a'))
+ ->where('menutype = ' . $this->_db->q($menuType));
+
+ $cMenu = $this->_db->setQuery($query)->loadObject();
+
+ if ($check)
+ {
+ // Check if menu type exists.
+ if (!$cMenu)
+ {
+ $this->setError(JText::_('COM_MENUS_ERROR_MENUTYPE_NOT_FOUND'));
+ }
+ // Check if menu type is valid against ACL.
+ elseif (!JFactory::getUser()->authorise('core.manage', 'com_menus.menu.' . $cMenu->id))
+ {
+ $this->setError(JText::_('JERROR_ALERTNOAUTHOR'));
+ }
+ }
+
+ return $cMenu;
+ }
+
+ /**
+ * Method to get an array of data items.
+ *
+ * @return mixed An array of data items on success, false on failure.
+ *
+ * @since 12.2
+ */
+ public function getItems()
+ {
+ $store = $this->getStoreId();
+
+ if (!isset($this->cache[$store]))
+ {
+ $items = parent::getItems();
+ $lang = JFactory::getLanguage();
+
+ if ($items)
+ {
+ foreach ($items as $item)
+ {
+ if ($extension = $item->componentname)
+ {
+ $lang->load("$extension.sys", JPATH_ADMINISTRATOR, null, false, true)
+ || $lang->load("$extension.sys", JPATH_ADMINISTRATOR . '/components/' . $extension, null, false, true);
+ }
+
+ // Translate component name
+ $item->title = JText::_($item->title);
+ }
+ }
+
+ $this->cache[$store] = $items;
+ }
+
+ return $this->cache[$store];
+ }
}
diff --git a/administrator/components/com_menus/models/menus.php b/administrator/components/com_menus/models/menus.php
index c8d7cbc77ce87..6c7f8e6dc566e 100644
--- a/administrator/components/com_menus/models/menus.php
+++ b/administrator/components/com_menus/models/menus.php
@@ -34,6 +34,7 @@ public function __construct($config = array())
'id', 'a.id',
'title', 'a.title',
'menutype', 'a.menutype',
+ 'client_id', 'a.client_id',
);
}
@@ -138,9 +139,9 @@ public function getItems()
// Inject the values back into the array.
foreach ($items as $item)
{
- $item->count_published = isset($countPublished[$item->menutype]) ? $countPublished[$item->menutype] : 0;
+ $item->count_published = isset($countPublished[$item->menutype]) ? $countPublished[$item->menutype] : 0;
$item->count_unpublished = isset($countUnpublished[$item->menutype]) ? $countUnpublished[$item->menutype] : 0;
- $item->count_trashed = isset($countTrashed[$item->menutype]) ? $countTrashed[$item->menutype] : 0;
+ $item->count_trashed = isset($countTrashed[$item->menutype]) ? $countTrashed[$item->menutype] : 0;
}
// Add the items to the internal cache.
@@ -163,10 +164,12 @@ protected function getListQuery()
$query = $db->getQuery(true);
// Select all fields from the table.
- $query->select($this->getState('list.select', 'a.id, a.menutype, a.title, a.description'))
+ $query->select($this->getState('list.select', 'a.id, a.menutype, a.title, a.description, a.client_id'))
->from($db->quoteName('#__menu_types') . ' AS a')
->where('a.id > 0');
+ $query->where('a.client_id = ' . (int) $this->getState('client_id'));
+
// Filter by search in title or menutype
if ($search = trim($this->getState('filter.search')))
{
@@ -194,9 +197,12 @@ protected function getListQuery()
*/
protected function populateState($ordering = 'a.title', $direction = 'asc')
{
- $search = $this->getUserStateFromRequest($this->context . '.search', 'filter_search');
+ $search = $this->getUserStateFromRequest($this->context . '.search', 'filter_search');
$this->setState('filter.search', $search);
+ $clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int');
+ $this->setState('client_id', $clientId);
+
// List state information.
parent::populateState($ordering, $direction);
}
@@ -210,13 +216,13 @@ protected function populateState($ordering = 'a.title', $direction = 'asc')
*/
public function getModMenuId()
{
- $db = $this->getDbo();
+ $db = $this->getDbo();
$query = $db->getQuery(true)
->select('e.extension_id')
->from('#__extensions AS e')
->where('e.type = ' . $db->quote('module'))
->where('e.element = ' . $db->quote('mod_menu'))
- ->where('e.client_id = 0');
+ ->where('e.client_id = ' . (int) $this->getState('client_id'));
$db->setQuery($query);
return $db->loadResult();
diff --git a/administrator/components/com_menus/models/menutypes.php b/administrator/components/com_menus/models/menutypes.php
index 85e429b2db640..79aab9ed78b6c 100644
--- a/administrator/components/com_menus/models/menutypes.php
+++ b/administrator/components/com_menus/models/menutypes.php
@@ -25,6 +25,28 @@ class MenusModelMenutypes extends JModelLegacy
*/
protected $rlu = array();
+ /**
+ * Method to auto-populate the model state.
+ *
+ * This method should only be called once per instantiation and is designed
+ * to be called on the first call to the getState() method unless the model
+ * configuration flag to ignore the request is set.
+ *
+ * @return void
+ *
+ * @note Calling getState in this method will result in recursion.
+ * @since 12.2
+ */
+ protected function populateState()
+ {
+ parent::populateState();
+
+ $app = JFactory::getApplication();
+ $clientId = $app->input->get('client_id', 0);
+
+ $this->state->set('client_id', $clientId);
+ }
+
/**
* Method to get the reverse lookup of the base link URL to Title
*
@@ -57,7 +79,7 @@ public function getTypeOptions()
$list = array();
// Get the list of components.
- $db = $this->getDbo();
+ $db = $this->getDbo();
$query = $db->getQuery(true)
->select('name, element AS ' . $db->quoteName('option'))
->from('#__extensions')
@@ -69,7 +91,9 @@ public function getTypeOptions()
foreach ($components as $component)
{
- if ($options = $this->getTypeOptionsByComponent($component->option))
+ $options = $this->getTypeOptionsByComponent($component->option);
+
+ if ($options)
{
$list[$component->name] = $options;
@@ -124,8 +148,8 @@ public function addReverseLookupUrl($option)
protected function getTypeOptionsByComponent($component)
{
$options = array();
-
- $mainXML = JPATH_SITE . '/components/' . $component . '/metadata.xml';
+ $client = JApplicationHelper::getClientInfo($this->getState('client_id'));
+ $mainXML = $client->path . '/components/' . $component . '/metadata.xml';
if (is_file($mainXML))
{
@@ -137,6 +161,11 @@ protected function getTypeOptionsByComponent($component)
$options = $this->getTypeOptionsFromMvc($component);
}
+ if ($client->id == 1 && empty($options))
+ {
+ $options = $this->getTypeOptionsFromManifest($component);
+ }
+
return $options;
}
@@ -146,7 +175,7 @@ protected function getTypeOptionsByComponent($component)
* @param string $file File path
* @param string $component Component option as in URL
*
- * @return array
+ * @return array|bool
*
* @since 1.6
*/
@@ -199,31 +228,29 @@ protected function getTypeOptionsFromXml($file, $component)
{
return false;
}
- else
+
+ // Process each child as an option.
+ foreach ($children as $child)
{
- // Process each child as an option.
- foreach ($children as $child)
+ if ($child->getName() == 'option')
{
- if ($child->getName() == 'option')
- {
- // Create the menu option for the component.
- $o = new JObject;
- $o->title = (string) $child['name'];
- $o->description = (string) $child['msg'];
- $o->request = array('option' => $component, (string) $optionsNode['var'] => (string) $child['value']);
+ // Create the menu option for the component.
+ $o = new JObject;
+ $o->title = (string) $child['name'];
+ $o->description = (string) $child['msg'];
+ $o->request = array('option' => $component, (string) $optionsNode['var'] => (string) $child['value']);
- $options[] = $o;
- }
- elseif ($child->getName() == 'default')
- {
- // Create the menu option for the component.
- $o = new JObject;
- $o->title = (string) $child['name'];
- $o->description = (string) $child['msg'];
- $o->request = array('option' => $component);
+ $options[] = $o;
+ }
+ elseif ($child->getName() == 'default')
+ {
+ // Create the menu option for the component.
+ $o = new JObject;
+ $o->title = (string) $child['name'];
+ $o->description = (string) $child['msg'];
+ $o->request = array('option' => $component);
- $options[] = $o;
- }
+ $options[] = $o;
}
}
@@ -235,18 +262,19 @@ protected function getTypeOptionsFromXml($file, $component)
*
* @param string $component Component option like in URLs
*
- * @return array
+ * @return array|bool
*
* @since 1.6
*/
protected function getTypeOptionsFromMvc($component)
{
$options = array();
+ $client = JApplicationHelper::getClientInfo($this->getState('client_id'));
// Get the views for this component.
- if (is_dir(JPATH_SITE . '/components/' . $component))
+ if (is_dir($client->path . '/components/' . $component))
{
- $folders = JFolder::folders(JPATH_SITE . '/components/' . $component, '^view[s]?$', false, true);
+ $folders = JFolder::folders($client->path . '/components/' . $component, '^view[s]?$', false, true);
}
$path = '';
@@ -344,6 +372,104 @@ protected function getTypeOptionsFromMvc($component)
return $options;
}
+ /**
+ * Get menu types from Component manifest
+ *
+ * @param string $component Component option like in URLs
+ *
+ * @return array|bool
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function getTypeOptionsFromManifest($component)
+ {
+ // Load the component manifest
+ $fileName = JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml';
+
+ if (!is_file($fileName))
+ {
+ return false;
+ }
+
+ if (!($manifest = simplexml_load_file($fileName)))
+ {
+ return false;
+ }
+
+ // Check for a valid XML root tag.
+ if ($manifest->getName() != 'extension')
+ {
+ return false;
+ }
+
+ $options = array();
+
+ // Start with the component root menu.
+ $rootMenu = $manifest->administration->menu;
+
+ // If the menu item doesn't exist or is hidden do nothing.
+ if (!$rootMenu || in_array((string) $rootMenu['hidden'], array('true', 'hidden')))
+ {
+ return $options;
+ }
+
+ // Create the root menu option.
+ $ro = new stdClass;
+ $ro->title = (string) trim($rootMenu);
+ $ro->description = '';
+ $ro->request = array('option' => $component);
+
+ // Process submenu options.
+ $submenu = $manifest->administration->submenu;
+
+ if (!$submenu)
+ {
+ return $options;
+ }
+
+ foreach ($submenu->menu as $child)
+ {
+ $attributes = $child->attributes();
+
+ $o = new stdClass;
+ $o->title = (string) trim($child);
+ $o->description = '';
+
+ if ((string) $attributes->link)
+ {
+ parse_str((string) $attributes->link, $request);
+ }
+ else
+ {
+ $request = array();
+
+ $request['option'] = $component;
+ $request['act'] = (string) $attributes->act;
+ $request['task'] = (string) $attributes->task;
+ $request['controller'] = (string) $attributes->controller;
+ $request['view'] = (string) $attributes->view;
+ $request['layout'] = (string) $attributes->layout;
+ $request['sub'] = (string) $attributes->sub;
+ }
+
+ $o->request = array_filter($request, 'strlen');
+ $options[] = new JObject($o);
+
+ // Do not repeat the default view link (index.php?option=com_abc).
+ if (count($o->request) == 1)
+ {
+ $ro = null;
+ }
+ }
+
+ if ($ro)
+ {
+ $options[] = new JObject($ro);
+ }
+
+ return $options;
+ }
+
/**
* Get the menu types from component layouts
*
@@ -361,11 +487,12 @@ protected function getTypeOptionsFromLayouts($component, $view)
$layoutNames = array();
$lang = JFactory::getLanguage();
$path = '';
+ $client = JApplicationHelper::getClientInfo($this->getState('client_id'));
// Get the views for this component.
- if (is_dir(JPATH_SITE . '/components/' . $component))
+ if (is_dir($client->path . '/components/' . $component))
{
- $folders = JFolder::folders(JPATH_SITE . '/components/' . $component, '^view[s]?$', false, true);
+ $folders = JFolder::folders($client->path . '/components/' . $component, '^view[s]?$', false, true);
}
if (!empty($folders[0]))
@@ -395,7 +522,7 @@ protected function getTypeOptionsFromLayouts($component, $view)
// Get the template layouts
// TODO: This should only search one template -- the current template for this item (default of specified)
- $folders = JFolder::folders(JPATH_SITE . '/templates', '', false, true);
+ $folders = JFolder::folders($client->path . '/templates', '', false, true);
// Array to hold association between template file names and templates
$templateName = array();
@@ -405,8 +532,8 @@ protected function getTypeOptionsFromLayouts($component, $view)
if (is_dir($folder . '/html/' . $component . '/' . $view))
{
$template = basename($folder);
- $lang->load('tpl_' . $template . '.sys', JPATH_SITE, null, false, true)
- || $lang->load('tpl_' . $template . '.sys', JPATH_SITE . '/templates/' . $template, null, false, true);
+ $lang->load('tpl_' . $template . '.sys', $client->path, null, false, true)
+ || $lang->load('tpl_' . $template . '.sys', $client->path . '/templates/' . $template, null, false, true);
$templateLayouts = JFolder::files($folder . '/html/' . $component . '/' . $view, '.xml$', false, true);
diff --git a/administrator/components/com_menus/views/item/tmpl/edit.php b/administrator/components/com_menus/views/item/tmpl/edit.php
index de72294593e76..12cd2122a5806 100644
--- a/administrator/components/com_menus/views/item/tmpl/edit.php
+++ b/administrator/components/com_menus/views/item/tmpl/edit.php
@@ -87,12 +87,12 @@
// Add the script to the document head.
JFactory::getDocument()->addScriptDeclaration($script);
// In case of modal
-$isModal = $input->get('layout') == 'modal' ? true : false;
-$layout = $isModal ? 'modal' : 'edit';
-$tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : '';
+$isModal = $input->get('layout') == 'modal' ? true : false;
+$layout = $isModal ? 'modal' : 'edit';
+$tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : '';
+$clientId = $this->state->get('item.client_id', 0);
?>
-
-