first commit

This commit is contained in:
2025-06-17 11:53:18 +02:00
commit 9f0f7ba12b
8804 changed files with 1369176 additions and 0 deletions

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<access component="com_menus">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" />
<action name="core.options" title="JACTION_OPTIONS" />
<action name="core.manage" title="JACTION_MANAGE" />
<action name="core.create" title="JACTION_CREATE" />
<action name="core.delete" title="JACTION_DELETE" />
<action name="core.edit" title="JACTION_EDIT" />
<action name="core.edit.state" title="JACTION_EDITSTATE" />
</section>
<section name="menu">
<action name="core.manage" title="JACTION_MANAGE" />
<action name="core.create" title="JACTION_CREATE" />
<action name="core.delete" title="JACTION_DELETE" />
<action name="core.edit" title="JACTION_EDIT" />
<action name="core.edit.state" title="JACTION_EDITSTATE" />
</section>
</access>

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<help key="Menus:_Options"/>
<inlinehelp button="show"/>
<fieldset
name="page-options"
label="COM_MENUS_PAGE_OPTIONS_LABEL"
>
<field
name="page_title"
type="text"
label="COM_MENUS_ITEM_FIELD_PAGE_TITLE_LABEL"
default=""
/>
<field
name="show_page_heading"
type="radio"
layout="joomla.form.field.radio.switcher"
label="COM_MENUS_ITEM_FIELD_SHOW_PAGE_HEADING_LABEL"
default="0"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="page_heading"
type="text"
label="COM_MENUS_ITEM_FIELD_PAGE_HEADING_LABEL"
default=""
showon="show_page_heading:1"
/>
<field
name="pageclass_sfx"
type="text"
label="COM_MENUS_ITEM_FIELD_PAGE_CLASS_LABEL"
validate="CssIdentifier"
/>
</fieldset>
<fieldset
name="permissions"
label="JCONFIG_PERMISSIONS_LABEL"
description="JCONFIG_PERMISSIONS_DESC"
>
<field
name="rules"
type="rules"
label="JCONFIG_PERMISSIONS_LABEL"
filter="rules"
validate="rules"
component="com_menus"
section="component"
/>
</fieldset>
</config>

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<field
name="client_id"
type="list"
label="JSITEADMIN"
filtermode="selector"
class="js-select-reset-on-change"
validate="options"
>
<option value="0">JSITE</option>
<option value="1">JADMINISTRATOR</option>
</field>
<field
name="menutype"
type="menu"
label="COM_MENUS_SELECT_MENU_FILTER"
accesstype="manage"
clientid=""
showAll="false"
filtermode="selector"
class="js-select-submit-on-change"
>
<option value="">COM_MENUS_SELECT_MENU</option>
</field>
<fields name="filter">
<field
name="search"
type="text"
inputmode="search"
label="COM_MENUS_ITEMS_SEARCH_FILTER_LABEL"
description="COM_MENUS_ITEMS_SEARCH_FILTER"
hint="JSEARCH_FILTER"
noresults="JGLOBAL_NO_MATCHING_RESULTS"
/>
<field
name="published"
type="status"
label="JSTATUS"
optionsFilter="*,0,1,-2"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_PUBLISHED</option>
</field>
<field
name="access"
type="accesslevel"
label="JGRID_HEADING_ACCESS"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_ACCESS</option>
</field>
<field
name="language"
type="contentlanguage"
label="JGRID_HEADING_LANGUAGE"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_LANGUAGE</option>
<option value="*">JALL</option>
</field>
<field
name="level"
type="integer"
label="JGLOBAL_MAXLEVEL_LABEL"
first="1"
last="10"
step="1"
languages="*"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_MAX_LEVELS</option>
</field>
<field
name="parent_id"
type="MenuItemByType"
label="COM_MENUS_FILTER_PARENT_MENU_ITEM_LABEL"
class="js-select-submit-on-change"
>
<option value="">COM_MENUS_FILTER_SELECT_PARENT_MENU_ITEM</option>
</field>
<field
name="componentName"
type="MenuItemByComponent"
label="COM_MENUS_FILTER_COMPONENT_LABEL"
class="js-select-submit-on-change"
>
<option value="">COM_MENUS_OPTION_SELECT_COMPONENT</option>
</field>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
statuses="*,0,1,2,-2"
class="js-select-submit-on-change"
default="a.lft ASC"
validate="options"
>
<option value="">JGLOBAL_SORT_BY</option>
<option value="a.lft ASC">JGRID_HEADING_ORDERING_ASC</option>
<option value="a.lft DESC">JGRID_HEADING_ORDERING_DESC</option>
<option value="a.published ASC">JSTATUS_ASC</option>
<option value="a.published DESC">JSTATUS_DESC</option>
<option value="a.title ASC">JGLOBAL_TITLE_ASC</option>
<option value="a.title DESC">JGLOBAL_TITLE_DESC</option>
<option value="menutype_title ASC">COM_MENUS_HEADING_MENU_ASC</option>
<option value="menutype_title DESC">COM_MENUS_HEADING_MENU_DESC</option>
<option value="a.home ASC">COM_MENUS_HEADING_HOME_ASC</option>
<option value="a.home DESC">COM_MENUS_HEADING_HOME_DESC</option>
<option value="a.access ASC">JGRID_HEADING_ACCESS_ASC</option>
<option value="a.access DESC">JGRID_HEADING_ACCESS_DESC</option>
<option value="association ASC" requires="associations">JASSOCIATIONS_ASC</option>
<option value="association DESC" requires="associations">JASSOCIATIONS_DESC</option>
<option value="language ASC" requires="multilanguage">JGRID_HEADING_LANGUAGE_ASC</option>
<option value="language DESC" requires="multilanguage">JGRID_HEADING_LANGUAGE_DESC</option>
<option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
</field>
<field
name="limit"
type="limitbox"
label="JGLOBAL_LIST_LIMIT"
default="25"
class="js-select-submit-on-change"
/>
</fields>
</form>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<field
name="client_id"
type="list"
label="JSITEADMIN"
filtermode="selector"
class="js-select-reset-on-change"
validate="options"
>
<option value="0">JSITE</option>
<option value="1">JADMINISTRATOR</option>
</field>
<field
name="menutype"
type="menu"
label="COM_MENUS_SELECT_MENU_FILTER"
accesstype="manage"
clientid=""
showAll="false"
filtermode="selector"
class="js-select-submit-on-change"
>
<option value="">COM_MENUS_SELECT_MENU</option>
</field>
<fields name="filter">
<field
name="search"
type="text"
inputmode="search"
label="COM_MENUS_ITEMS_SEARCH_FILTER_LABEL"
description="COM_MENUS_ITEMS_SEARCH_FILTER"
hint="JSEARCH_FILTER"
noresults="JGLOBAL_NO_MATCHING_RESULTS"
/>
<field
name="published"
type="status"
label="JSTATUS"
optionsFilter="*,0,1,-2"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_PUBLISHED</option>
</field>
<field
name="level"
type="integer"
label="JGLOBAL_MAXLEVEL_LABEL"
first="1"
last="10"
step="1"
languages="*"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_MAX_LEVELS</option>
</field>
<field
name="parent_id"
type="MenuItemByType"
label="COM_MENUS_FILTER_PARENT_MENU_ITEM_LABEL"
client_id="1"
class="js-select-submit-on-change"
>
<option value="">COM_MENUS_FILTER_SELECT_PARENT_MENU_ITEM</option>
</field>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
statuses="*,0,1,2,-2"
class="js-select-submit-on-change"
default="a.lft ASC"
validate="options"
>
<option value="">JGLOBAL_SORT_BY</option>
<option value="a.lft ASC">JGRID_HEADING_ORDERING_ASC</option>
<option value="a.lft DESC">JGRID_HEADING_ORDERING_DESC</option>
<option value="a.published ASC">JSTATUS_ASC</option>
<option value="a.published DESC">JSTATUS_DESC</option>
<option value="a.title ASC">JGLOBAL_TITLE_ASC</option>
<option value="a.title DESC">JGLOBAL_TITLE_DESC</option>
<option value="menutype_title ASC">COM_MENUS_HEADING_MENU_ASC</option>
<option value="menutype_title DESC">COM_MENUS_HEADING_MENU_DESC</option>
<option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
</field>
<field
name="limit"
type="limitbox"
label="JGLOBAL_LIST_LIMIT"
default="25"
class="js-select-submit-on-change"
/>
</fields>
</form>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<field
name="client_id"
type="list"
label="JSITEADMIN"
filtermode="selector"
class="js-select-submit-on-change"
validate="options"
>
<option value="0">JSITE</option>
<option value="1">JADMINISTRATOR</option>
</field>
<fields name="filter">
<field
name="search"
type="text"
inputmode="search"
label="COM_MENUS_MENUS_FILTER_SEARCH_LABEL"
description="COM_MENUS_MENUS_FILTER_SEARCH_DESC"
hint="JSEARCH_FILTER"
/>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
class="js-select-submit-on-change"
default="a.title ASC"
validate="options"
>
<option value="">JGLOBAL_SORT_BY</option>
<option value="a.ordering ASC">JGRID_HEADING_ORDERING_ASC</option>
<option value="a.ordering DESC">JGRID_HEADING_ORDERING_DESC</option>
<option value="a.title ASC">JGLOBAL_TITLE_ASC</option>
<option value="a.title DESC">JGLOBAL_TITLE_DESC</option>
<option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
</field>
<field
name="limit"
type="limitbox"
label="JGLOBAL_LIST_LIMIT"
default="5"
class="js-select-submit-on-change"
/>
</fields>
</form>

View File

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<fieldset>
<field
name="id"
type="hidden"
label="JGLOBAL_FIELD_ID_LABEL"
class="readonly"
default="0"
filter="int"
readonly="true"
/>
<field
name="title"
type="text"
label="COM_MENUS_ITEM_FIELD_TITLE_LABEL"
required="true"
/>
<field
name="alias"
type="alias"
label="JFIELD_ALIAS_LABEL"
description="JFIELD_ALIAS_DESC"
hint="JFIELD_ALIAS_PLACEHOLDER"
/>
<field
name="note"
type="text"
label="JFIELD_NOTE_LABEL"
maxlength="255"
/>
<field
name="link"
type="link"
label="COM_MENUS_ITEM_FIELD_LINK_LABEL"
readonly="true"
/>
<field
name="menutype"
type="menu"
label="COM_MENUS_ITEM_FIELD_ASSIGNED_LABEL"
required="true"
clientid="0"
>
<option value="">COM_MENUS_SELECT_MENU</option>
</field>
<field
name="type"
type="menutype"
label="COM_MENUS_ITEM_FIELD_TYPE_LABEL"
required="true"
/>
<field
name="published"
type="list"
label="JSTATUS"
class="form-select-color-state"
default="1"
filter="integer"
validate="options"
>
<option value="1">JPUBLISHED</option>
<option value="0">JUNPUBLISHED</option>
<option value="-2">JTRASHED</option>
</field>
<field
name="publish_up"
type="calendar"
label="JGLOBAL_FIELD_PUBLISH_UP_LABEL"
translateformat="true"
showtime="true"
filter="user_utc"
showon="home:0"
/>
<field
name="publish_down"
type="calendar"
label="JGLOBAL_FIELD_PUBLISH_DOWN_LABEL"
translateformat="true"
showtime="true"
filter="user_utc"
showon="home:0"
/>
<field
name="parent_id"
type="MenuParent"
label="COM_MENUS_ITEM_FIELD_PARENT_LABEL"
layout="joomla.form.field.list-fancy-select"
default="1"
filter="int"
clientid="0"
>
<option value="1">JGLOBAL_ROOT_PARENT</option>
</field>
<field
name="menuordering"
type="MenuOrdering"
label="COM_MENUS_ITEM_FIELD_ORDERING_LABEL"
filter="int"
/>
<field
name="component_id"
type="hidden"
filter="int"
/>
<field
name="browserNav"
type="list"
label="COM_MENUS_ITEM_FIELD_BROWSERNAV_LABEL"
default="0"
filter="int"
validate="options"
>
<option value="0">COM_MENUS_FIELD_VALUE_PARENT</option>
<option value="1">COM_MENUS_FIELD_VALUE_NEW_WITH_NAV</option>
<option value="2">COM_MENUS_FIELD_VALUE_NEW_WITHOUT_NAV</option>
</field>
<field
name="access"
type="accesslevel"
label="JFIELD_ACCESS_LABEL"
filter="UINT"
validate="options"
/>
<field
name="template_style_id"
type="templatestyle"
label="COM_MENUS_ITEM_FIELD_TEMPLATE_LABEL"
client="site"
filter="int"
showon="type!:alias[OR]params.alias_redirect:0"
>
<option value="0">JOPTION_USE_DEFAULT</option>
</field>
<field
name="home"
type="radio"
label="COM_MENUS_ITEM_FIELD_HOME_LABEL"
default="0"
layout="joomla.form.field.radio.switcher"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="language"
type="contentlanguage"
label="JFIELD_LANGUAGE_LABEL"
>
<option value="*">JALL</option>
</field>
<field
name="path"
type="hidden"
filter="unset"
/>
<field
name="level"
type="hidden"
filter="unset"
/>
<field
name="checked_out"
type="hidden"
filter="unset"
/>
<field
name="checked_out_time"
type="hidden"
filter="unset"
/>
<field
name="lft"
type="hidden"
filter="unset"
/>
<field
name="rgt"
type="hidden"
filter="unset"
/>
<field
name="toggle_modules_assigned"
type="radio"
label="COM_MENUS_ITEM_FIELD_HIDE_UNASSIGNED_LABEL"
default="1"
layout="joomla.form.field.radio.switcher"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="toggle_modules_published"
type="radio"
label="COM_MENUS_ITEM_FIELD_HIDE_UNPUBLISHED_LABEL"
default="1"
layout="joomla.form.field.radio.switcher"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
</fieldset>
<fields name="params">
</fields>
</form>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<!-- Add fields to the request variables for the layout. -->
<fields name="params">
<fieldset name="aliasoptions">
<field
name="aliasoptions"
type="modal_menu"
label="COM_MENUS_ITEM_FIELD_ALIAS_MENU_LABEL"
clientid="0"
required="true"
select="true"
new="true"
edit="true"
clear="true"
/>
<field
name="alias_redirect"
type="radio"
label="COM_MENUS_ITEM_FIELD_ALIAS_REDIRECT_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu-anchor_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_icon_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
default="1"
filter="integer"
layout="joomla.form.field.radio.switcher"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
<help key="Menu_Item:_Alias" />
</form>

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params" label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<fieldset name="menu-options" label="COM_MENUS_LINKTYPE_OPTIONS_LABEL">
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu-anchor_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_icon_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
<fieldset name="page-options" label="COM_MENUS_PAGE_OPTIONS_LABEL">
<field
name="page_title"
type="text"
label="COM_MENUS_ITEM_FIELD_PAGE_TITLE_LABEL"
useglobal="true"
/>
<field
name="show_page_heading"
type="list"
label="COM_MENUS_ITEM_FIELD_SHOW_PAGE_HEADING_LABEL"
class="form-select-color-state"
default=""
useglobal="true"
validate="options"
>
<option value="1">JSHOW</option>
<option value="0">JHIDE</option>
</field>
<field
name="page_heading"
type="text"
label="COM_MENUS_ITEM_FIELD_PAGE_HEADING_LABEL"
/>
<field
name="pageclass_sfx"
type="text"
label="COM_MENUS_ITEM_FIELD_PAGE_CLASS_LABEL"
validate="CssIdentifier"
/>
</fieldset>
<fieldset name="metadata" label="JGLOBAL_FIELDSET_METADATA_OPTIONS">
<field
name="menu-meta_description"
type="textarea"
label="JFIELD_META_DESCRIPTION_LABEL"
rows="3"
cols="30"
maxlength="300"
charcounter="true"
/>
<field
name="robots"
type="list"
label="JFIELD_METADATA_ROBOTS_LABEL"
validate="options"
>
<option value="">JGLOBAL_USE_GLOBAL</option>
<option value="index, follow" />
<option value="noindex, follow" />
<option value="index, nofollow" />
<option value="noindex, nofollow" />
</field>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu-anchor_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_icon_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
<help key="Menu_Item:_Heading" />
</form>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_icon_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
<help key="Menu_Item:_Separator" />
</form>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset name="menu-options" label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu-anchor_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_icon_css"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu-anchor_rel"
type="list"
label="COM_MENUS_ITEM_FIELD_ANCHOR_REL_LABEL"
default=""
validate="options"
>
<option value="">JNONE</option>
<option value="alternate"/>
<option value="author"/>
<option value="bookmark"/>
<option value="external"/>
<option value="help"/>
<option value="license"/>
<option value="me"/>
<option value="next"/>
<option value="nofollow"/>
<option value="noopener"/>
<option value="noreferrer"/>
<option value="prefetch"/>
<option value="prev"/>
<option value="search"/>
<option value="sponsored"/>
<option value="tag"/>
<option value="ugc"/>
</field>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
<help key="Menu_Item:_URL" />
</form>

View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<fieldset>
<field
name="id"
type="hidden"
label="JGLOBAL_FIELD_ID_LABEL"
class="readonly"
default="0"
filter="int"
readonly="true"
/>
<field
name="title"
type="text"
label="COM_MENUS_ITEM_FIELD_TITLE_LABEL"
required="true"
/>
<field
name="alias"
type="alias"
label="JFIELD_ALIAS_LABEL"
description="JFIELD_ALIAS_DESC"
hint="JFIELD_ALIAS_PLACEHOLDER"
/>
<field
name="note"
type="text"
label="JFIELD_NOTE_LABEL"
maxlength="255"
class="col-md-12"
/>
<field
name="link"
type="link"
label="COM_MENUS_ITEM_FIELD_LINK_LABEL"
readonly="true"
/>
<field
name="menutype"
type="menu"
label="COM_MENUS_ITEM_FIELD_ASSIGNED_LABEL"
required="true"
clientid="1"
>
<option value="">COM_MENUS_SELECT_MENU</option>
</field>
<field
name="type"
type="menutype"
label="COM_MENUS_ITEM_FIELD_TYPE_LABEL"
required="true"
/>
<field
name="published"
type="list"
label="JSTATUS"
class="form-select-color-state"
default="1"
filter="integer"
validate="options"
>
<option value="1">JPUBLISHED</option>
<option value="0">JUNPUBLISHED</option>
<option value="-2">JTRASHED</option>
</field>
<field
name="parent_id"
type="MenuParent"
label="COM_MENUS_ITEM_FIELD_PARENT_LABEL"
default="1"
filter="int"
clientid="1"
>
<option value="1">JGLOBAL_ROOT_PARENT</option>
</field>
<field
name="menuordering"
type="MenuOrdering"
label="COM_MENUS_ITEM_FIELD_ORDERING_LABEL"
filter="int"
/>
<field
name="component_id"
type="hidden"
filter="int"
/>
<field
name="browserNav"
type="list"
label="COM_MENUS_ITEM_FIELD_BROWSERNAV_LABEL"
default="0"
filter="int"
validate="options"
>
<option value="0">COM_MENUS_FIELD_VALUE_PARENT</option>
<option value="1">COM_MENUS_FIELD_VALUE_NEW_WITH_NAV</option>
</field>
<field
name="home"
type="hidden"
default="0"
/>
<field
name="access"
type="hidden"
default="0"
/>
<field
name="template_style_id"
type="hidden"
default="0"
/>
<field
name="language"
type="hidden"
default="*"
/>
<field
name="path"
type="hidden"
filter="unset"
/>
<field
name="level"
type="hidden"
filter="unset"
/>
<field
name="checked_out"
type="hidden"
filter="unset"
/>
<field
name="checked_out_time"
type="hidden"
filter="unset"
/>
<field
name="lft"
type="hidden"
filter="unset"
/>
<field
name="rgt"
type="hidden"
filter="unset"
/>
</fieldset>
<fields name="params">
</fields>
</form>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<!-- Add fields to the request variables for the layout. -->
<fields name="params">
<fieldset name="aliasoptions">
<field
name="aliasoptions"
type="modal_menu"
label="COM_MENUS_ITEM_FIELD_ALIAS_MENU_LABEL"
clientid="1"
required="true"
select="true"
new="true"
edit="true"
clear="true"
/>
</fieldset>
<fieldset
name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu_icon"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
<help key="Menu_Item:_Alias"/>
</form>

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params" label="COM_MENUS_LINKTYPE_OPTIONS_LABEL">
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu_icon"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset>
<!-- Container type menu item does not have a navigation -->
<field
name="link"
type="hidden"
/>
<field
name="browserNav"
type="hidden"
default="0"
/>
</fieldset>
<fields name="params">
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu_icon"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
<field
name="hideitems"
type="checkboxes"
label="COM_MENUS_ITEM_FIELD_COMPONENTS_CONTAINER_HIDE_ITEMS_LABEL"
description="COM_MENUS_ITEM_FIELD_COMPONENTS_CONTAINER_HIDE_ITEMS_DESC"
filter="array"
/>
</fields>
<help key="Menu_Item:_Components_Menu_Container"/>
</form>

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset>
<!-- Heading type menu item does not have a navigation -->
<field
name="link"
type="hidden"
/>
<field
name="browserNav"
type="hidden"
default="0"
/>
</fieldset>
<fields name="params">
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu_icon"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="dashboard"
type="text"
label="COM_MENUS_ITEM_FIELD_DASHBOARD_LABEL"
description="COM_MENUS_ITEM_FIELD_DASHBOARD_DESC"
filter="cmd"
/>
</fieldset>
</fields>
<help key="Menu_Item:_Heading"/>
</form>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset>
<!-- Text separator type menu item does not have a navigation -->
<field
name="link"
type="hidden"
/>
<field
name="browserNav"
type="hidden"
default="0"
/>
<fields name="params">
<field
name="text_separator"
type="radio"
label="COM_MENUS_ITEM_FIELD_TEXT_SEPARATOR_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
>
<option value="0">COM_MENUS_ITEM_FIELD_TEXT_SEPARATOR_AS_LABEL</option>
<option value="1">COM_MENUS_ITEM_FIELD_TEXT_SEPARATOR_AS_SEPARATOR</option>
</field>
</fields>
</fieldset>
<help key="Menu_Item:_Separator" />
</form>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset name="menu-options"
label="COM_MENUS_LINKTYPE_OPTIONS_LABEL"
>
<field
name="menu-anchor_title"
type="text"
label="COM_MENUS_ITEM_FIELD_ANCHOR_TITLE_LABEL"
/>
<field
name="menu-anchor_rel"
type="list"
label="COM_MENUS_ITEM_FIELD_ANCHOR_REL_LABEL"
default=""
validate="options"
>
<option value="">JNONE</option>
<option value="alternate"/>
<option value="author"/>
<option value="bookmark"/>
<option value="external"/>
<option value="help"/>
<option value="license"/>
<option value="me"/>
<option value="next"/>
<option value="nofollow"/>
<option value="noopener"/>
<option value="noreferrer"/>
<option value="prefetch"/>
<option value="prev"/>
<option value="search"/>
<option value="sponsored"/>
<option value="tag"/>
<option value="ugc"/>
</field>
<field
name="menu_icon"
type="text"
label="COM_MENUS_ITEM_FIELD_ICON_TITLE_LABEL"
description="COM_MENUS_ITEM_FIELD_ICON_TITLE_DESC"
validate="CssIdentifier"
/>
<field
type="spacer"
/>
<field
name="menu_image"
type="media"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_LABEL"
/>
<field
name="menu_image_css"
type="text"
label="COM_MENUS_ITEM_FIELD_MENU_IMAGE_CSS_LABEL"
validate="CssIdentifier"
/>
<field
name="menu_text"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_TEXT_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="menu_show"
type="radio"
label="COM_MENUS_ITEM_FIELD_MENU_SHOW_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
<help key="Menu_Item:_URL" />
</form>

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Menus\Administrator\Field">
<fieldset>
<field
name="id"
type="hidden"
default="0"
filter="int"
readonly="true"
/>
<field
name="asset_id"
type="hidden"
filter="unset"
/>
<field
name="menutype"
type="text"
label="COM_MENUS_MENU_MENUTYPE_LABEL"
maxlength="24"
required="true"
/>
<field
name="title"
type="text"
label="JGLOBAL_TITLE"
maxlength="48"
required="true"
/>
<field
name="description"
type="text"
label="JGLOBAL_DESCRIPTION"
id="menudescription"
maxlength="255"
/>
<field
name="client_id"
type="hidden"
/>
<field
name="preset"
type="menuPreset"
label="COM_MENUS_FIELD_PRESET_LABEL"
description="COM_MENUS_FIELD_PRESET_DESC"
>
<option value="">JNONE</option>
</field>
<field
name="rules"
type="rules"
label="JFIELD_RULES_LABEL"
translate_label="false"
filter="rules"
component="com_menus"
section="menu"
validate="rules"
/>
</fieldset>
</form>

View File

@ -0,0 +1,27 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*
* @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
*/
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menus component helper.
*
* @since 1.6
*
* @deprecated 4.3 will be removed in 6.0
* Use \Joomla\Component\Menus\Administrator\Helper\MenusHelper instead
*/
class MenusHelper extends \Joomla\Component\Menus\Administrator\Helper\MenusHelper
{
}

View File

@ -0,0 +1,83 @@
<?php
/**
* @package Joomla.Site
* @subpackage Layout
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
extract($displayData);
/**
* Layout variables
* -----------------
* @var string $autocomplete Autocomplete attribute for the field.
* @var boolean $autofocus Is autofocus enabled?
* @var string $class Classes for the input.
* @var string $description Description of the field.
* @var boolean $disabled Is this field disabled?
* @var string $group Group the field belongs to. <fields> section in form XML.
* @var boolean $hidden Is this field hidden in the form?
* @var string $hint Placeholder for the field.
* @var string $id DOM id of the field.
* @var string $label Label of the field.
* @var string $labelclass Classes to apply to the label.
* @var boolean $multiple Does this field support multiple values?
* @var string $name Name of the input field.
* @var string $onchange Onchange attribute for the field.
* @var string $onclick Onclick attribute for the field.
* @var string $pattern Pattern (Reg Ex) of value of the form field.
* @var boolean $readonly Is this field read only?
* @var boolean $repeat Allows extensions to duplicate elements.
* @var boolean $required Is this field required?
* @var integer $size Size attribute of the input.
* @var boolean $spellcheck Spellcheck state for the form field.
* @var string $validate Validation rules to apply.
* @var string $value Value attribute of the field.
* @var string $dataAttribute Miscellaneous data attributes preprocessed for HTML output
* @var array $dataAttributes Miscellaneous data attribute for eg, data-*
* @var string $valueTitle
* @var array $canDo
* @var string[] $urls
* @var string[] $modalTitles
* @var string $language
*/
// Do nothing when propagate is disabled
if (empty($canDo['propagate'])) {
return;
}
// Scripts for backward compatibility
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->useScript('field.modal-fields');
$wa->addInlineScript(
'window.jSelectMenu_' . $id . ' = function (id, title, object) {
window.processModalSelect("Item", "' . $id . '", id, title, "", object);
}',
['name' => 'inline.select_menu_' . $id],
['type' => 'module']
);
Text::script('JGLOBAL_ASSOCIATIONS_PROPAGATE_FAILED');
// Language propagate callback name
// Strip off language tag at the end
$tagLength = strlen($language);
$callbackFunctionStem = substr("jSelectMenu_" . $id, 0, -$tagLength);
?>
<button type="button" class="btn btn-primary" <?php echo $value ? '' : 'hidden'; ?>
title="<?php echo $this->escape(Text::_('JGLOBAL_ASSOCIATIONS_PROPAGATE_TIP')); ?>"
data-show-when-value="1"
onclick="Joomla.propagateAssociation('<?php echo $id; ?>', '<?php echo $callbackFunctionStem; ?>')">
<span class="icon-sync" aria-hidden="true"></span> <?php echo Text::_('JGLOBAL_ASSOCIATIONS_PROPAGATE_BUTTON'); ?>
</button>

View File

@ -0,0 +1,68 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
$app = Factory::getApplication();
$form = $displayData->getForm();
$input = $app->getInput();
$component = $input->getCmd('option', 'com_content');
if ($component == 'com_categories') {
$extension = $input->getCmd('extension', 'com_content');
$parts = explode('.', $extension);
$component = $parts[0];
}
$saveHistory = ComponentHelper::getParams($component)->get('save_history', 0);
$fields = $displayData->get('fields') ?: [
['parent', 'parent_id'],
['published', 'state', 'enabled'],
['category', 'catid'],
'featured',
'sticky',
'access',
'language',
'tags',
'note',
'version_note',
];
$hiddenFields = $displayData->get('hidden_fields') ?: [];
if (!$saveHistory) {
$hiddenFields[] = 'version_note';
}
$html = [];
$html[] = '<fieldset><ul class="list-unstyled">';
foreach ($fields as $field) {
$field = is_array($field) ? $field : [$field];
foreach ($field as $f) {
if ($form->getField($f)) {
if (in_array($f, $hiddenFields)) {
$form->setFieldAttribute($f, 'type', 'hidden');
}
$html[] = '<li>' . $form->renderField($f) . '</li>';
break;
}
}
}
$html[] = '</ul></fieldset>';
echo implode('', $html);

View File

@ -0,0 +1,123 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
$data = $displayData;
// Receive overridable options
$data['options'] = !empty($data['options']) ? $data['options'] : [];
$noResultsText = '';
$hideActiveFilters = false;
$showFilterButton = false;
$showSelector = false;
$selectorFieldName = $data['options']['selectorFieldName'] ?? 'client_id';
// If a filter form exists.
if (isset($data['view']->filterForm) && !empty($data['view']->filterForm)) {
// Checks if a selector (e.g. client_id) exists.
if ($selectorField = $data['view']->filterForm->getField($selectorFieldName)) {
$showSelector = $selectorField->getAttribute('filtermode', '') === 'selector' ? true : $showSelector;
// Checks if a selector should be shown in the current layout.
if (isset($data['view']->layout)) {
$showSelector = $selectorField->getAttribute('layout', 'default') != $data['view']->layout ? false : $showSelector;
}
// Unset the selector field from active filters group.
unset($data['view']->activeFilters[$selectorFieldName]);
}
if ($data['view'] instanceof \Joomla\Component\Menus\Administrator\View\Items\HtmlView) :
unset($data['view']->activeFilters['client_id']);
endif;
// Checks if the filters button should exist.
$filters = $data['view']->filterForm->getGroup('filter');
$showFilterButton = isset($filters['filter_search']) && count($filters) === 1 ? false : true;
// Checks if it should show the be hidden.
$hideActiveFilters = empty($data['view']->activeFilters);
// Check if the no results message should appear.
if (isset($data['view']->total) && (int) $data['view']->total === 0) {
$noResults = $data['view']->filterForm->getFieldAttribute('search', 'noresults', '', 'filter');
if (!empty($noResults)) {
$noResultsText = Text::_($noResults);
}
}
}
// Set some basic options.
$customOptions = [
'filtersHidden' => isset($data['options']['filtersHidden']) && $data['options']['filtersHidden'] ? $data['options']['filtersHidden'] : $hideActiveFilters,
'filterButton' => isset($data['options']['filterButton']) && $data['options']['filterButton'] ? $data['options']['filterButton'] : $showFilterButton,
'defaultLimit' => $data['options']['defaultLimit'] ?? Factory::getApplication()->get('list_limit', 20),
'searchFieldSelector' => '#filter_search',
'selectorFieldName' => $selectorFieldName,
'showSelector' => $showSelector,
'orderFieldSelector' => '#list_fullordering',
'showNoResults' => !empty($noResultsText),
'noResultsText' => !empty($noResultsText) ? $noResultsText : '',
'formSelector' => !empty($data['options']['formSelector']) ? $data['options']['formSelector'] : '#adminForm',
];
// Merge custom options in the options array.
$data['options'] = array_merge($customOptions, $data['options']);
// Add class to hide the active filters if needed.
$filtersActiveClass = $hideActiveFilters ? '' : ' js-stools-container-filters-visible';
// Load search tools
HTMLHelper::_('searchtools.form', $data['options']['formSelector'], $data['options']);
?>
<div class="js-stools" role="search">
<?php if ($data['view'] instanceof \Joomla\Component\Menus\Administrator\View\Items\HtmlView) : ?>
<?php // Add the itemtype and language selectors before the form filters. Do not display in modal.?>
<?php $app = Factory::getApplication(); ?>
<?php $clientIdField = $data['view']->filterForm->getField('client_id'); ?>
<?php if ($clientIdField) : ?>
<div class="js-stools-container-selector">
<div class="visually-hidden">
<?php echo $clientIdField->label; ?>
</div>
<div class="js-stools-field-selector js-stools-client_id">
<?php echo $clientIdField->input; ?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
<?php if ($data['options']['showSelector']) : ?>
<div class="js-stools-container-selector">
<?php echo LayoutHelper::render('joomla.searchtools.default.selector', $data); ?>
</div>
<?php endif; ?>
<div class="js-stools-container-bar ms-auto">
<div class="btn-toolbar">
<?php echo $this->sublayout('bar', $data); ?>
<?php echo $this->sublayout('list', $data); ?>
</div>
</div>
<!-- Filters div -->
<div class="js-stools-container-filters clearfix<?php echo $filtersActiveClass; ?>">
<?php if ($data['options']['filterButton']) : ?>
<?php echo $this->sublayout('filters', $data); ?>
<?php endif; ?>
</div>
</div>
<?php if ($data['options']['showNoResults']) : ?>
<?php echo $this->sublayout('noitems', $data); ?>
<?php endif; ?>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="component" method="upgrade">
<name>com_menus</name>
<author>Joomla! Project</author>
<creationDate>2006-04</creationDate>
<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>COM_MENUS_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Component\Menus</namespace>
<files folder="site">
<folder>forms</folder>
<folder>src</folder>
</files>
<media destination="com_menus" folder="media">
<folder>css</folder>
<folder>js</folder>
</media>
<administration>
<files folder="admin">
<filename>access.xml</filename>
<filename>config.xml</filename>
<filename>menus.xml</filename>
<folder>forms</folder>
<folder>helpers</folder>
<folder>layouts</folder>
<folder>presets</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
<languages folder="admin">
<language tag="en-GB">language/en-GB/com_menus.ini</language>
<language tag="en-GB">language/en-GB/com_menus.sys.ini</language>
</languages>
</administration>
<dashboards>
<dashboard title="COM_MENUS_DASHBOARD_TITLE" icon="icon-list">menus</dashboard>
</dashboards>
</extension>

View File

@ -0,0 +1,651 @@
<?xml version="1.0"?>
<menu
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:joomla.org"
xsi:schemaLocation="urn:joomla.org menu.xsd"
>
<menuitem
title="MOD_MENU_CONTROL_PANEL"
type="component"
element="com_cpanel"
link="index.php?option=com_cpanel&amp;view=cpanel"
class="class:home"
/>
<menuitem
title="MOD_MENU_SYSTEM"
type="heading"
icon="wrench"
class="class:wrench"
>
<menuitem
title="MOD_MENU_CONFIGURATION"
type="component"
element="com_config"
link="index.php?option=com_config&amp;view=application"
/>
<menuitem
title="MOD_MENU_GLOBAL_CHECKIN"
type="component"
element="com_checkin"
link="index.php?option=com_checkin&amp;view=checkin"
/>
<menuitem
title="MOD_MENU_CLEAR_CACHE"
type="component"
element="com_cache"
link="index.php?option=com_cache&amp;view=cache"
/>
<menuitem
title="MOD_MENU_SYSTEM_INFORMATION"
type="component"
element="com_admin"
link="index.php?option=com_admin&amp;view=sysinfo"
/>
</menuitem>
<menuitem
title="MOD_MENU_COM_USERS"
type="heading"
icon="users"
class="class:users"
>
<menuitem
title="COM_USERS_MENUS_USER_MANAGER"
quicktask-title="COM_USERS_MENUS_ADD_USER"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=users"
quicktask="index.php?option=com_users&amp;task=user.add"
/>
<menuitem
title="COM_USERS_MENUS_GROUPS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=groups"
/>
<menuitem
title="COM_USERS_MENUS_LEVELS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=levels"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_FIELDS"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;context=com_users.user"
/>
<menuitem
title="MOD_MENU_FIELDS_GROUP"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;view=groups&amp;context=com_users.user"
/>
<menuitem
type="separator"
/>
<menuitem
title="COM_USERS_MENUS_NOTES"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=notes"
/>
<menuitem
title="COM_USERS_MENUS_NOTE_CATEGORIES"
type="component"
element="com_categories"
link="index.php?option=com_categories&amp;view=categories&amp;extension=com_users"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_COM_PRIVACY"
type="heading"
icon="user-secret"
class="class:privacy"
dashboard="privacy"
>
<menuitem
title="MOD_MENU_COM_PRIVACY_REQUESTS"
type="component"
element="com_privacy"
link="index.php?option=com_privacy&amp;view=requests"
/>
<menuitem
title="MOD_MENU_COM_PRIVACY_CAPABILITIES"
type="component"
element="com_privacy"
link="index.php?option=com_privacy&amp;view=capabilities"
/>
<menuitem
title="MOD_MENU_COM_PRIVACY_CONSENTS"
type="component"
element="com_privacy"
link="index.php?option=com_privacy&amp;view=consents"
/>
</menuitem>
<menuitem
title="MOD_MENU_COM_ACTIONLOGS"
type="component"
element="com_actionlogs"
link="index.php?option=com_actionlogs&amp;view=actionlogs"
class="class:userlogs"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_MASS_MAIL_USERS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=mail"
scope="massmail"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_MESSAGING"
type="component"
element="com_messages"
link="index.php?option=com_messages&amp;view=messages"
>
<menuitem
title="MOD_MENU_MESSAGING_NEW"
type="component"
element="com_messages"
link="index.php?option=com_messages&amp;task=message.add"
/>
<menuitem
title="MOD_MENU_MESSAGING_PRIVATE"
type="component"
element="com_messages"
link="index.php?option=com_messages&amp;view=messages"
/>
</menuitem>
</menuitem>
<menuitem
title="MOD_MENU_MENUS"
type="heading"
icon="list"
class="class:list"
>
<menuitem
title="MOD_MENU_MENU_MANAGER"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=menus"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_MENUS_ALL_ITEMS"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype="
/>
<!--
Following is an example of repeatable group based on simple database query.
This requires sql_* attributes (sql_select and sql_from are required)
The values can be used like - "{sql:columnName}" in any attribute of repeated elements.
The repeated elements are place inside this xml node but they will be populated in the same level in the rendered menu
-->
<menuitem
type="separator"
title="JSITE"
hidden="false"
sql_select="a.id, a.title, a.menutype, CASE COALESCE(SUM(m.home), 0) WHEN 0 THEN '' WHEN 1 THEN CASE m.language WHEN '*' THEN 'class:icon-home' ELSE CONCAT('image:', l.lang_code) END ELSE 'image:mod_languages/icon-16-language.png' END AS icon"
sql_from="#__menu_types AS a"
sql_where="a.client_id = 0"
sql_leftjoin="#__menu AS m ON m.menutype = a.menutype AND m.home = 1 LEFT JOIN #__languages AS l ON l.lang_code = m.language"
sql_group="a.id, a.title, a.menutype, m.language, l.lang_code"
sql_order="a.id DESC"
>
<menuitem
title="{sql:title} "
quicktask-title="MOD_MENU_MENU_MANAGER_NEW_SITE_MENU_ITEM"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype={sql:menutype}"
icon="{sql:icon}"
class="class:menu"
quicktask="index.php?option=com_menus&amp;task=item.add&amp;menutype={sql:menutype}"
/>
</menuitem>
<menuitem
type="separator"
title="JADMINISTRATOR"
hidden="false"
sql_select="title, menutype"
sql_from="#__menu_types"
sql_where="client_id = 1"
sql_order="id DESC"
>
<menuitem
title="{sql:title}"
quicktask-title="MOD_MENU_MENU_MANAGER_NEW_ADMIN_MENU_ITEM"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype={sql:menutype}"
icon="{sql:icon}"
class="class:menu"
quicktask="index.php?option=com_menus&amp;task=item.add&amp;client_id=1&amp;menutype={sql:menutype}"
/>
</menuitem>
</menuitem>
<menuitem
title="MOD_MENU_COM_CONTENT"
type="heading"
icon="file-alt"
class="class:file-alt"
>
<menuitem
title="COM_CONTENT_MENUS_ARTICLE_MANAGER"
quicktask-title="COM_CONTENT_MENUS_NEW_ARTICLE"
type="component"
element="com_content"
link="index.php?option=com_content&amp;view=articles"
quicktask="index.php?option=com_content&amp;task=article.add"
/>
<menuitem
title="COM_CONTENT_MENUS_CATEGORY_MANAGER"
quicktask-title="COM_CONTENT_MENUS_NEW_CATEGORY"
type="component"
element="com_categories"
link="index.php?option=com_categories&amp;view=categories&amp;extension=com_content"
quicktask="index.php?option=com_categories&amp;extension=com_content&amp;task=category.add"
/>
<menuitem
title="COM_CONTENT_MENUS_FEATURED"
type="component"
element="com_content"
link="index.php?option=com_content&amp;view=featured"
/>
<menuitem
type="separator"
/>
<menuitem
title="COM_CONTENT_MENUS_WORKFLOW"
type="component"
element="com_workflow"
link="index.php?option=com_workflow&amp;view=workflows&amp;extension=com_content.article"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_FIELDS"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;context=com_content.article"
/>
<menuitem
title="MOD_MENU_FIELDS_GROUP"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;view=groups&amp;context=com_content.article"
/>
</menuitem>
<menuitem
title="MOD_MENU_MEDIA_MANAGER"
type="component"
element="com_media"
link="index.php?option=com_media&amp;view=media"
class="class:image"
/>
<menuitem
title="MOD_MENU_COMPONENTS"
type="container"
class="class:puzzle-piece"
>
<menuitem
title="COM_JOOMLAUPDATE"
type="component"
element="com_joomlaupdate"
link="index.php?option=com_joomlaupdate&amp;view=joomlaupdate"
class="class:component"
permission="core.manage;com_joomlaupdate"
/>
<menuitem
title="MOD_MENU_MANAGE_GUIDEDTOURS"
type="component"
element="com_guidedtours"
link="index.php?option=com_guidedtours&amp;view=tours"
permission="core.manage;com_guidedtours"
/>
<menuitem
title="COM_POSTINSTALL"
type="component"
element="com_postinstall"
link="index.php?option=com_postinstall&amp;view=messages"
class="class:component"
/>
<menuitem
title="MOD_MENU_MANAGE_REDIRECTS"
type="component"
element="com_redirect"
link="index.php?option=com_redirect&amp;view=links"
permission="core.manage;com_redirect"
/>
<menuitem
title="MOD_MENU_MANAGE_SCHEDULED_TASKS"
type="component"
element="com_scheduler"
link="index.php?option=com_scheduler&amp;view=tasks"
permission="core.manage;com_scheduler"
/>
</menuitem>
<menuitem
title="MOD_MENU_EXTENSIONS_EXTENSIONS"
type="heading"
icon="cubes"
class="class:cubes"
>
<menuitem
title="MOD_MENU_EXTENSIONS_EXTENSION_MANAGER"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=manage">
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_INSTALL"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=install"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_UPDATE"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=update"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_MANAGE"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=manage"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_DISCOVER"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=discover"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_DATABASE"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=database"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_WARNINGS"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=warnings"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_LANGUAGES"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=languages"
/>
<menuitem
title="MOD_MENU_INSTALLER_SUBMENU_UPDATESITES"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=updatesites"
/>
</menuitem>
<menuitem
title="MOD_MENU_EXTENSIONS_MODULE_MANAGER_SITE"
quicktask-title="COM_CONTENT_MENUS_NEW_SITE_MODULE"
type="component"
element="com_modules"
link="index.php?option=com_modules&amp;view=modules&amp;client_id=0"
quicktask="index.php?option=com_modules&amp;view=select&amp;client_id=0"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_MODULE_MANAGER_ADMINISTRATOR"
quicktask-title="COM_CONTENT_MENUS_NEW_ADMIN_MODULE"
type="component"
element="com_modules"
link="index.php?option=com_modules&amp;view=modules&amp;client_id=1"
quicktask="index.php?option=com_modules&amp;view=select&amp;client_id=1"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_PLUGIN_MANAGER"
type="component"
element="com_plugins"
link="index.php?option=com_plugins&amp;view=plugins"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_TEMPLATE_MANAGER"
type="component"
element="com_templates"
link="index.php?option=com_templates">
<menuitem
title="MOD_MENU_COM_TEMPLATES_SUBMENU_STYLES"
type="component"
element="com_templates"
link="index.php?option=com_templates&amp;view=styles&amp;client_id=0"
/>
<menuitem
title="MOD_MENU_COM_TEMPLATES_SUBMENU_TEMPLATES"
type="component"
element="com_templates"
link="index.php?option=com_templates&amp;view=templates"
/>
<menuitem
title="MOD_MENU_COM_MAILS_TEMPLATES"
type="component"
element="com_mails"
link="index.php?option=com_mails&amp;view=templates"
/>
</menuitem>
<menuitem
title="MOD_MENU_EXTENSIONS_LANGUAGE_MANAGER"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=installed">
<menuitem
title="MOD_MENU_COM_LANGUAGES_SUBMENU_INSTALLED"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=installed"
/>
<menuitem
title="MOD_MENU_COM_LANGUAGES_SUBMENU_CONTENT"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=languages"
/>
<menuitem
title="MOD_MENU_COM_LANGUAGES_SUBMENU_OVERRIDES"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=overrides"
/>
</menuitem>
</menuitem>
<menuitem
title="MOD_MENU_HELP"
type="heading"
icon="info-circle"
class="class:info-circle"
>
<menuitem
type="component"
title="MOD_MENU_HELP_JOOMLA"
element="com_admin"
link="index.php?option=com_admin&amp;view=help"
scope="help"
/>
<menuitem
type="separator"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_SUPPORT_OFFICIAL_FORUM"
link="https://forum.joomla.org"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_SUPPORT_CUSTOM_FORUM"
link="special:custom-forum"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_SUPPORT_OFFICIAL_LANGUAGE_FORUM"
link="special:language-forum"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_DOCUMENTATION"
link="https://docs.joomla.org"
scope="help"
/>
<menuitem
type="separator"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_EXTENSIONS"
link="https://extensions.joomla.org"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_TRANSLATIONS"
link="https://downloads.joomla.org/language-packs"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_RESOURCES"
link="https://community.joomla.org/service-providers-directory/"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_COMMUNITY"
link="https://community.joomla.org"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_SECURITY"
link="https://developer.joomla.org/security-centre.html"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_DEVELOPER"
link="https://developer.joomla.org"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_XCHANGE"
link="https://joomla.stackexchange.com"
scope="help"
/>
<menuitem
type="url"
target="_blank"
title="MOD_MENU_HELP_SHOP"
link="https://community.joomla.org/the-joomla-shop.html"
scope="help"
/>
</menuitem>
</menu>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<menu
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:joomla.org"
xsi:schemaLocation="urn:joomla.org menu.xsd"
>
<menuitem
title="MOD_MENU_COMPONENTS"
type="container"
class="class:puzzle-piece"
dashboard="components"
/>
</menu>

View File

@ -0,0 +1,338 @@
<?xml version="1.0"?>
<menu
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:joomla.org"
xsi:schemaLocation="urn:joomla.org menu.xsd"
>
<menuitem
type="component"
title="MOD_MENU_CONTROL_PANEL"
link="index.php"
class="class:home"
element="com_cpanel"
/>
<menuitem
title="COM_CONTENT_MENUS"
type="heading"
icon="file-alt"
class="class:file-alt"
dashboard="content"
>
<menuitem
title="COM_CONTENT_MENUS_ARTICLE_MANAGER"
quicktask-title="COM_CONTENT_MENUS_NEW_ARTICLE"
type="component"
element="com_content"
link="index.php?option=com_content&amp;view=articles"
quicktask="index.php?option=com_content&amp;task=article.add"
/>
<menuitem
title="COM_CONTENT_MENUS_CATEGORY_MANAGER"
quicktask-title="COM_CONTENT_MENUS_NEW_CATEGORY"
type="component"
element="com_categories"
link="index.php?option=com_categories&amp;view=categories&amp;extension=com_content"
quicktask="index.php?option=com_categories&amp;extension=com_content&amp;task=category.add"
/>
<menuitem
title="COM_CONTENT_MENUS_FEATURED"
type="component"
element="com_content"
link="index.php?option=com_content&amp;view=featured"
class="class:featured"
/>
<menuitem
title="COM_CONTENT_MENUS_WORKFLOW"
type="component"
element="com_workflow"
link="index.php?option=com_workflow&amp;view=workflows&amp;extension=com_content.article"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_FIELDS"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;view=fields&amp;context=com_content.article"
/>
<menuitem
title="MOD_MENU_FIELDS_GROUP"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;view=groups&amp;context=com_content.article"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_MEDIA_MANAGER"
type="component"
element="com_media"
link="index.php?option=com_media"
class="class:image"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_MODULE_MANAGER_SITE"
quicktask-title="COM_CONTENT_MENUS_NEW_SITE_MODULE"
type="component"
element="com_modules"
link="index.php?option=com_modules&amp;view=modules&amp;client_id=0"
quicktask="index.php?option=com_modules&amp;view=select&amp;client_id=0"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_MODULE_MANAGER_ADMINISTRATOR"
quicktask-title="COM_CONTENT_MENUS_NEW_ADMIN_MODULE"
type="component"
element="com_modules"
link="index.php?option=com_modules&amp;view=modules&amp;client_id=1"
quicktask="index.php?option=com_modules&amp;view=select&amp;client_id=1"
/>
</menuitem>
<menuitem
title="MOD_MENU_MENUS"
type="heading"
icon="list"
class="class:list"
dashboard="menus"
>
<menuitem
title="MOD_MENU_MENU_MANAGER"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=menus"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_MENUS_ALL_ITEMS"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype="
/>
<!--
Following is an example of repeatable group based on simple database query.
This requires sql_* attributes (sql_select and sql_from are required)
The values can be used like - "{sql:columnName}" in any attribute of repeated elements.
The repeated elements are placed inside this xml node but they will be populated in the same level in the rendered menu
-->
<menuitem
type="separator"
title="JSITE"
hidden="false"
sql_select="a.id, a.title, a.menutype, CASE COALESCE(SUM(m.home), 0) WHEN 0 THEN '' WHEN 1 THEN CASE m.language WHEN '*' THEN 'class:icon-home' ELSE CONCAT('image:', l.lang_code) END ELSE 'image:mod_languages/icon-16-language.png' END AS icon"
sql_from="#__menu_types AS a"
sql_where="a.client_id = 0"
sql_leftjoin="#__menu AS m ON m.menutype = a.menutype AND m.home = 1 LEFT JOIN #__languages AS l ON l.lang_code = m.language"
sql_group="a.id, a.title, a.menutype, m.language, l.lang_code"
sql_order="a.ordering ASC"
>
<menuitem
title="{sql:title}"
quicktask-title="MOD_MENU_MENU_MANAGER_NEW_SITE_MENU_ITEM"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype={sql:menutype}"
icon="{sql:icon}"
class="class:menu"
quicktask="index.php?option=com_menus&amp;task=item.add&amp;menutype={sql:menutype}"
/>
</menuitem>
<menuitem
type="separator"
title="JADMINISTRATOR"
hidden="false"
sql_select="title, menutype"
sql_from="#__menu_types"
sql_where="client_id = 1"
sql_order="ordering ASC"
>
<menuitem
title="{sql:title}"
quicktask-title="MOD_MENU_MENU_MANAGER_NEW_ADMIN_MENU_ITEM"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype={sql:menutype}"
icon="{sql:icon}"
class="class:menu"
quicktask="index.php?option=com_menus&amp;task=item.add&amp;client_id=1&amp;menutype={sql:menutype}"
/>
</menuitem>
</menuitem>
<menuitem
title="MOD_MENU_COMPONENTS"
type="container"
class="class:puzzle-piece"
dashboard="components"
/>
<menuitem
title="COM_USERS_MENUS_USERS"
type="heading"
icon="users"
class="class:users"
alias="users"
dashboard="users"
>
<menuitem
title="COM_USERS_MENUS_USER_MANAGER"
quicktask-title="COM_USERS_MENUS_ADD_USER"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=users"
quicktask="index.php?option=com_users&amp;task=user.add"
/>
<menuitem
title="COM_USERS_MENUS_GROUPS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=groups"
/>
<menuitem
title="COM_USERS_MENUS_LEVELS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=levels"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_FIELDS"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;view=fields&amp;context=com_users.user"
/>
<menuitem
title="MOD_MENU_FIELDS_GROUP"
type="component"
element="com_fields"
link="index.php?option=com_fields&amp;view=groups&amp;context=com_users.user"
/>
<menuitem
type="separator"
/>
<menuitem
title="COM_USERS_MENUS_NOTES"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=notes"
/>
<menuitem
title="COM_USERS_MENUS_NOTE_CATEGORIES"
type="component"
element="com_categories"
link="index.php?option=com_categories&amp;view=categories&amp;extension=com_users"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_COM_PRIVACY"
type="heading"
icon="user-secret"
class="class:privacy"
dashboard="privacy"
>
<menuitem
title="MOD_MENU_COM_PRIVACY_REQUESTS"
type="component"
element="com_privacy"
link="index.php?option=com_privacy&amp;view=requests"
/>
<menuitem
title="MOD_MENU_COM_PRIVACY_CAPABILITIES"
type="component"
element="com_privacy"
link="index.php?option=com_privacy&amp;view=capabilities"
/>
<menuitem
title="MOD_MENU_COM_PRIVACY_CONSENTS"
type="component"
element="com_privacy"
link="index.php?option=com_privacy&amp;view=consents"
/>
</menuitem>
<menuitem
title="MOD_MENU_COM_ACTIONLOGS"
type="component"
element="com_actionlogs"
link="index.php?option=com_actionlogs&amp;view=actionlogs"
class="class:userlogs"
/>
<menuitem
type="separator"
/>
<menuitem
title="MOD_MENU_MASS_MAIL_USERS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=mail"
scope="massmail"
/>
<menuitem
title="MOD_MENU_MESSAGING"
type="component"
element="com_messages"
link="index.php?option=com_messages"
>
<menuitem
title="MOD_MENU_MESSAGING_PRIVATE"
type="component"
element="com_messages"
link="index.php?option=com_messages&amp;view=messages"
quicktask="index.php?option=com_messages&amp;task=message.add"
/>
</menuitem>
</menuitem>
<menuitem
title="MOD_MENU_SYSTEM"
type="component"
element="com_cpanel"
class="class:wrench"
link="index.php?option=com_cpanel&amp;view=cpanel&amp;dashboard=system"
/>
<menuitem
title="MOD_MENU_HELP"
type="component"
element="com_cpanel"
class="class:info-circle"
link="index.php?option=com_cpanel&amp;view=cpanel&amp;dashboard=help"
/>
</menu>

View File

@ -0,0 +1,172 @@
<?xml version="1.0"?>
<menu
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:joomla.org"
xsi:schemaLocation="urn:joomla.org menu.xsd"
>
<menuitem
title="MOD_MENU_HELP_PARENT_START_HERE"
type="heading"
icon="compass"
permission="core.admin"
>
<menuitem
title="MOD_MENU_HELP_JOOMLA"
type="component"
element="com_admin"
link="index.php?option=com_admin&amp;view=help"
/>
</menuitem>
<menuitem
title="MOD_MENU_HELP_PARENT_FIND_HELP"
type="heading"
icon="question-circle"
permission="core.admin"
>
<menuitem
title="MOD_MENU_HELP_DOCUMENTATION"
type="url"
target="_blank"
link="https://docs.joomla.org"
/>
<menuitem
title="MOD_MENU_HELP_SUPPORT_OFFICIAL_FORUM"
type="url"
target="_blank"
link="https://forum.joomla.org"
/>
<menuitem
title="MOD_MENU_HELP_SUPPORT_OFFICIAL_LANGUAGE_FORUM"
type="component"
element="com_admin"
target="_blank"
link="index.php?option=com_admin&amp;view=help&amp;layout=langforum"
/>
<menuitem
title="MOD_MENU_HELP_XCHANGE"
type="url"
target="_blank"
link="https://joomla.stackexchange.com"
/>
</menuitem>
<menuitem
title="MOD_MENU_HELP_PARENT_MEET_JOOMLERS"
type="heading"
icon="users"
>
<menuitem
title="MOD_MENU_HELP_RESOURCES"
type="url"
target="_blank"
link="https://community.joomla.org/service-providers-directory/"
/>
<menuitem
title="MOD_MENU_HELP_EVENTS"
type="url"
target="_blank"
link="https://community.joomla.org/events.html"
/>
<menuitem
title="MOD_MENU_HELP_USER_GROUPS"
type="url"
target="_blank"
link="https://community.joomla.org/user-groups.html"
/>
</menuitem>
<menuitem
title="MOD_MENU_HELP_PARENT_NEWS"
type="heading"
icon="bullhorn"
>
<menuitem
title="MOD_MENU_HELP_COMMUNITY_NEWS"
type="url"
target="_blank"
link="https://www.joomla.org/announcements.html"
/>
<menuitem
title="MOD_MENU_HELP_COMMUNITY_NEWSLETTER"
type="url"
target="_blank"
link="https://community.joomla.org/general-newsletter.html"
/>
<menuitem
title="MOD_MENU_HELP_SECURITY"
type="url"
target="_blank"
link="https://developer.joomla.org/security-centre.html"
/>
</menuitem>
<menuitem
title="MOD_MENU_HELP_PARENT_RESOURCES"
type="heading"
icon="cloud-download-alt"
permission="core.manage;com_installer"
>
<menuitem
title="MOD_MENU_HELP_DEVELOPER"
type="url"
target="_blank"
link="https://developer.joomla.org"
/>
<menuitem
title="MOD_MENU_HELP_TRANSLATIONS"
type="url"
target="_blank"
link="https://downloads.joomla.org/language-packs"
/>
<menuitem
title="MOD_MENU_HELP_EXTENSIONS"
type="url"
target="_blank"
link="https://extensions.joomla.org"
/>
<menuitem
title="MOD_MENU_HELP_SHOP"
type="url"
target="_blank"
link="https://community.joomla.org/the-joomla-shop.html"
/>
</menuitem>
<menuitem
title="MOD_MENU_HELP_PARENT_GET_INVOLVED"
type="heading"
icon="handshake"
>
<menuitem
title="MOD_MENU_HELP_COMMUNITY"
type="url"
target="_blank"
link="https://community.joomla.org"
/>
<menuitem
title="MOD_MENU_HELP_ISSUES_TRACKER"
type="url"
target="_blank"
link="https://issues.joomla.org/"
/>
<menuitem
title="MOD_MENU_HELP_GITHUB"
type="url"
target="_blank"
link="https://github.com/joomla/joomla-cms/"
/>
</menuitem>
</menu>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:joomla.org"
xmlns="urn:joomla.org">
<xs:element name="menu" type="menuType"/>
<xs:simpleType name="typeType">
<xs:restriction base="xs:string">
<xs:enumeration value="component" />
<xs:enumeration value="container" />
<xs:enumeration value="heading" />
<xs:enumeration value="separator" />
<xs:enumeration value="url" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="elementType">
<xs:restriction base="xs:string">
<xs:pattern value="com_(.+)" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="scopeType">
<xs:restriction base="xs:string">
<xs:enumeration value="default" />
<xs:enumeration value="edit" />
<xs:enumeration value="help" />
<xs:enumeration value="massmail" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="trueFalse">
<xs:restriction base="xs:string">
<xs:enumeration value="true" />
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="browserNavType">
<xs:restriction base="xs:string">
<xs:enumeration value="_blank" />
<xs:enumeration value=""/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="menuType">
<xs:sequence>
<xs:element type="menuitemType" name="menuitem" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="menuitemType" mixed="true">
<xs:sequence>
<xs:element type="xs:string" name="params" minOccurs="0" maxOccurs="1"/>
<xs:element type="menuitemType" name="menuitem" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute type="typeType" name="type" use="required"/>
<xs:attribute type="xs:string" name="title" use="optional"/>
<xs:attribute type="xs:string" name="link" use="optional"/>
<xs:attribute type="xs:string" name="class" use="optional"/>
<xs:attribute type="xs:string" name="icon" use="optional"/>
<xs:attribute type="elementType" name="element" use="optional"/>
<xs:attribute type="trueFalse" name="hidden" use="optional" default="false"/>
<xs:attribute type="xs:string" name="sql_select" use="optional"/>
<xs:attribute type="xs:string" name="sql_from" use="optional"/>
<xs:attribute type="xs:string" name="sql_where" use="optional"/>
<xs:attribute type="xs:string" name="sql_leftjoin" use="optional"/>
<xs:attribute type="xs:string" name="sql_innerjoin" use="optional"/>
<xs:attribute type="xs:string" name="sql_group" use="optional"/>
<xs:attribute type="xs:string" name="sql_order" use="optional"/>
<xs:attribute type="xs:string" name="sql_target" use="optional"/>
<xs:attribute type="browserNavType" name="target" use="optional" default=""/>
<xs:attribute type="scopeType" name="scope" use="optional" default="default"/>
<xs:attribute type="xs:string" name="permission" use="optional"/>
<xs:attribute type="xs:string" name="quicktask" use="optional"/>
<xs:attribute type="xs:string" name="quicktask-title" use="optional"/>
<xs:attribute type="xs:string" name="quicktask-icon" use="optional"/>
<xs:attribute type="xs:string" name="quicktask-permission" use="optional"/>
<xs:attribute type="xs:string" name="ajax-badge" use="optional"/>
<xs:attribute type="xs:string" name="dashboard" use="optional"/>
</xs:complexType>
</xs:schema>

View File

@ -0,0 +1,80 @@
<?xml version="1.0"?>
<menu
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:joomla.org"
xsi:schemaLocation="urn:joomla.org menu.xsd"
>
<menuitem
title="MOD_MENU_MENUS"
type="heading"
icon="list"
class="class:list"
>
<menuitem
title="MOD_MENU_MENU_MANAGER"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=menus"
/>
<menuitem
title="MOD_MENU_MENUS_ALL_ITEMS"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype="
/>
</menuitem>
<!--
Following is an example of repeatable group based on simple database query.
This requires sql_* attributes (sql_select and sql_from are required)
The values can be used like - "{sql:columnName}" in any attribute of repeated elements.
The repeated elements are place inside this xml node but they will be populated in the same level in the rendered menu
-->
<menuitem
type="separator"
title="JSITE"
icon="desktop"
hidden="false"
sql_select="a.id, a.title, a.menutype, CASE COALESCE(SUM(m.home), 0) WHEN 0 THEN '' WHEN 1 THEN CASE m.language WHEN '*' THEN 'class:icon-home' ELSE CONCAT('image:', l.lang_code) END ELSE 'image:mod_languages/icon-16-language.png' END AS icon"
sql_from="#__menu_types AS a"
sql_where="a.client_id = 0"
sql_leftjoin="#__menu AS m ON m.menutype = a.menutype AND m.home = 1 LEFT JOIN #__languages AS l ON l.lang_code = m.language"
sql_group="a.id, a.title, a.menutype, m.language, l.lang_code"
sql_order="a.ordering ASC"
sql_target="self"
>
<menuitem
title="{sql:title} "
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype={sql:menutype}"
icon="{sql:icon}"
class="class:menu"
quicktask="index.php?option=com_menus&amp;task=item.add&amp;menutype={sql:menutype}"
quicktask-title="MOD_MENU_MENU_MANAGER_NEW_SITE_MENU_ITEM"
/>
</menuitem>
<menuitem
type="separator"
title="JADMINISTRATOR"
icon="desktop"
hidden="false"
sql_select="title, menutype"
sql_from="#__menu_types"
sql_where="client_id = 1"
sql_order="ordering ASC"
sql_target="self"
>
<menuitem
title="{sql:title}"
type="component"
element="com_menus"
link="index.php?option=com_menus&amp;view=items&amp;menutype={sql:menutype}"
class="class:menu"
quicktask="index.php?option=com_menus&amp;task=item.add&amp;client_id=1&amp;menutype={sql:menutype}"
quicktask-title="MOD_MENU_MENU_MANAGER_NEW_ADMIN_MENU_ITEM"
/>
</menuitem>
</menu>

View File

@ -0,0 +1,311 @@
<?xml version="1.0"?>
<menu
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:joomla.org"
xsi:schemaLocation="urn:joomla.org menu.xsd"
>
<menuitem
title="MOD_MENU_SYSTEM_PARENT_SETUP"
type="heading"
icon="cog"
permission="core.admin"
>
<menuitem
title="MOD_MENU_CONFIGURATION"
type="component"
element="com_config"
link="index.php?option=com_config"
/>
</menuitem>
<menuitem
title="MOD_MENU_MAINTAIN"
type="heading"
icon="tools"
>
<menuitem
title="MOD_MENU_CLEAR_CACHE"
type="component"
element="com_cache"
link="index.php?option=com_cache"
permission="core.manage;com_cache"
/>
<menuitem
title="MOD_MENU_SYSTEM_INFORMATION_DATABASE"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=database"
permission="core.manage;com_installer"
ajax-badge="index.php?option=com_installer&amp;task=database.getMenuBadgeData&amp;format=json"
/>
<menuitem
title="MOD_MENU_GLOBAL_CHECKIN"
type="component"
element="com_checkin"
link="index.php?option=com_checkin"
permission="core.manage;com_checkin"
ajax-badge="index.php?option=com_checkin&amp;task=getMenuBadgeData&amp;format=json"
/>
</menuitem>
<menuitem
title="MOD_MENU_INFORMATION"
type="heading"
icon="info-circle"
>
<menuitem
title="MOD_MENU_INFORMATION_WARNINGS"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=warnings"
permission="core.manage;com_installer"
ajax-badge="index.php?option=com_installer&amp;task=getMenuBadgeData&amp;format=json"
/>
<menuitem
title="MOD_MENU_INFORMATION_POST_INSTALL_MESSAGES"
type="component"
element="com_postinstall"
link="index.php?option=com_postinstall"
permission="core.manage;com_postinstall"
ajax-badge="index.php?option=com_postinstall&amp;task=getMenuBadgeData&amp;format=json"
/>
<menuitem
title="MOD_MENU_SYSTEM_INFORMATION_SYSINFO"
type="component"
element="com_admin"
link="index.php?option=com_admin&amp;view=sysinfo"
permission="core.admin"
/>
</menuitem>
<menuitem
title="MOD_MENU_INSTALL"
type="heading"
icon="upload"
permission="core.manage;com_installer"
>
<menuitem
title="MOD_MENU_INSTALL_EXTENSIONS"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=install"
/>
<menuitem
title="MOD_MENU_INSTALL_DISCOVER"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=discover"
ajax-badge="index.php?option=com_installer&amp;task=discover.getMenuBadgeData&amp;format=json"
/>
<menuitem
title="MOD_MENU_INSTALL_LANGUAGES"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=languages"
/>
</menuitem>
<menuitem
title="MOD_MENU_MANAGE"
type="heading"
icon="tasks"
>
<menuitem
title="MOD_MENU_MANAGE_EXTENSIONS"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=manage"
permission="core.manage;com_installer"
/>
<menuitem
title="MOD_MENU_MANAGE_LANGUAGES"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=installed"
permission="core.manage;com_languages"
/>
<menuitem
title="MOD_MENU_MANAGE_LANGUAGES_CONTENT"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=languages"
permission="core.manage;com_languages"
/>
<menuitem
title="MOD_MENU_MANAGE_LANGUAGES_OVERRIDES"
type="component"
element="com_languages"
link="index.php?option=com_languages&amp;view=overrides"
permission="core.manage;com_languages"
/>
<menuitem
title="MOD_MENU_MANAGE_PLUGINS"
type="component"
element="com_plugins"
link="index.php?option=com_plugins"
permission="core.manage;com_plugins"
/>
<menuitem
title="MOD_MENU_MANAGE_REDIRECTS"
type="component"
element="com_redirect"
link="index.php?option=com_redirect"
permission="core.manage;com_redirect"
/>
<menuitem
title="MOD_MENU_MANAGE_GUIDEDTOURS"
type="component"
element="com_guidedtours"
link="index.php?option=com_guidedtours&amp;view=tours"
permission="core.manage;com_guidedtours"
/>
<menuitem
title="MOD_MENU_MANAGE_SCHEDULED_TASKS"
type="component"
element="com_scheduler"
link="index.php?option=com_scheduler&amp;view=tasks"
permission="core.manage;com_scheduler"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_MODULE_MANAGER_SITE"
type="component"
element="com_modules"
link="index.php?option=com_modules&amp;view=modules&amp;client_id=0"
permission="core.manage;com_modules"
/>
<menuitem
title="MOD_MENU_EXTENSIONS_MODULE_MANAGER_ADMINISTRATOR"
type="component"
element="com_modules"
link="index.php?option=com_modules&amp;view=modules&amp;client_id=1"
permission="core.manage;com_modules"
/>
</menuitem>
<menuitem
title="MOD_MENU_UPDATE"
type="heading"
icon="sync"
>
<menuitem
title="MOD_MENU_UPDATE_JOOMLA"
type="component"
element="com_joomlaupdate"
link="index.php?option=com_joomlaupdate"
permission="core.manage;com_joomlaupdate"
ajax-badge="index.php?option=com_joomlaupdate&amp;task=getMenuBadgeData&amp;format=json"
/>
<menuitem
title="MOD_MENU_UPDATE_EXTENSIONS"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=update"
permission="core.manage;com_installer"
ajax-badge="index.php?option=com_installer&amp;task=update.getMenuBadgeData&amp;format=json"
/>
<menuitem
title="MOD_MENU_UPDATE_SOURCES"
type="component"
element="com_installer"
link="index.php?option=com_installer&amp;view=updatesites"
permission="core.manage;com_installer"
/>
</menuitem>
<menuitem
title="MOD_MENU_TEMPLATES"
type="heading"
icon="paint-brush"
permission="core.manage;com_templates"
>
<menuitem
title="MOD_MENU_TEMPLATE_SITE_TEMPLATES"
type="component"
element="com_templates"
link="index.php?option=com_templates&amp;view=templates&amp;client_id=0"
/>
<menuitem
title="MOD_MENU_TEMPLATE_SITE_STYLES"
type="component"
element="com_templates"
link="index.php?option=com_templates&amp;view=styles&amp;client_id=0"
/>
<menuitem
title="MOD_MENU_TEMPLATE_ADMIN_TEMPLATES"
type="component"
element="com_templates"
link="index.php?option=com_templates&amp;view=templates&amp;client_id=1"
/>
<menuitem
title="MOD_MENU_TEMPLATE_ADMIN_STYLES"
type="component"
element="com_templates"
link="index.php?option=com_templates&amp;view=styles&amp;client_id=1"
/>
<menuitem
title="MOD_MENU_CONFIGURATION_MAILS"
type="component"
element="com_mails"
link="index.php?option=com_mails&amp;view=templates"
/>
</menuitem>
<menuitem
title="MOD_MENU_ACCESS"
type="heading"
icon="key"
>
<menuitem
title="MOD_MENU_ACCESS_GROUPS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=groups"
permission="core.manage;com_users"
/>
<menuitem
title="MOD_MENU_ACCESS_LEVELS"
type="component"
element="com_users"
link="index.php?option=com_users&amp;view=levels"
permission="core.manage;com_users"
/>
<menuitem
title="MOD_MENU_ACCESS_SETTINGS"
type="component"
element="com_config"
link="index.php?option=com_config#page-permissions"
permission="core.manage"
/>
<menuitem
title="MOD_MENU_ACCESS_TEXT_FILTERS"
type="component"
element="com_config"
link="index.php?option=com_config#page-filters"
permission="core.manage"
/>
</menuitem>
</menu>

View File

@ -0,0 +1,60 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Association\AssociationExtensionInterface;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
use Joomla\CMS\HTML\Registry;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Component\Menus\Administrator\Extension\MenusComponent;
use Joomla\Component\Menus\Administrator\Helper\AssociationsHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
/**
* The menus service provider.
*
* @since 4.0.0
*/
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.0.0
*/
public function register(Container $container)
{
$container->set(AssociationExtensionInterface::class, new AssociationsHelper());
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Menus'));
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Menus'));
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new MenusComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setRegistry($container->get(Registry::class));
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
$component->setAssociationExtension($container->get(AssociationExtensionInterface::class));
return $component;
}
);
}
};

View File

@ -0,0 +1,86 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Controller;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Table\Table;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The menu controller for ajax requests
*
* @since 3.9.0
*/
class AjaxController extends BaseController
{
/**
* Method to fetch associations of a menu item
*
* The method assumes that the following http parameters are passed in an Ajax Get request:
* token: the form token
* assocId: the id of the menu item whose associations are to be returned
* excludeLang: the association for this language is to be excluded
*
* @return null
*
* @since 3.9.0
*/
public function fetchAssociations()
{
if (!Session::checkToken('get')) {
echo new JsonResponse(null, Text::_('JINVALID_TOKEN'), true);
} else {
$assocId = $this->input->getInt('assocId', 0);
if ($assocId == 0) {
echo new JsonResponse(null, Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', 'assocId'), true);
return;
}
$excludeLang = $this->input->get('excludeLang', '', 'STRING');
$associations = Associations::getAssociations('com_menus', '#__menu', 'com_menus.item', (int) $assocId, 'id', '', '');
unset($associations[$excludeLang]);
// Add the title to each of the associated records
Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_menus/tables');
$menuTable = Table::getInstance('Menu', '\\Joomla\\CMS\\Table\\', []);
foreach ($associations as $lang => $association) {
$menuTable->load($association->id);
$associations[$lang]->title = $menuTable->title;
}
$countContentLanguages = \count(LanguageHelper::getContentLanguages([0, 1], false));
if (\count($associations) == 0) {
$message = Text::_('JGLOBAL_ASSOCIATIONS_PROPAGATE_MESSAGE_NONE');
} elseif ($countContentLanguages > \count($associations) + 2) {
$tags = implode(', ', array_keys($associations));
$message = Text::sprintf('JGLOBAL_ASSOCIATIONS_PROPAGATE_MESSAGE_SOME', $tags);
} else {
$message = Text::_('JGLOBAL_ASSOCIATIONS_PROPAGATE_MESSAGE_ALL');
}
echo new JsonResponse($associations, $message);
}
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Base controller class for Menu Manager.
*
* @since 1.6
*/
class DisplayController extends BaseController
{
/**
* The default view for the display method.
*
* @var string
* @since 4.0.0
*/
protected $default_view = 'menus';
/**
* Method to display a view.
*
* @param boolean $cachable If true, the view output will be cached
* @param array|boolean $urlparams An array of safe URL parameters and their variable types.
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
*
* @return static This object to support chaining.
*
* @since 1.5
*/
public function display($cachable = false, $urlparams = false)
{
// Verify menu
$menuType = $this->input->post->getCmd('menutype', '');
if ($menuType !== '') {
$uri = Uri::getInstance();
if ($uri->getVar('menutype') !== $menuType) {
$uri->setVar('menutype', $menuType);
if ($forcedLanguage = $this->input->post->get('forcedLanguage')) {
$uri->setVar('forcedLanguage', $forcedLanguage);
}
$this->setRedirect(Route::_('index.php' . $uri->toString(['query']), false));
return parent::display();
}
}
// Check if we have a mod_menu module set to All languages or a mod_menu module for each admin language.
if ($langMissing = $this->getModel('Menus', 'Administrator')->getMissingModuleLanguages()) {
$this->app->enqueueMessage(Text::sprintf('JMENU_MULTILANG_WARNING_MISSING_MODULES', implode(', ', $langMissing)), 'warning');
}
return parent::display();
}
}

View File

@ -0,0 +1,590 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Controller;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The Menu ItemModel Controller
*
* @since 1.6
*/
class ItemController extends FormController
{
/**
* Method to check if you can add a new record.
*
* Extended classes can override this if necessary.
*
* @param array $data An array of input data.
*
* @return boolean
*
* @since 3.6
*/
protected function allowAdd($data = [])
{
$user = $this->app->getIdentity();
$menuType = $this->input->getCmd('menutype', $data['menutype'] ?? '');
$menutypeID = 0;
// Load menutype ID
if ($menuType) {
$menutypeID = (int) $this->getMenuTypeId($menuType);
}
return $user->authorise('core.create', 'com_menus.menu.' . $menutypeID);
}
/**
* Method to check if you edit a record.
*
* Extended classes can override this if necessary.
*
* @param array $data An array of input data.
* @param string $key The name of the key for the primary key; default is id.
*
* @return boolean
*
* @since 3.6
*/
protected function allowEdit($data = [], $key = 'id')
{
$user = $this->app->getIdentity();
$menutypeID = 0;
if (isset($data[$key])) {
$model = $this->getModel();
$item = $model->getItem($data[$key]);
if (!empty($item->menutype)) {
// Protected menutype, do not allow edit
if ($item->menutype == 'main') {
return false;
}
$menutypeID = (int) $this->getMenuTypeId($item->menutype);
}
}
return $user->authorise('core.edit', 'com_menus.menu.' . (int) $menutypeID);
}
/**
* Loads the menutype ID by a given menutype string
*
* @param string $menutype The given menutype
*
* @return integer
*
* @since 3.6
*/
protected function getMenuTypeId($menutype)
{
$model = $this->getModel();
$table = $model->getTable('MenuType');
$table->load(['menutype' => $menutype]);
return (int) $table->id;
}
/**
* Method to add a new menu item.
*
* @return mixed True if the record can be added, otherwise false.
*
* @since 1.6
*/
public function add()
{
$result = parent::add();
if ($result) {
$context = 'com_menus.edit.item';
$this->app->setUserState($context . '.type', null);
$this->app->setUserState($context . '.link', null);
}
return $result;
}
/**
* Method to run batch operations.
*
* @param object $model The model.
*
* @return boolean True if successful, false otherwise and internal error is set.
*
* @since 1.6
*/
public function batch($model = null)
{
$this->checkToken();
/** @var \Joomla\Component\Menus\Administrator\Model\ItemModel $model */
$model = $this->getModel('Item', 'Administrator', []);
// Preset the redirect
$this->setRedirect(Route::_('index.php?option=com_menus&view=items' . $this->getRedirectToListAppend(), false));
return parent::batch($model);
}
/**
* Method to cancel an edit.
*
* @param string $key The name of the primary key of the URL variable.
*
* @return boolean True if access level checks pass, false otherwise.
*
* @since 1.6
*/
public function cancel($key = null)
{
$this->checkToken();
$result = parent::cancel();
if ($result) {
// Clear the ancillary data from the session.
$context = 'com_menus.edit.item';
$this->app->setUserState($context . '.type', null);
$this->app->setUserState($context . '.link', null);
// When editing in modal then redirect to modalreturn layout
if ($this->input->get('layout') === 'modal') {
$id = $this->input->get('id');
$return = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($id)
. '&layout=modalreturn&from-task=cancel';
} else {
$return = 'index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend()
. '&menutype=' . $this->app->getUserState('com_menus.items.menutype');
}
// Redirect to the list screen.
$this->setRedirect(Route::_($return, false));
}
return $result;
}
/**
* Method to edit an existing record.
*
* @param string $key The name of the primary key of the URL variable.
* @param string $urlVar The name of the URL variable if different from the primary key
* (sometimes required to avoid router collisions).
*
* @return boolean True if access level check and checkout passes, false otherwise.
*
* @since 1.6
*/
public function edit($key = null, $urlVar = null)
{
$result = parent::edit();
if ($result) {
// Push the new ancillary data into the session.
$this->app->setUserState('com_menus.edit.item.type', null);
$this->app->setUserState('com_menus.edit.item.link', 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 3.0.1
*/
protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id')
{
$append = parent::getRedirectToItemAppend($recordId, $urlVar);
if ($recordId) {
/** @var \Joomla\Component\Menus\Administrator\Model\ItemModel $model */
$model = $this->getModel();
$item = $model->getItem($recordId);
$clientId = $item->client_id;
$append = '&client_id=' . $clientId . $append;
} else {
$clientId = $this->input->get('client_id', '0', 'int');
$menuType = $this->input->get('menutype', 'mainmenu', 'cmd');
$append = '&client_id=' . $clientId . ($menuType ? '&menutype=' . $menuType : '') . $append;
}
return $append;
}
/**
* Method to save a record.
*
* @param string $key The name of the primary key of the URL variable.
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
*
* @return boolean True if successful, false otherwise.
*
* @since 1.6
*/
public function save($key = null, $urlVar = null)
{
// Check for request forgeries.
$this->checkToken();
/** @var \Joomla\Component\Menus\Administrator\Model\ItemModel $model */
$model = $this->getModel('Item', 'Administrator', []);
$table = $model->getTable();
$data = $this->input->post->get('jform', [], 'array');
$task = $this->getTask();
$context = 'com_menus.edit.item';
$app = $this->app;
// Set the menutype should we need it.
if ($data['menutype'] !== '') {
$this->input->set('menutype', $data['menutype']);
}
// Determine the name of the primary key for the data.
if (empty($key)) {
$key = $table->getKeyName();
}
// To avoid data collisions the urlVar may be different from the primary key.
if (empty($urlVar)) {
$urlVar = $key;
}
$recordId = $this->input->getInt($urlVar);
// Populate the row id from the session.
$data[$key] = $recordId;
// The save2copy task needs to be handled slightly differently.
if ($task == 'save2copy') {
// Check-in the original row.
if ($model->checkin($data['id']) === false) {
// Check-in failed, go back to the item and display a notice.
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()), 'warning');
return false;
}
// Reset the ID and then treat the request as for Apply.
$data['id'] = 0;
$data['associations'] = [];
$task = 'apply';
}
// Access check.
if (!$this->allowSave($data, $key)) {
$this->setMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'error');
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_list
. $this->getRedirectToListAppend(),
false
)
);
return false;
}
// Validate the posted data.
// This post is made up of two forms, one for the item and one for params.
$form = $model->getForm($data);
if (!$form) {
throw new \Exception($model->getError(), 500);
}
if ($data['type'] == 'url') {
$data['link'] = str_replace(['"', '>', '<'], '', $data['link']);
if (strstr($data['link'], ':')) {
$segments = explode(':', $data['link']);
$protocol = strtolower($segments[0]);
$scheme = [
'http', 'https', 'ftp', 'ftps', 'gopher', 'mailto',
'news', 'prospero', 'telnet', 'rlogin', 'tn3270', 'wais',
'mid', 'cid', 'nntp', 'tel', 'urn', 'ldap', 'file', 'fax',
'modem', 'git', 'sms',
];
if (!\in_array($protocol, $scheme)) {
$app->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'warning');
$this->setRedirect(
Route::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)
);
return false;
}
}
}
$data = $model->validate($form, $data);
// Preprocess request fields to ensure that we remove not set or empty request params
$request = $form->getGroup('request', true);
// Check for the special 'request' entry.
if ($data['type'] == 'component' && !empty($request)) {
$removeArgs = [];
if (!isset($data['request']) || !\is_array($data['request'])) {
$data['request'] = [];
}
foreach ($request as $field) {
$fieldName = $field->getAttribute('name');
if (!isset($data['request'][$fieldName]) || $data['request'][$fieldName] == '') {
$removeArgs[$fieldName] = '';
}
}
// Parse the submitted link arguments.
$args = [];
parse_str(parse_url($data['link'], PHP_URL_QUERY), $args);
// Merge in the user supplied request arguments.
$args = array_merge($args, $data['request']);
// Remove the unused request params
if (!empty($args) && !empty($removeArgs)) {
$args = array_diff_key($args, $removeArgs);
}
$data['link'] = 'index.php?' . urldecode(http_build_query($args, '', '&'));
}
// Check for validation errors.
if ($data === false) {
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$app->enqueueMessage($errors[$i]->getMessage(), 'warning');
} else {
$app->enqueueMessage($errors[$i], 'warning');
}
}
// Save the data in the session.
$app->setUserState('com_menus.edit.item.data', $data);
// Redirect back to the edit screen.
$editUrl = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId);
$this->setRedirect(Route::_($editUrl, false));
return false;
}
// Attempt to save the data.
if (!$model->save($data)) {
// Save the data in the session.
$app->setUserState('com_menus.edit.item.data', $data);
// Redirect back to the edit screen.
$editUrl = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId);
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
$this->setRedirect(Route::_($editUrl, false));
return false;
}
// Save succeeded, check-in the row.
if ($model->checkin($data['id']) === false) {
// Check-in failed, go back to the row and display a notice.
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()), 'warning');
$redirectUrl = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId);
$this->setRedirect(Route::_($redirectUrl, false));
return false;
}
$this->setMessage(Text::_('COM_MENUS_SAVE_SUCCESS'));
// Redirect the user and adjust session state based on the chosen task.
switch ($task) {
case 'apply':
// Set the row data in the session.
$recordId = $model->getState($this->context . '.id');
$this->holdEditId($context, $recordId);
$app->setUserState('com_menus.edit.item.data', null);
$app->setUserState('com_menus.edit.item.type', null);
$app->setUserState('com_menus.edit.item.link', null);
// Redirect back to the edit screen.
$editUrl = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId);
$this->setRedirect(Route::_($editUrl, false));
break;
case 'save2new':
// Clear the row id and data in the session.
$this->releaseEditId($context, $recordId);
$app->setUserState('com_menus.edit.item.data', null);
$app->setUserState('com_menus.edit.item.type', null);
$app->setUserState('com_menus.edit.item.link', null);
// Redirect back to the edit screen.
$this->setRedirect(Route::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend(), false));
break;
default:
// Clear the row id and data in the session.
$this->releaseEditId($context, $recordId);
$app->setUserState('com_menus.edit.item.data', null);
$app->setUserState('com_menus.edit.item.type', null);
$app->setUserState('com_menus.edit.item.link', null);
// When editing in modal then redirect to modalreturn layout
if ($this->input->get('layout') === 'modal') {
$return = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId)
. '&layout=modalreturn&from-task=save';
} else {
// Redirect to the list screen.
$return = 'index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend()
. '&menutype=' . $app->getUserState('com_menus.items.menutype');
}
$this->setRedirect(Route::_($return, false));
break;
}
return true;
}
/**
* Sets the type of the menu item currently being edited.
*
* @return void
*
* @since 1.6
*/
public function setType()
{
$this->checkToken();
$app = $this->app;
// Get the posted values from the request.
$data = $this->input->post->get('jform', [], 'array');
// Get the type.
$type = $data['type'];
$type = json_decode(base64_decode($type));
$title = $type->title ?? null;
$recordId = $type->id ?? 0;
$specialTypes = ['alias', 'separator', 'url', 'heading', 'container'];
if (!\in_array($title, $specialTypes)) {
$title = 'component';
} else {
// Set correct component id to ensure proper 404 messages with system links
$data['component_id'] = 0;
}
$app->setUserState('com_menus.edit.item.type', $title);
if ($title == 'component') {
if (isset($type->request)) {
// Clean component name
$type->request->option = InputFilter::getInstance()->clean($type->request->option, 'CMD');
$component = ComponentHelper::getComponent($type->request->option);
$data['component_id'] = $component->id;
$app->setUserState('com_menus.edit.item.link', 'index.php?' . Uri::buildQuery((array) $type->request));
}
} elseif ($title == 'alias') {
// If the type is alias you just need the item id from the menu item referenced.
$app->setUserState('com_menus.edit.item.link', 'index.php?Itemid=');
}
unset($data['request']);
$data['type'] = $title;
if ($this->input->get('fieldtype') == 'type') {
$data['link'] = $app->getUserState('com_menus.edit.item.link');
}
// Save the data in the session.
$app->setUserState('com_menus.edit.item.data', $data);
$this->setRedirect(
Route::_('index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($recordId), false)
);
}
/**
* Gets the parent items of the menu location currently.
*
* @return void
*
* @since 3.2
*/
public function getParentItem()
{
$app = $this->app;
$results = [];
$menutype = $this->input->get->get('menutype');
if ($menutype) {
/** @var \Joomla\Component\Menus\Administrator\Model\ItemsModel $model */
$model = $this->getModel('Items', 'Administrator', []);
$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++) {
$results[$i]->title = str_repeat(' - ', $results[$i]->level) . $results[$i]->title;
}
}
// Output a \JSON object
echo json_encode($results);
$app->close();
}
}

View File

@ -0,0 +1,249 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Controller;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\MVC\Controller\AdminController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\Router\Route;
use Joomla\Input\Input;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The Menu Item Controller
*
* @since 1.6
*/
class ItemsController extends AdminController
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
* @param MVCFactoryInterface $factory The factory.
* @param CMSApplication $app The Application for the dispatcher
* @param Input $input Input
*
* @since 1.6
*/
public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null)
{
parent::__construct($config, $factory, $app, $input);
$this->registerTask('unsetDefault', 'setDefault');
}
/**
* Proxy for getModel.
*
* @param string $name The model name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $config Configuration array for model. Optional.
*
* @return object The model.
*
* @since 1.6
*/
public function getModel($name = 'Item', $prefix = 'Administrator', $config = ['ignore_request' => true])
{
return parent::getModel($name, $prefix, $config);
}
/**
* Method to get the number of published frontend menu items for quickicons
*
* @return void
*
* @since 4.0.0
*/
public function getQuickiconContent()
{
$model = $this->getModel('Items');
$model->setState('filter.published', 1);
$model->setState('filter.client_id', 0);
$amount = (int) $model->getTotal();
$result = [];
$result['amount'] = $amount;
$result['sronly'] = Text::plural('COM_MENUS_ITEMS_N_QUICKICON_SRONLY', $amount);
$result['name'] = Text::plural('COM_MENUS_ITEMS_N_QUICKICON', $amount);
echo new JsonResponse($result);
}
/**
* Rebuild the nested set tree.
*
* @return boolean False on failure or error, true on success.
*
* @since 1.6
*/
public function rebuild()
{
$this->checkToken();
$this->setRedirect('index.php?option=com_menus&view=items&menutype=' . $this->input->getCmd('menutype'));
/** @var \Joomla\Component\Menus\Administrator\Model\ItemModel $model */
$model = $this->getModel();
if ($model->rebuild()) {
// Reorder succeeded.
$this->setMessage(Text::_('COM_MENUS_ITEMS_REBUILD_SUCCESS'));
return true;
}
// Rebuild failed.
$this->setMessage(Text::sprintf('COM_MENUS_ITEMS_REBUILD_FAILED'), 'error');
return false;
}
/**
* Method to set the home property for a list of items
*
* @return void
*
* @since 1.6
*/
public function setDefault()
{
// Check for request forgeries
$this->checkToken('request');
$app = $this->app;
// Get items to publish from the request.
$cid = (array) $this->input->get('cid', [], 'int');
$data = ['setDefault' => 1, 'unsetDefault' => 0];
$task = $this->getTask();
$value = ArrayHelper::getValue($data, $task, 0, 'int');
// Remove zero values resulting from input filter
$cid = array_filter($cid);
if (empty($cid)) {
$this->setMessage(Text::_($this->text_prefix . '_NO_ITEM_SELECTED'), 'warning');
} else {
// Get the model.
$model = $this->getModel();
// Publish the items.
if (!$model->setHome($cid, $value)) {
$this->setMessage($model->getError(), 'warning');
} else {
if ($value == 1) {
$ntext = 'COM_MENUS_ITEMS_SET_HOME';
} else {
$ntext = 'COM_MENUS_ITEMS_UNSET_HOME';
}
$this->setMessage(Text::plural($ntext, \count($cid)));
}
}
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_list
. '&menutype=' . $app->getUserState('com_menus.items.menutype'),
false
)
);
}
/**
* Method to publish a list of items
*
* @return void
*
* @since 3.6.0
*/
public function publish()
{
// Check for request forgeries
$this->checkToken();
// Get items to publish from the request.
$cid = (array) $this->input->get('cid', [], 'int');
$data = ['publish' => 1, 'unpublish' => 0, 'trash' => -2, 'report' => -3];
$task = $this->getTask();
$value = ArrayHelper::getValue($data, $task, 0, 'int');
// Remove zero values resulting from input filter
$cid = array_filter($cid);
if (empty($cid)) {
try {
Log::add(Text::_($this->text_prefix . '_NO_ITEM_SELECTED'), Log::WARNING, 'jerror');
} catch (\RuntimeException $exception) {
$this->setMessage(Text::_($this->text_prefix . '_NO_ITEM_SELECTED'), 'warning');
}
} else {
// Get the model.
$model = $this->getModel();
// Publish the items.
try {
$model->publish($cid, $value);
$errors = $model->getErrors();
$messageType = 'message';
if ($value == 1) {
if ($errors) {
$messageType = 'error';
$ntext = $this->text_prefix . '_N_ITEMS_FAILED_PUBLISHING';
} else {
$ntext = $this->text_prefix . '_N_ITEMS_PUBLISHED';
}
} elseif ($value == 0) {
$ntext = $this->text_prefix . '_N_ITEMS_UNPUBLISHED';
} else {
$ntext = $this->text_prefix . '_N_ITEMS_TRASHED';
}
$this->setMessage(Text::plural($ntext, \count($cid)), $messageType);
} catch (\Exception $e) {
$this->setMessage($e->getMessage(), 'error');
}
}
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_list . '&menutype=' .
$this->app->getUserState('com_menus.items.menutype'),
false
)
);
}
/**
* Gets the URL arguments to append to a list redirect.
*
* @return string The arguments to append to the redirect URL.
*
* @since 4.0.0
*/
protected function getRedirectToListAppend()
{
return '&menutype=' . $this->app->getUserState('com_menus.items.menutype');
}
}

View File

@ -0,0 +1,224 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Controller;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\Router\Route;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The Menu Type Controller
*
* @since 1.6
*/
class MenuController extends FormController
{
/**
* Dummy method to redirect back to standard controller
*
* @param boolean $cachable If true, the view output will be cached.
* @param array $urlparams An array of safe URL parameters and their variable types.
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
*
* @return void
*
* @since 1.5
*/
public function display($cachable = false, $urlparams = false)
{
$this->setRedirect(Route::_('index.php?option=com_menus&view=menus', false));
}
/**
* Method to save a menu item.
*
* @param string $key The name of the primary key of the URL variable.
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
*
* @return boolean True if successful, false otherwise.
*
* @since 1.6
*/
public function save($key = null, $urlVar = null)
{
// Check for request forgeries.
$this->checkToken();
$app = $this->app;
$data = $this->input->post->get('jform', [], 'array');
$context = 'com_menus.edit.menu';
$task = $this->getTask();
$recordId = $this->input->getInt('id');
// Prevent using 'main' as menutype as this is reserved for backend menus
if (strtolower($data['menutype']) == 'main') {
$this->setMessage(Text::_('COM_MENUS_ERROR_MENUTYPE'), 'error');
// Redirect back to the edit screen.
$this->setRedirect(Route::_('index.php?option=com_menus&view=menu&layout=edit' . $this->getRedirectToItemAppend($recordId), false));
return false;
}
$data['menutype'] = InputFilter::getInstance()->clean($data['menutype'], 'TRIM');
// Populate the row id from the session.
$data['id'] = $recordId;
// Get the model and attempt to validate the posted data.
/** @var \Joomla\Component\Menus\Administrator\Model\MenuModel $model */
$model = $this->getModel('Menu', '', ['ignore_request' => false]);
$form = $model->getForm();
if (!$form) {
throw new \Exception($model->getError(), 500);
}
$validData = $model->validate($form, $data);
// Check for validation errors.
if ($validData === false) {
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$app->enqueueMessage($errors[$i]->getMessage(), 'warning');
} else {
$app->enqueueMessage($errors[$i], 'warning');
}
}
// Save the data in the session.
$app->setUserState($context . '.data', $data);
// Redirect back to the edit screen.
$this->setRedirect(Route::_('index.php?option=com_menus&view=menu&layout=edit' . $this->getRedirectToItemAppend($recordId), false));
return false;
}
if (isset($validData['preset'])) {
$preset = trim($validData['preset']) ?: null;
unset($validData['preset']);
}
// Attempt to save the data.
if (!$model->save($validData)) {
// Save the data in the session.
$app->setUserState($context . '.data', $validData);
// Redirect back to the edit screen.
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
$this->setRedirect(Route::_('index.php?option=com_menus&view=menu&layout=edit' . $this->getRedirectToItemAppend($recordId), false));
return false;
}
// Import the preset selected
if (isset($preset) && $data['client_id'] == 1) {
// Menu Type has not been saved yet. Make sure items get the real menutype.
$menutype = ApplicationHelper::stringURLSafe($data['menutype']);
try {
MenusHelper::installPreset($preset, $menutype);
$this->setMessage(Text::_('COM_MENUS_PRESET_IMPORT_SUCCESS'));
} catch (\Exception $e) {
// Save was successful but the preset could not be loaded. Let it through with just a warning
$this->setMessage(Text::sprintf('COM_MENUS_PRESET_IMPORT_FAILED', $e->getMessage()));
}
} else {
$this->setMessage(Text::_('COM_MENUS_MENU_SAVE_SUCCESS'));
}
// Redirect the user and adjust session state based on the chosen task.
switch ($task) {
case 'apply':
// Set the record data in the session.
$recordId = $model->getState($this->context . '.id');
$this->holdEditId($context, $recordId);
$app->setUserState($context . '.data', null);
// Redirect back to the edit screen.
$this->setRedirect(Route::_('index.php?option=com_menus&view=menu&layout=edit' . $this->getRedirectToItemAppend($recordId), false));
break;
case 'save2new':
// Clear the record id and data from the session.
$this->releaseEditId($context, $recordId);
$app->setUserState($context . '.data', null);
// Redirect back to the edit screen.
$this->setRedirect(Route::_('index.php?option=com_menus&view=menu&layout=edit', false));
break;
default:
// Clear the record id and data from the session.
$this->releaseEditId($context, $recordId);
$app->setUserState($context . '.data', null);
// Redirect to the list screen.
$this->setRedirect(Route::_('index.php?option=com_menus&view=menus', false));
break;
}
}
/**
* Method to display a menu as preset xml.
*
* @return boolean True if successful, false otherwise.
*
* @since 3.8.0
*/
public function exportXml()
{
// Check for request forgeries.
$this->checkToken();
$cid = (array) $this->input->get('cid', [], 'int');
// We know the first element is the one we need because we don't allow multi selection of rows
$id = empty($cid) ? 0 : reset($cid);
if ($id === 0) {
$this->setMessage(Text::_('COM_MENUS_SELECT_MENU_FIRST_EXPORT'), 'warning');
$this->setRedirect(Route::_('index.php?option=com_menus&view=menus', false));
return false;
}
$model = $this->getModel('Menu');
$item = $model->getItem($id);
if (!$item->menutype) {
$this->setMessage(Text::_('COM_MENUS_SELECT_MENU_FIRST_EXPORT'), 'warning');
$this->setRedirect(Route::_('index.php?option=com_menus&view=menus', false));
return false;
}
$this->setRedirect(Route::_('index.php?option=com_menus&view=menu&menutype=' . $item->menutype . '&format=xml', false));
return true;
}
}

View File

@ -0,0 +1,104 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\AdminController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The Menu List Controller
*
* @since 1.6
*/
class MenusController extends AdminController
{
/**
* Display the view
*
* @param boolean $cachable If true, the view output will be cached.
* @param array $urlparams An array of safe URL parameters and their variable types.
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
*
* @return void
*
* @since 1.6
*/
public function display($cachable = false, $urlparams = false)
{
}
/**
* Method to get a model object, loading it if required.
*
* @param string $name The model name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $config Configuration array for model. Optional.
*
* @return object The model.
*
* @since 1.6
*/
public function getModel($name = 'Menu', $prefix = 'Administrator', $config = ['ignore_request' => true])
{
return parent::getModel($name, $prefix, $config);
}
/**
* Remove an item.
*
* @return void
*
* @since 1.6
*/
public function delete()
{
// Check for request forgeries
$this->checkToken();
$user = $this->app->getIdentity();
$cids = (array) $this->input->get('cid', [], 'int');
// Remove zero values resulting from input filter
$cids = array_filter($cids);
if (empty($cids)) {
$this->setMessage(Text::_('COM_MENUS_NO_MENUS_SELECTED'), 'warning');
} else {
// Access checks.
foreach ($cids as $i => $id) {
if (!$user->authorise('core.delete', 'com_menus.menu.' . (int) $id)) {
// Prune items that you can't change.
unset($cids[$i]);
$this->app->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), 'error');
}
}
if (\count($cids) > 0) {
// Get the model.
/** @var \Joomla\Component\Menus\Administrator\Model\MenuModel $model */
$model = $this->getModel();
// Remove the items.
if (!$model->delete($cids)) {
$this->setMessage($model->getError(), 'error');
} else {
$this->setMessage(Text::plural('COM_MENUS_N_MENUS_DELETED', \count($cids)));
}
}
}
$this->setRedirect('index.php?option=com_menus&view=menus');
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Extension;
use Joomla\CMS\Association\AssociationServiceInterface;
use Joomla\CMS\Association\AssociationServiceTrait;
use Joomla\CMS\Extension\BootableExtensionInterface;
use Joomla\CMS\Extension\MVCComponent;
use Joomla\CMS\HTML\HTMLRegistryAwareTrait;
use Joomla\Component\Menus\Administrator\Service\HTML\Menus;
use Psr\Container\ContainerInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Component class for com_menus
*
* @since 4.0.0
*/
class MenusComponent extends MVCComponent implements
BootableExtensionInterface,
AssociationServiceInterface
{
use AssociationServiceTrait;
use HTMLRegistryAwareTrait;
/**
* Booting the extension. This is the function to set up the environment of the extension like
* registering new class loaders, etc.
*
* If required, some initial set up can be done from services of the container, eg.
* registering HTML services.
*
* @param ContainerInterface $container The container
*
* @return void
*
* @since 4.0.0
*/
public function boot(ContainerInterface $container)
{
$this->getRegistry()->register('menus', new Menus());
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Language\Text;
use Joomla\Utilities\ArrayHelper;
/**
* MenuItem by Component field.
*
* @since 4.3.0
*/
class MenuItemByComponentField extends ListField
{
/**
* The form field type.
*
* @var string
* @since 4.3.0
*/
protected $type = 'MenuItemByComponent';
/**
* Method to get a list of options for a list input.
*
* @return array An array of JHtml options.
*
* @since 4.3.0
*/
protected function getOptions()
{
// Initialise variable.
$db = $this->getDatabase();
$options = [];
$query = $db->getQuery(true);
$query->select('DISTINCT ' . $db->quoteName('extensions.element'))
->from($db->quoteName('#__menu', 'menu'))
->join(
'INNER',
$db->quoteName('#__extensions', 'extensions'),
$db->quoteName('extensions.extension_id') . ' = ' . $db->quoteName('menu.component_id')
)
->where($db->quoteName('menu.client_id') . ' = 0')
->where($db->quoteName('menu.type') . ' = ' . $db->quote('component'))
->where($db->quoteName('extensions.extension_id') . ' IS NOT NULL');
$app = Factory::getApplication();
$currentMenuType = $app->getInput()->getString('menutype', $app->getUserState($this->context . '.menutype', ''));
if ($currentMenuType) {
$query->where($db->quoteName('menu.menutype') . ' = :currentMenuType')
->bind(':currentMenuType', $currentMenuType);
}
$db->setQuery($query);
$components = $db->loadColumn();
foreach ($components as $component) {
// Load component language files
$lang = $app->getLanguage();
$lang->load($component, JPATH_BASE)
|| $lang->load($component, JPATH_ADMINISTRATOR . '/components/' . $component);
$option = new \stdClass();
$option->value = $component;
$option->text = Text::_(strtoupper($component));
$options[] = $option;
}
// Sort by name
$options = ArrayHelper::sortObjects($options, 'text', 1, true, true);
// Merge any additional options in the XML definition.
$options = array_merge(parent::getOptions(), $options);
return $options;
}
}

View File

@ -0,0 +1,272 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\GroupedlistField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Supports an HTML grouped select list of menu item grouped by menu
*
* @since 3.8.0
*/
class MenuItemByTypeField extends GroupedlistField
{
/**
* The form field type.
*
* @var string
* @since 3.8.0
*/
public $type = 'MenuItemByType';
/**
* The menu type.
*
* @var string
* @since 3.8.0
*/
protected $menuType;
/**
* The client id.
*
* @var string
* @since 3.8.0
*/
protected $clientId;
/**
* The language.
*
* @var array
* @since 3.8.0
*/
protected $language;
/**
* The published status.
*
* @var array
* @since 3.8.0
*/
protected $published;
/**
* The disabled status.
*
* @var array
* @since 3.8.0
*/
protected $disable;
/**
* Method to get certain otherwise inaccessible properties from the form field object.
*
* @param string $name The property name for which to get the value.
*
* @return mixed The property value or null.
*
* @since 3.8.0
*/
public function __get($name)
{
switch ($name) {
case 'menuType':
case 'clientId':
case 'language':
case 'published':
case 'disable':
return $this->$name;
}
return parent::__get($name);
}
/**
* Method to set certain otherwise inaccessible properties of the form field object.
*
* @param string $name The property name for which to set the value.
* @param mixed $value The value of the property.
*
* @return void
*
* @since 3.8.0
*/
public function __set($name, $value)
{
switch ($name) {
case 'menuType':
$this->menuType = (string) $value;
break;
case 'clientId':
$this->clientId = (int) $value;
break;
case 'language':
case 'published':
case 'disable':
$value = (string) $value;
$this->$name = $value ? explode(',', $value) : [];
break;
default:
parent::__set($name, $value);
}
}
/**
* Method to attach a JForm object to the field.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
*
* @return boolean True on success.
*
* @see \Joomla\CMS\Form\FormField::setup()
* @since 3.8.0
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$result = parent::setup($element, $value, $group);
if ($result == true) {
$menuType = (string) $this->element['menu_type'];
if (!$menuType) {
$app = Factory::getApplication();
$currentMenuType = $app->getUserState('com_menus.items.menutype', '');
$menuType = $app->getInput()->getString('menutype', $currentMenuType);
}
$this->menuType = $menuType;
$this->clientId = (int) $this->element['client_id'];
$this->published = $this->element['published'] ? explode(',', (string) $this->element['published']) : [];
$this->disable = $this->element['disable'] ? explode(',', (string) $this->element['disable']) : [];
$this->language = $this->element['language'] ? explode(',', (string) $this->element['language']) : [];
}
return $result;
}
/**
* Method to get the field option groups.
*
* @return array The field option objects as a nested array in groups.
*
* @since 3.8.0
*/
protected function getGroups()
{
$groups = [];
$menuType = $this->menuType;
// Get the menu items.
$items = MenusHelper::getMenuLinks($menuType, 0, 0, $this->published, $this->language, $this->clientId);
// Build group for a specific menu type.
if ($menuType) {
// If the menutype is empty, group the items by menutype.
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('title'))
->from($db->quoteName('#__menu_types'))
->where($db->quoteName('menutype') . ' = :menuType')
->bind(':menuType', $menuType);
$db->setQuery($query);
try {
$menuTitle = $db->loadResult();
} catch (\RuntimeException $e) {
$menuTitle = $menuType;
}
// Initialize the group.
$groups[$menuTitle] = [];
// Build the options array.
foreach ($items as $key => $link) {
// Unset if item is menu_item_root
if ($link->text === 'Menu_Item_Root') {
unset($items[$key]);
continue;
}
$levelPrefix = str_repeat('- ', max(0, $link->level - 1));
// Displays language code if not set to All
if ($link->language !== '*') {
$lang = ' (' . $link->language . ')';
} else {
$lang = '';
}
$text = Text::_($link->text);
$groups[$menuTitle][] = HTMLHelper::_(
'select.option',
$link->value,
$levelPrefix . $text . $lang,
'value',
'text',
\in_array($link->type, $this->disable)
);
}
} else {
// Build groups for all menu types.
// Build the groups arrays.
foreach ($items as $menu) {
// Initialize the group.
$groups[$menu->title] = [];
// Build the options array.
foreach ($menu->links as $link) {
$levelPrefix = str_repeat('- ', max(0, $link->level - 1));
// Displays language code if not set to All
if ($link->language !== '*') {
$lang = ' (' . $link->language . ')';
} else {
$lang = '';
}
$text = Text::_($link->text);
$groups[$menu->title][] = HTMLHelper::_(
'select.option',
$link->value,
$levelPrefix . $text . $lang,
'value',
'text',
\in_array($link->type, $this->disable)
);
}
}
}
// Merge any additional groups in the XML definition.
$groups = array_merge(parent::getGroups(), $groups);
return $groups;
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Language\Text;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu Ordering field.
*
* @since 1.6
*/
class MenuOrderingField extends ListField
{
/**
* The form field type.
*
* @var string
* @since 1.7
*/
protected $type = 'MenuOrdering';
/**
* Method to get the list of siblings in a menu.
* The method requires that parent be set.
*
* @return array|boolean The field option objects or false if the parent field has not been set
*
* @since 1.7
*/
protected function getOptions()
{
$options = [];
// Get the parent
$parent_id = (int) $this->form->getValue('parent_id', 0);
if (!$parent_id) {
return false;
}
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select(
[
$db->quoteName('a.id', 'value'),
$db->quoteName('a.title', 'text'),
$db->quoteName('a.client_id', 'clientId'),
]
)
->from($db->quoteName('#__menu', 'a'))
->where($db->quoteName('a.published') . ' >= 0')
->where($db->quoteName('a.parent_id') . ' = :parentId')
->bind(':parentId', $parent_id, ParameterType::INTEGER);
if ($menuType = $this->form->getValue('menutype')) {
$query->where($db->quoteName('a.menutype') . ' = :menuType')
->bind(':menuType', $menuType);
} else {
$query->where($db->quoteName('a.menutype') . ' != ' . $db->quote(''));
}
$query->order($db->quoteName('a.lft') . ' ASC');
// Get the options.
$db->setQuery($query);
try {
$options = $db->loadObjectList();
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
}
// Allow translation of custom admin menus
foreach ($options as &$option) {
if ($option->clientId != 0) {
$option->text = Text::_($option->text);
}
}
$options = array_merge(
[['value' => '-1', 'text' => Text::_('COM_MENUS_ITEM_FIELD_ORDERING_VALUE_FIRST')]],
$options,
[['value' => '-2', 'text' => Text::_('COM_MENUS_ITEM_FIELD_ORDERING_VALUE_LAST')]]
);
// Merge any additional options in the XML definition.
$options = array_merge(parent::getOptions(), $options);
return $options;
}
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*
* @since 1.7
*/
protected function getInput()
{
if ($this->form->getValue('id', 0) == 0) {
return '<span class="readonly">' . Text::_('COM_MENUS_ITEM_FIELD_ORDERING_TEXT') . '</span>';
}
return parent::getInput();
}
}

View File

@ -0,0 +1,116 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Language\Text;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu Parent field.
*
* @since 1.6
*/
class MenuParentField extends ListField
{
/**
* The form field type.
*
* @var string
* @since 1.6
*/
protected $type = 'MenuParent';
/**
* Method to get the field options.
*
* @return array The field option objects.
*
* @since 1.6
*/
protected function getOptions()
{
$options = [];
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select(
[
'DISTINCT ' . $db->quoteName('a.id', 'value'),
$db->quoteName('a.title', 'text'),
$db->quoteName('a.level'),
$db->quoteName('a.lft'),
]
)
->from($db->quoteName('#__menu', 'a'));
// Filter by menu type.
if ($menuType = $this->form->getValue('menutype')) {
$query->where($db->quoteName('a.menutype') . ' = :menuType')
->bind(':menuType', $menuType);
} else {
// Skip special menu types
$query->where($db->quoteName('a.menutype') . ' != ' . $db->quote(''));
$query->where($db->quoteName('a.menutype') . ' != ' . $db->quote('main'));
}
// Filter by client id.
$clientId = $this->getAttribute('clientid');
if (!\is_null($clientId)) {
$clientId = (int) $clientId;
$query->where($db->quoteName('a.client_id') . ' = :clientId')
->bind(':clientId', $clientId, ParameterType::INTEGER);
}
// Prevent parenting to children of this item.
if ($id = (int) $this->form->getValue('id')) {
$query->join('LEFT', $db->quoteName('#__menu', 'p'), $db->quoteName('p.id') . ' = :id')
->bind(':id', $id, ParameterType::INTEGER)
->where(
'NOT(' . $db->quoteName('a.lft') . ' >= ' . $db->quoteName('p.lft')
. ' AND ' . $db->quoteName('a.rgt') . ' <= ' . $db->quoteName('p.rgt') . ')'
);
}
$query->where($db->quoteName('a.published') . ' != -2')
->order($db->quoteName('a.lft') . ' ASC');
// Get the options.
$db->setQuery($query);
try {
$options = $db->loadObjectList();
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
}
// Pad the option text with spaces using depth level as a multiplier.
for ($i = 0, $n = \count($options); $i < $n; $i++) {
if ($clientId != 0) {
// Allow translation of custom admin menus
$options[$i]->text = str_repeat('- ', $options[$i]->level) . Text::_($options[$i]->text);
} else {
$options[$i]->text = str_repeat('- ', $options[$i]->level) . $options[$i]->text;
}
}
// Merge any additional options in the XML definition.
$options = array_merge(parent::getOptions(), $options);
return $options;
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Administrator Menu Presets list field.
*
* @since 3.8.0
*/
class MenuPresetField extends ListField
{
/**
* The form field type.
*
* @var string
*
* @since 3.8.0
*/
protected $type = 'MenuPreset';
/**
* Method to get the field options.
*
* @return array The field option objects.
*
* @since 3.8.0
*/
protected function getOptions()
{
$options = [];
$presets = MenusHelper::getPresets();
foreach ($presets as $preset) {
$options[] = HTMLHelper::_('select.option', $preset->name, Text::_($preset->title));
}
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,149 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field;
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;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu Type field.
*
* @since 1.6
*/
class MenutypeField extends ModalSelectField
{
/**
* The form field type.
*
* @var string
* @since 1.6
*/
protected $type = 'menutype';
/**
* Method to attach a Form object to the field.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value.
*
* @return boolean True on success.
*
* @see FormField::setup()
* @since 5.0.0
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$result = parent::setup($element, $value, $group);
if (!$result) {
return $result;
}
$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);
$this->urls['select'] = $url;
$this->canDo['clear'] = false;
$this->modalTitles['select'] = Text::_('COM_MENUS_ITEM_FIELD_TYPE_LABEL');
$this->buttonIcons['select'] = 'icon-list';
return $result;
}
/**
* Method to retrieve the title of selected item.
*
* @return string
*
* @since 5.0.0
*/
protected function getValueTitle()
{
$title = '';
$clientId = (int) $this->element['clientid'] ?: 0;
// Get a reverse lookup of the base link URL to Title
switch ($this->value) {
case 'url':
$title = Text::_('COM_MENUS_TYPE_EXTERNAL_URL');
break;
case 'alias':
$title = Text::_('COM_MENUS_TYPE_ALIAS');
break;
case 'separator':
$title = Text::_('COM_MENUS_TYPE_SEPARATOR');
break;
case 'heading':
$title = Text::_('COM_MENUS_TYPE_HEADING');
break;
case 'container':
$title = Text::_('COM_MENUS_TYPE_CONTAINER');
break;
default:
$link = $this->form->getValue('link');
if ($link !== null) {
/** @var \Joomla\Component\Menus\Administrator\Model\MenutypesModel $model */
$model = Factory::getApplication()->bootComponent('com_menus')
->getMVCFactory()->createModel('Menutypes', 'Administrator', ['ignore_request' => true]);
$model->setState('client_id', $clientId);
$rlu = $model->getReverseLookup();
// Clean the link back to the option, view and layout
$title = Text::_(ArrayHelper::getValue($rlu, MenusHelper::getLinkKey($link)));
}
break;
}
return $title;
}
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*
* @since 5.0.0
*/
protected function getInput()
{
// Get the layout data
$data = $this->getLayoutData();
// Load the content title here to avoid a double DB Query
$data['valueTitle'] = $this->getValueTitle();
// On new item creation the model forces the value to be 'component',
// However this is need to be empty in the input for correct validation and rendering.
if ($data['value'] === 'component' && !$data['valueTitle'] && !$this->form->getValue('link')) {
$data['value'] = '';
}
return $this->getRenderer($this->layout)->render($data);
}
}

View File

@ -0,0 +1,292 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Field\Modal;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\ModalSelectField;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Supports a modal menu item picker.
*
* @since 3.7.0
*/
class MenuField extends ModalSelectField
{
/**
* The form field type.
*
* @var string
* @since 3.7.0
*/
protected $type = 'Modal_Menu';
/**
* Method to get certain otherwise inaccessible properties from the form field object.
*
* @param string $name The property name for which to get the value.
*
* @return mixed The property value or null.
*
* @since 3.7.0
*/
public function __get($name)
{
switch ($name) {
case 'allowSelect':
case 'allowClear':
case 'allowNew':
case 'allowEdit':
case 'allowPropagate':
// @TODO: The override only for backward compatibility. Remove in Joomla 6.
$map = [
'allowSelect' => 'select',
'allowClear' => 'clear',
'allowNew' => 'new',
'allowEdit' => 'edit',
'allowPropagate' => 'propagate',
];
$newName = $map[$name];
@trigger_error(
sprintf(
'MenuField::__get property "%s" is deprecated, and will not work in Joomla 6. Use "%s" property instead.',
$name,
$newName
),
E_USER_DEPRECATED
);
return parent::__get($newName);
}
return parent::__get($name);
}
/**
* Method to set certain otherwise inaccessible properties of the form field object.
*
* @param string $name The property name for which to set the value.
* @param mixed $value The value of the property.
*
* @return void
*
* @since 3.7.0
*/
public function __set($name, $value)
{
switch ($name) {
case 'allowSelect':
case 'allowClear':
case 'allowNew':
case 'allowEdit':
case 'allowPropagate':
// @TODO: The override only for backward compatibility. Remove in Joomla 6.
$map = [
'allowSelect' => 'select',
'allowClear' => 'clear',
'allowNew' => 'new',
'allowEdit' => 'edit',
'allowPropagate' => 'propagate',
];
$newName = $map[$name];
@trigger_error(
sprintf(
'MenuField::__set property "%s" is deprecated, and will not work in Joomla 6. Use "%s" property instead.',
$name,
$newName
),
E_USER_DEPRECATED
);
$value = (string) $value;
$value = !($value === 'false' || $value === 'off' || $value === '0');
parent::__set($newName, $value);
break;
default:
parent::__set($name, $value);
}
}
/**
* Method to attach a JForm object to the field.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
*
* @return boolean True on success.
*
* @see FormField::setup()
* @since 3.7.0
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
// Check if the value consist with id:alias, extract the id only
if ($value && str_contains($value, ':')) {
[$id] = explode(':', $value, 2);
$value = (int) $id;
}
$return = parent::setup($element, $value, $group);
if (!$return) {
return $return;
}
$app = Factory::getApplication();
$app->getLanguage()->load('com_menus', JPATH_ADMINISTRATOR);
$languages = LanguageHelper::getContentLanguages([0, 1], false);
$language = (string) $this->element['language'];
$clientId = (int) $this->element['clientid'];
// Prepare enabled actions
$this->canDo['propagate'] = ((string) $this->element['propagate'] === 'true') && \count($languages) > 2;
// Creating/editing menu items is not supported in frontend.
if (!$app->isClient('administrator')) {
$this->canDo['new'] = false;
$this->canDo['edit'] = false;
}
// Prepare Urls
$linkItems = (new Uri())->setPath(Uri::base(true) . '/index.php');
$linkItems->setQuery([
'option' => 'com_menus',
'view' => 'items',
'layout' => 'modal',
'tmpl' => 'component',
'client_id' => $clientId,
Session::getFormToken() => 1,
]);
$linkItem = clone $linkItems;
$linkItem->setVar('view', 'item');
$linkCheckin = (new Uri())->setPath(Uri::base(true) . '/index.php');
$linkCheckin->setQuery([
'option' => 'com_menus',
'task' => 'items.checkin',
'format' => 'json',
Session::getFormToken() => 1,
]);
if ($language) {
$linkItems->setVar('forcedLanguage', $language);
$linkItem->setVar('forcedLanguage', $language);
$modalTitle = Text::_('COM_MENUS_SELECT_A_MENUITEM') . ' &#8212; ' . $this->getTitle();
$this->dataAttributes['data-language'] = $language;
} else {
$modalTitle = Text::_('COM_MENUS_SELECT_A_MENUITEM');
}
$urlSelect = $linkItems;
$urlEdit = clone $linkItem;
$urlEdit->setVar('task', 'item.edit');
$urlNew = clone $linkItem;
$urlNew->setVar('task', 'item.add');
$this->urls['select'] = (string) $urlSelect;
$this->urls['new'] = (string) $urlNew;
$this->urls['edit'] = (string) $urlEdit;
$this->urls['checkin'] = (string) $linkCheckin;
// Prepare titles
$this->modalTitles['select'] = $modalTitle;
$this->modalTitles['new'] = Text::_('COM_MENUS_NEW_MENUITEM');
$this->modalTitles['edit'] = Text::_('COM_MENUS_EDIT_MENUITEM');
$this->hint = $this->hint ?: Text::_('COM_MENUS_SELECT_A_MENUITEM');
return $return;
}
/**
* Method to retrieve the title of selected item.
*
* @return string
*
* @since 5.0.0
*/
protected function getValueTitle()
{
$value = (int) $this->value ?: '';
$title = '';
if ($value) {
try {
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('title'))
->from($db->quoteName('#__menu'))
->where($db->quoteName('id') . ' = :id')
->bind(':id', $value, ParameterType::INTEGER);
$db->setQuery($query);
$title = $db->loadResult();
} catch (\Throwable $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
}
}
return $title ?: $value;
}
/**
* Method to get the data to be passed to the layout for rendering.
*
* @return array
*
* @since 5.0.0
*/
protected function getLayoutData()
{
$data = parent::getLayoutData();
$data['language'] = (string) $this->element['language'];
return $data;
}
/**
* Get the renderer
*
* @param string $layoutId Id to load
*
* @return FileLayout
*
* @since 5.0.0
*/
protected function getRenderer($layoutId = 'default')
{
$layout = parent::getRenderer($layoutId);
$layout->setComponent('com_menus');
$layout->setClient(1);
return $layout;
}
}

View File

@ -0,0 +1,182 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Helper;
use Joomla\CMS\Association\AssociationExtensionHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Table\Table;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu associations helper.
*
* @since 3.7.0
*/
class AssociationsHelper extends AssociationExtensionHelper
{
/**
* The extension name
*
* @var array $extension
*
* @since 3.7.0
*/
protected $extension = 'com_menus';
/**
* Array of item types
*
* @var array $itemTypes
*
* @since 3.7.0
*/
protected $itemTypes = ['item'];
/**
* Has the extension association support
*
* @var boolean $associationsSupport
*
* @since 3.7.0
*/
protected $associationsSupport = true;
/**
* Method to get the associations for a given item.
*
* @param integer $id Id of the item
* @param string $view Name of the view
*
* @return array Array of associations for the item
*
* @since 4.0.0
*/
public function getAssociationsForItem($id = 0, $view = null)
{
return [];
}
/**
* Get the associated items for an item
*
* @param string $typeName The item type
* @param int $id The id of item for which we need the associated items
*
* @return array
*
* @since 3.7.0
*/
public function getAssociations($typeName, $id)
{
$type = $this->getType($typeName);
$context = $this->extension . '.item';
// Get the associations.
$associations = Associations::getAssociations(
$this->extension,
$type['tables']['a'],
$context,
$id,
'id',
'alias',
''
);
return $associations;
}
/**
* Get item information
*
* @param string $typeName The item type
* @param int $id The id of item for which we need the associated items
*
* @return Table|null
*
* @since 3.7.0
*/
public function getItem($typeName, $id)
{
if (empty($id)) {
return null;
}
$table = null;
switch ($typeName) {
case 'item':
$table = Table::getInstance('menu');
break;
}
if (\is_null($table)) {
return null;
}
$table->load($id);
return $table;
}
/**
* Get information about the type
*
* @param string $typeName The item type
*
* @return array Array of item types
*
* @since 3.7.0
*/
public function getType($typeName = '')
{
$fields = $this->getFieldsTemplate();
$tables = [];
$joins = [];
$support = $this->getSupportTemplate();
$title = '';
if (\in_array($typeName, $this->itemTypes)) {
switch ($typeName) {
case 'item':
$fields['ordering'] = 'a.lft';
$fields['level'] = 'a.level';
$fields['catid'] = '';
$fields['state'] = 'a.published';
$fields['created_user_id'] = '';
$fields['menutype'] = 'a.menutype';
$support['state'] = true;
$support['acl'] = true;
$support['checkout'] = true;
$support['level'] = true;
$tables = [
'a' => '#__menu',
];
$title = 'menu';
break;
}
}
return [
'fields' => $fields,
'support' => $support,
'tables' => $tables,
'joins' => $joins,
'title' => $title,
];
}
}

View File

@ -0,0 +1,908 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Helper;
use Joomla\CMS\Application\ApplicationHelper;
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;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Menu\AdministratorMenuItem;
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\File;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menus component helper.
*
* @since 1.6
*/
class MenusHelper extends ContentHelper
{
/**
* Defines the valid request variables for the reverse lookup.
*
* @var array
*/
protected static $_filter = ['option', 'view', 'layout'];
/**
* List of preset include paths
*
* @var array
*
* @since 4.0.0
*/
protected static $presets = null;
/**
* Gets a standard form of a link for lookups.
*
* @param mixed $request A link string or array of request variables.
*
* @return mixed A link in standard option-view-layout form, or false if the supplied response is invalid.
*
* @since 1.6
*/
public static function getLinkKey($request)
{
if (empty($request)) {
return false;
}
// Check if the link is in the form of index.php?...
if (\is_string($request)) {
$args = [];
if (strpos($request, 'index.php') === 0) {
parse_str(parse_url(htmlspecialchars_decode($request), PHP_URL_QUERY), $args);
} else {
parse_str($request, $args);
}
$request = $args;
}
// Only take the option, view and layout parts.
foreach ($request as $name => $value) {
if ((!\in_array($name, self::$_filter)) && (!($name == 'task' && !\array_key_exists('view', $request)))) {
// Remove the variables we want to ignore.
unset($request[$name]);
}
}
ksort($request);
return 'index.php?' . http_build_query($request, '', '&');
}
/**
* Get the menu list for create a menu module
*
* @param int $clientId Optional client id - viz 0 = site, 1 = administrator, can be NULL for all
*
* @return array The menu array list
*
* @since 1.6
*/
public static function getMenuTypes($clientId = 0)
{
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName('a.menutype'))
->from($db->quoteName('#__menu_types', 'a'));
if (isset($clientId)) {
$clientId = (int) $clientId;
$query->where($db->quoteName('a.client_id') . ' = :clientId')
->bind(':clientId', $clientId, ParameterType::INTEGER);
}
$db->setQuery($query);
return $db->loadColumn();
}
/**
* Get a list of menu links for one or all menus.
*
* @param string $menuType An option menu to filter the list on, otherwise all menu with given client id links
* are returned as a grouped array.
* @param integer $parentId An optional parent ID to pivot results around.
* @param integer $mode An optional mode. If parent ID is set and mode=2, the parent and children are excluded from the list.
* @param array $published An optional array of states
* @param array $languages Optional array of specify which languages we want to filter
* @param int $clientId Optional client id - viz 0 = site, 1 = administrator, can be NULL for all (used only if menutype not given)
*
* @return array|boolean
*
* @since 1.6
*/
public static function getMenuLinks($menuType = null, $parentId = 0, $mode = 0, $published = [], $languages = [], $clientId = 0)
{
$hasClientId = $clientId !== null;
$clientId = (int) $clientId;
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select(
[
'DISTINCT ' . $db->quoteName('a.id', 'value'),
$db->quoteName('a.title', 'text'),
$db->quoteName('a.alias'),
$db->quoteName('a.level'),
$db->quoteName('a.menutype'),
$db->quoteName('a.client_id'),
$db->quoteName('a.type'),
$db->quoteName('a.published'),
$db->quoteName('a.template_style_id'),
$db->quoteName('a.checked_out'),
$db->quoteName('a.language'),
$db->quoteName('a.lft'),
$db->quoteName('e.name', 'componentname'),
$db->quoteName('e.element'),
]
)
->from($db->quoteName('#__menu', 'a'))
->join('LEFT', $db->quoteName('#__extensions', 'e'), $db->quoteName('e.extension_id') . ' = ' . $db->quoteName('a.component_id'));
if (Multilanguage::isEnabled()) {
$query->select(
[
$db->quoteName('l.title', 'language_title'),
$db->quoteName('l.image', 'language_image'),
$db->quoteName('l.sef', 'language_sef'),
]
)
->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language'));
}
// Filter by the type if given, this is more specific than client id
if ($menuType) {
$query->where('(' . $db->quoteName('a.menutype') . ' = :menuType OR ' . $db->quoteName('a.parent_id') . ' = 0)')
->bind(':menuType', $menuType);
} elseif ($hasClientId) {
$query->where($db->quoteName('a.client_id') . ' = :clientId')
->bind(':clientId', $clientId, ParameterType::INTEGER);
}
// Prevent the parent and children from showing if requested.
if ($parentId && $mode == 2) {
$query->join('LEFT', $db->quoteName('#__menu', 'p'), $db->quoteName('p.id') . ' = :parentId')
->where(
'(' . $db->quoteName('a.lft') . ' <= ' . $db->quoteName('p.lft')
. ' OR ' . $db->quoteName('a.rgt') . ' >= ' . $db->quoteName('p.rgt') . ')'
)
->bind(':parentId', $parentId, ParameterType::INTEGER);
}
if (!empty($languages)) {
$query->whereIn($db->quoteName('a.language'), (array) $languages, ParameterType::STRING);
}
if (!empty($published)) {
$query->whereIn($db->quoteName('a.published'), (array) $published);
}
$query->where($db->quoteName('a.published') . ' != -2');
$query->order($db->quoteName('a.lft') . ' ASC');
try {
// Get the options.
$db->setQuery($query);
$links = $db->loadObjectList();
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
return false;
}
if (empty($menuType)) {
// If the menutype is empty, group the items by menutype.
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__menu_types'))
->where($db->quoteName('menutype') . ' <> ' . $db->quote(''))
->order(
[
$db->quoteName('title'),
$db->quoteName('menutype'),
]
);
if ($hasClientId) {
$query->where($db->quoteName('client_id') . ' = :clientId')
->bind(':clientId', $clientId, ParameterType::INTEGER);
}
try {
$db->setQuery($query);
$menuTypes = $db->loadObjectList();
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
return false;
}
// Create a reverse lookup and aggregate the links.
$rlu = [];
foreach ($menuTypes as &$type) {
$rlu[$type->menutype] = & $type;
$type->links = [];
}
// Loop through the list of menu links.
foreach ($links as &$link) {
if (isset($rlu[$link->menutype])) {
$rlu[$link->menutype]->links[] = & $link;
// Cleanup garbage.
unset($link->menutype);
}
}
return $menuTypes;
}
return $links;
}
/**
* Get the associations
*
* @param integer $pk Menu item id
*
* @return array
*
* @since 3.0
*/
public static function getAssociations($pk)
{
$langAssociations = Associations::getAssociations('com_menus', '#__menu', 'com_menus.item', $pk, 'id', '', '');
$associations = [];
foreach ($langAssociations as $langAssociation) {
$associations[$langAssociation->language] = $langAssociation->id;
}
return $associations;
}
/**
* Load the menu items from database for the given menutype
*
* @param string $menutype The selected menu type
* @param boolean $enabledOnly Whether to load only enabled/published menu items.
* @param int[] $exclude The menu items to exclude from the list
*
* @return AdministratorMenuItem A root node with the menu items as children
*
* @since 4.0.0
*/
public static function getMenuItems($menutype, $enabledOnly = false, $exclude = [])
{
$root = new AdministratorMenuItem();
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true);
// Prepare the query.
$query->select($db->quoteName('m') . '.*')
->from($db->quoteName('#__menu', 'm'))
->where(
[
$db->quoteName('m.menutype') . ' = :menutype',
$db->quoteName('m.client_id') . ' = 1',
$db->quoteName('m.id') . ' > 1',
]
)
->bind(':menutype', $menutype);
if ($enabledOnly) {
$query->where($db->quoteName('m.published') . ' = 1');
}
// Filter on the enabled states.
$query->select($db->quoteName('e.element'))
->join('LEFT', $db->quoteName('#__extensions', 'e'), $db->quoteName('m.component_id') . ' = ' . $db->quoteName('e.extension_id'))
->extendWhere(
'AND',
[
$db->quoteName('e.enabled') . ' = 1',
$db->quoteName('e.enabled') . ' IS NULL',
],
'OR'
);
if (\count($exclude)) {
$exId = array_map('intval', array_filter($exclude, 'is_numeric'));
$exEl = array_filter($exclude, 'is_string');
if ($exId) {
$query->whereNotIn($db->quoteName('m.id'), $exId)
->whereNotIn($db->quoteName('m.parent_id'), $exId);
}
if ($exEl) {
$query->whereNotIn($db->quoteName('e.element'), $exEl, ParameterType::STRING);
}
}
// Order by lft.
$query->order($db->quoteName('m.lft'));
try {
$menuItems = [];
$iterator = $db->setQuery($query)->getIterator();
foreach ($iterator as $item) {
$menuItems[$item->id] = new AdministratorMenuItem((array) $item);
}
unset($iterator);
foreach ($menuItems as $menuitem) {
// Resolve the alias item to get the original item
if ($menuitem->type == 'alias') {
static::resolveAlias($menuitem);
}
if ($menuitem->link = \in_array($menuitem->type, ['separator', 'heading', 'container']) ? '#' : trim($menuitem->link)) {
$menuitem->submenu = [];
$menuitem->class = $menuitem->img ?? '';
$menuitem->scope = $menuitem->scope ?? null;
$menuitem->target = $menuitem->browserNav ? '_blank' : '';
}
$menuitem->ajaxbadge = $menuitem->getParams()->get('ajax-badge');
$menuitem->dashboard = $menuitem->getParams()->get('dashboard');
if ($menuitem->parent_id > 1) {
if (isset($menuItems[$menuitem->parent_id])) {
$menuItems[$menuitem->parent_id]->addChild($menuitem);
}
} else {
$root->addChild($menuitem);
}
}
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
}
return $root;
}
/**
* Method to install a preset menu into database and link them to the given menutype
*
* @param string $preset The preset name
* @param string $menutype The target menutype
*
* @return void
*
* @throws \Exception
*
* @since 4.0.0
*/
public static function installPreset($preset, $menutype)
{
$root = static::loadPreset($preset, false);
if (\count($root->getChildren()) == 0) {
throw new \Exception(Text::_('COM_MENUS_PRESET_LOAD_FAILED'));
}
static::installPresetItems($root, $menutype);
}
/**
* Method to install a preset menu item into database and link it to the given menutype
*
* @param AdministratorMenuItem $node The parent node of the items to process
* @param string $menutype The target menutype
*
* @return void
*
* @throws \Exception
*
* @since 4.0.0
*/
protected static function installPresetItems($node, $menutype)
{
$db = Factory::getDbo();
$query = $db->getQuery(true);
$items = $node->getChildren();
static $components = [];
if (!$components) {
$query->select(
[
$db->quoteName('extension_id'),
$db->quoteName('element'),
]
)
->from($db->quoteName('#__extensions'))
->where($db->quoteName('type') . ' = ' . $db->quote('component'));
$components = $db->setQuery($query)->loadObjectList();
$components = array_column((array) $components, 'element', 'extension_id');
}
$dispatcher = Factory::getApplication()->getDispatcher();
$items = $dispatcher->dispatch('onPreprocessMenuItems', new PreprocessMenuItemsEvent('onPreprocessMenuItems', [
'context' => 'com_menus.administrator.import',
'subject' => &$items, // @todo: Remove reference in Joomla 6, see PreprocessMenuItemsEvent::__constructor()
'params' => null,
'enabled' => true,
]))->getArgument('subject', $items);
foreach ($items as $item) {
/** @var \Joomla\CMS\Table\Menu $table */
$table = Table::getInstance('Menu');
$item->alias = $menutype . '-' . $item->title;
// Temporarily set unicodeslugs if a menu item has an unicode alias
$unicode = Factory::getApplication()->set('unicodeslugs', 1);
$item->alias = ApplicationHelper::stringURLSafe($item->alias);
Factory::getApplication()->set('unicodeslugs', $unicode);
if ($item->type == 'separator') {
// Do not reuse a separator
$item->title = $item->title ?: '-';
$item->alias = microtime(true);
} elseif ($item->type == 'heading' || $item->type == 'container') {
// Try to match an existing record to have minimum collision for a heading
$keys = [
'menutype' => $menutype,
'type' => $item->type,
'title' => $item->title,
'parent_id' => (int) $item->getParent()->id,
'client_id' => 1,
];
$table->load($keys);
} elseif ($item->type == 'url' || $item->type == 'component') {
if (substr($item->link, 0, 8) === 'special:') {
$special = substr($item->link, 8);
if ($special === 'language-forum') {
$item->link = 'index.php?option=com_admin&amp;view=help&amp;layout=langforum';
} elseif ($special === 'custom-forum') {
$item->link = '';
}
}
// Try to match an existing record to have minimum collision for a link
$keys = [
'menutype' => $menutype,
'type' => $item->type,
'link' => $item->link,
'parent_id' => (int) $item->getParent()->id,
'client_id' => 1,
];
$table->load($keys);
}
// Translate "hideitems" param value from "element" into "menu-item-id"
if ($item->type == 'container' && \count($hideitems = (array) $item->getParams()->get('hideitems'))) {
foreach ($hideitems as &$hel) {
if (!is_numeric($hel)) {
$hel = array_search($hel, $components);
}
}
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__menu'))
->whereIn($db->quoteName('component_id'), $hideitems);
$hideitems = $db->setQuery($query)->loadColumn();
$item->getParams()->set('hideitems', $hideitems);
}
$record = [
'menutype' => $menutype,
'title' => $item->title,
'alias' => $item->alias,
'type' => $item->type,
'link' => $item->link,
'browserNav' => $item->browserNav,
'img' => $item->class,
'access' => $item->access,
'component_id' => array_search($item->element, $components) ?: 0,
'parent_id' => (int) $item->getParent()->id,
'client_id' => 1,
'published' => 1,
'language' => '*',
'home' => 0,
'params' => (string) $item->getParams(),
];
if (!$table->bind($record)) {
throw new \Exception($table->getError());
}
$table->setLocation($item->getParent()->id, 'last-child');
if (!$table->check()) {
throw new \Exception($table->getError());
}
if (!$table->store()) {
throw new \Exception($table->getError());
}
$item->id = $table->get('id');
if ($item->hasChildren()) {
static::installPresetItems($item, $menutype);
}
}
}
/**
* Add a custom preset externally via plugin or any other means.
* WARNING: Presets with same name will replace previously added preset *except* Joomla's default preset (joomla)
*
* @param string $name The unique identifier for the preset.
* @param string $title The display label for the preset.
* @param string $path The path to the preset file.
* @param bool $replace Whether to replace the preset with the same name if any (except 'joomla').
*
* @return void
*
* @since 4.0.0
*/
public static function addPreset($name, $title, $path, $replace = true)
{
if (static::$presets === null) {
static::getPresets();
}
if ($name == 'joomla') {
$replace = false;
}
if (($replace || !\array_key_exists($name, static::$presets)) && is_file($path)) {
$preset = new \stdClass();
$preset->name = $name;
$preset->title = $title;
$preset->path = $path;
static::$presets[$name] = $preset;
}
}
/**
* Get a list of available presets.
*
* @return \stdClass[]
*
* @since 4.0.0
*/
public static function getPresets()
{
if (static::$presets === null) {
// Important: 'null' will cause infinite recursion.
static::$presets = [];
$components = ComponentHelper::getComponents();
$lang = Factory::getApplication()->getLanguage();
foreach ($components as $component) {
if (!$component->enabled) {
continue;
}
$folder = JPATH_ADMINISTRATOR . '/components/' . $component->option . '/presets/';
if (!Folder::exists($folder)) {
continue;
}
$lang->load($component->option . '.sys', JPATH_ADMINISTRATOR)
|| $lang->load($component->option . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component->option);
$presets = Folder::files($folder, '.xml');
foreach ($presets as $preset) {
$name = File::stripExt($preset);
$title = strtoupper($component->option . '_MENUS_PRESET_' . $name);
static::addPreset($name, $title, $folder . $preset);
}
}
// Load from template folder automatically
$app = Factory::getApplication();
$tpl = JPATH_THEMES . '/' . $app->getTemplate() . '/html/com_menus/presets';
if (is_dir($tpl)) {
$files = Folder::files($tpl, '\.xml$');
foreach ($files as $file) {
$name = substr($file, 0, -4);
$title = str_replace('-', ' ', $name);
static::addPreset(strtolower($name), ucwords($title), $tpl . '/' . $file);
}
}
}
return static::$presets;
}
/**
* Load the menu items from a preset file into a hierarchical list of objects
*
* @param string $name The preset name
* @param bool $fallback Fallback to default (joomla) preset if the specified one could not be loaded?
* @param AdministratorMenuItem $parent Root node of the menu
*
* @return AdministratorMenuItem
*
* @since 4.0.0
*/
public static function loadPreset($name, $fallback = true, $parent = null)
{
$presets = static::getPresets();
if (!$parent) {
$parent = new AdministratorMenuItem();
}
if (isset($presets[$name]) && ($xml = simplexml_load_file($presets[$name]->path, null, LIBXML_NOCDATA)) && $xml instanceof \SimpleXMLElement) {
static::loadXml($xml, $parent);
} elseif ($fallback && isset($presets['default'])) {
if (($xml = simplexml_load_file($presets['default']->path, null, LIBXML_NOCDATA)) && $xml instanceof \SimpleXMLElement) {
static::loadXml($xml, $parent);
}
}
return $parent;
}
/**
* Method to resolve the menu item alias type menu item
*
* @param AdministratorMenuItem &$item The alias object
*
* @return void
*
* @since 4.0.0
*/
public static function resolveAlias(&$item)
{
$obj = $item;
while ($obj->type == 'alias') {
$aliasTo = (int) $obj->getParams()->get('aliasoptions');
$db = Factory::getDbo();
$query = $db->getQuery(true);
$query->select(
[
$db->quoteName('a.id'),
$db->quoteName('a.link'),
$db->quoteName('a.type'),
$db->quoteName('e.element'),
]
)
->from($db->quoteName('#__menu', 'a'))
->join('LEFT', $db->quoteName('#__extensions', 'e'), $db->quoteName('e.extension_id') . ' = ' . $db->quoteName('a.component_id'))
->where($db->quoteName('a.id') . ' = :aliasTo')
->bind(':aliasTo', $aliasTo, ParameterType::INTEGER);
try {
$obj = new AdministratorMenuItem($db->setQuery($query)->loadAssoc());
if (!$obj) {
$item->link = '';
return;
}
} catch (\Exception $e) {
$item->link = '';
return;
}
}
$item->id = $obj->id;
$item->link = $obj->link;
$item->type = $obj->type;
$item->element = $obj->element;
}
/**
* Parse the flat list of menu items and prepare the hierarchy of them using parent-child relationship.
*
* @param AdministratorMenuItem $item Menu item to preprocess
*
* @return void
*
* @since 4.0.0
*/
public static function preprocess($item)
{
// Resolve the alias item to get the original item
if ($item->type == 'alias') {
static::resolveAlias($item);
}
if ($item->link = \in_array($item->type, ['separator', 'heading', 'container']) ? '#' : trim($item->link)) {
$item->class = $item->img ?? '';
$item->scope = $item->scope ?? null;
$item->target = $item->browserNav ? '_blank' : '';
}
}
/**
* Load a menu tree from an XML file
*
* @param \SimpleXMLElement[] $elements The xml menuitem nodes
* @param AdministratorMenuItem $parent The menu hierarchy list to be populated
* @param string[] $replace The substring replacements for iterator type items
*
* @return void
*
* @since 4.0.0
*/
protected static function loadXml($elements, $parent, $replace = [])
{
foreach ($elements as $element) {
if ($element->getName() != 'menuitem') {
continue;
}
$select = (string) $element['sql_select'];
$from = (string) $element['sql_from'];
/**
* Following is a repeatable group based on simple database query. This requires sql_* attributes (sql_select and sql_from are required)
* The values can be used like - "{sql:columnName}" in any attribute of repeated elements.
* The repeated elements are place inside this xml node but they will be populated in the same level in the rendered menu
*/
if ($select && $from) {
$hidden = $element['hidden'] == 'true';
$where = (string) $element['sql_where'];
$order = (string) $element['sql_order'];
$group = (string) $element['sql_group'];
$lJoin = (string) $element['sql_leftjoin'];
$iJoin = (string) $element['sql_innerjoin'];
$db = Factory::getDbo();
$query = $db->getQuery(true);
$query->select($select)->from($from);
if ($where) {
$query->where($where);
}
if ($order) {
$query->order($order);
}
if ($group) {
$query->group($group);
}
if ($lJoin) {
$query->join('LEFT', $lJoin);
}
if ($iJoin) {
$query->join('INNER', $iJoin);
}
$results = $db->setQuery($query)->loadObjectList();
// Skip the entire group if no items to iterate over.
if ($results) {
// Show the repeatable group heading node only if not set as hidden.
if (!$hidden) {
$child = static::parseXmlNode($element, $replace);
$parent->addChild($child);
}
// Iterate over the matching records, items goes in the same level (not $item->submenu) as this node.
if ('self' == (string) $element['sql_target']) {
foreach ($results as $result) {
static::loadXml($element->menuitem, $child, $result);
}
} else {
foreach ($results as $result) {
static::loadXml($element->menuitem, $parent, $result);
}
}
}
} else {
$item = static::parseXmlNode($element, $replace);
// Process the child nodes
static::loadXml($element->menuitem, $item, $replace);
$parent->addChild($item);
}
}
}
/**
* Create a menu item node from an xml element
*
* @param \SimpleXMLElement $node A menuitem element from preset xml
* @param string[] $replace The values to substitute in the title, link and element texts
*
* @return \stdClass
*
* @since 4.0.0
*/
protected static function parseXmlNode($node, $replace = [])
{
$item = new AdministratorMenuItem();
$item->id = null;
$item->type = (string) $node['type'];
$item->title = (string) $node['title'];
$item->alias = (string) $node['alias'];
$item->link = (string) $node['link'];
$item->target = (string) $node['target'];
$item->element = (string) $node['element'];
$item->class = (string) $node['class'];
$item->icon = (string) $node['icon'];
$item->access = (int) $node['access'];
$item->scope = (string) $node['scope'] ?: 'default';
$item->ajaxbadge = (string) $node['ajax-badge'];
$item->dashboard = (string) $node['dashboard'];
$params = new Registry(trim($node->params));
$params->set('menu-permission', (string) $node['permission']);
if ($item->type == 'separator' && trim($item->title, '- ')) {
$params->set('text_separator', 1);
}
if ($item->type == 'heading' || $item->type == 'container') {
$item->link = '#';
}
if ((string) $node['quicktask']) {
$params->set('menu-quicktask', (string) $node['quicktask']);
$params->set('menu-quicktask-title', (string) $node['quicktask-title']);
$params->set('menu-quicktask-icon', (string) $node['quicktask-icon']);
$params->set('menu-quicktask-permission', (string) $node['quicktask-permission']);
}
// Translate attributes for iterator values
foreach ($replace as $var => $val) {
$item->title = str_replace("{sql:$var}", $val, $item->title);
$item->element = str_replace("{sql:$var}", $val, $item->element);
$item->link = str_replace("{sql:$var}", $val, $item->link);
$item->class = str_replace("{sql:$var}", $val, $item->class);
$item->icon = str_replace("{sql:$var}", $val, $item->icon);
$params->set('menu-quicktask', str_replace("{sql:$var}", $val, $params->get('menu-quicktask', '')));
}
$item->setParams($params);
return $item;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,598 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Model;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu Item List Model for Menus.
*
* @since 1.6
*/
class ItemsModel extends ListModel
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
* @param MVCFactoryInterface $factory The factory.
*
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
* @since 3.2
*/
public function __construct($config = [], MVCFactoryInterface $factory = null)
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'id', 'a.id',
'menutype', 'a.menutype', 'menutype_title',
'title', 'a.title',
'alias', 'a.alias',
'published', 'a.published',
'access', 'a.access', 'access_level',
'language', 'a.language',
'checked_out', 'a.checked_out',
'checked_out_time', 'a.checked_out_time',
'lft', 'a.lft',
'rgt', 'a.rgt',
'level', 'a.level',
'path', 'a.path',
'client_id', 'a.client_id',
'home', 'a.home',
'parent_id', 'a.parent_id',
'publish_up', 'a.publish_up',
'publish_down', 'a.publish_down',
'e.element', 'componentName',
'a.ordering',
];
if (Associations::isEnabled()) {
$config['filter_fields'][] = 'association';
}
}
parent::__construct($config, $factory);
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
*
* @since 1.6
*/
protected function populateState($ordering = 'a.lft', $direction = 'asc')
{
$app = Factory::getApplication();
$forcedLanguage = $app->getInput()->get('forcedLanguage', '', 'cmd');
// Adjust the context to support modal layouts.
if ($layout = $app->getInput()->get('layout')) {
$this->context .= '.' . $layout;
}
// Adjust the context to support forced languages.
if ($forcedLanguage) {
$this->context .= '.' . $forcedLanguage;
}
$search = $this->getUserStateFromRequest($this->context . '.search', 'filter_search');
$this->setState('filter.search', $search);
$published = $this->getUserStateFromRequest($this->context . '.published', 'filter_published', '');
$this->setState('filter.published', $published);
$access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access');
$this->setState('filter.access', $access);
$parentId = $this->getUserStateFromRequest($this->context . '.filter.parent_id', 'filter_parent_id');
$this->setState('filter.parent_id', $parentId);
$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->getInput()->getInt('client_id', $currentClientId);
// Load mod_menu.ini file when client is administrator
if ($clientId == 1) {
Factory::getLanguage()->load('mod_menu', JPATH_ADMINISTRATOR);
}
$currentMenuType = $app->getUserState($this->context . '.menutype', '');
$menuType = $app->getInput()->getString('menutype', $currentMenuType);
// If client_id changed clear menutype and reset pagination
if ($clientId != $currentClientId) {
$menuType = '';
$app->getInput()->set('limitstart', 0);
$app->getInput()->set('menutype', '');
}
// If menutype changed reset pagination.
if ($menuType != $currentMenuType) {
$app->getInput()->set('limitstart', 0);
}
if (!$menuType) {
$app->setUserState($this->context . '.menutype', '');
$this->setState('menutypetitle', '');
$this->setState('menutypeid', '');
} elseif ($menuType == 'main') {
// Special menu types, if selected explicitly, will be allowed as a filter
// Adjust client_id to match the menutype. This is safe as client_id was not changed in this request.
$app->getInput()->set('client_id', 1);
$app->setUserState($this->context . '.menutype', $menuType);
$this->setState('menutypetitle', ucfirst($menuType));
$this->setState('menutypeid', -1);
} elseif ($cMenu = $this->getMenu($menuType, true)) {
// Get the menutype object with appropriate checks.
// Adjust client_id to match the menutype. This is safe as client_id was not changed in this request.
$app->getInput()->set('client_id', $cMenu->client_id);
$app->setUserState($this->context . '.menutype', $menuType);
$this->setState('menutypetitle', $cMenu->title);
$this->setState('menutypeid', $cMenu->id);
} else {
// This menutype does not exist, leave client id unchanged but reset menutype and pagination
$menuType = '';
$app->getInput()->set('limitstart', 0);
$app->getInput()->set('menutype', $menuType);
$app->setUserState($this->context . '.menutype', $menuType);
$this->setState('menutypetitle', '');
$this->setState('menutypeid', '');
}
// Client id filter
$clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int');
$this->setState('filter.client_id', $clientId);
// Use a different filter file when client is administrator
if ($clientId == 1) {
$this->filterFormName = 'filter_itemsadmin';
}
$this->setState('filter.menutype', $menuType);
$language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', '');
$this->setState('filter.language', $language);
// Component parameters.
$params = ComponentHelper::getParams('com_menus');
$this->setState('params', $params);
// List state information.
parent::populateState($ordering, $direction);
// Force a language.
if (!empty($forcedLanguage)) {
$this->setState('filter.language', $forcedLanguage);
}
}
/**
* Method to get a store id based on model configuration state.
*
* This is necessary because the model is used by the component and
* different modules that might need different sets of data or different
* ordering requirements.
*
* @param string $id A prefix for the store id.
*
* @return string A store id.
*
* @since 1.6
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('filter.access');
$id .= ':' . $this->getState('filter.published');
$id .= ':' . $this->getState('filter.language');
$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);
}
/**
* Builds an SQL query to load the list data.
*
* @return \Joomla\Database\DatabaseQuery A query object.
*
* @since 1.6
*/
protected function getListQuery()
{
// Create a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true);
$user = $this->getCurrentUser();
$clientId = (int) $this->getState('filter.client_id');
// Select all fields from the table.
$query->select(
// We can't quote state values because they could contain expressions.
$this->getState(
'list.select',
[
$db->quoteName('a.id'),
$db->quoteName('a.menutype'),
$db->quoteName('a.title'),
$db->quoteName('a.alias'),
$db->quoteName('a.note'),
$db->quoteName('a.path'),
$db->quoteName('a.link'),
$db->quoteName('a.type'),
$db->quoteName('a.parent_id'),
$db->quoteName('a.level'),
$db->quoteName('a.component_id'),
$db->quoteName('a.checked_out'),
$db->quoteName('a.checked_out_time'),
$db->quoteName('a.browserNav'),
$db->quoteName('a.access'),
$db->quoteName('a.img'),
$db->quoteName('a.template_style_id'),
$db->quoteName('a.params'),
$db->quoteName('a.lft'),
$db->quoteName('a.rgt'),
$db->quoteName('a.home'),
$db->quoteName('a.language'),
$db->quoteName('a.client_id'),
$db->quoteName('a.publish_up'),
$db->quoteName('a.publish_down'),
]
)
)
->select(
[
$db->quoteName('l.title', 'language_title'),
$db->quoteName('l.image', 'language_image'),
$db->quoteName('l.sef', 'language_sef'),
$db->quoteName('u.name', 'editor'),
$db->quoteName('c.element', 'componentname'),
$db->quoteName('ag.title', 'access_level'),
$db->quoteName('mt.id', 'menutype_id'),
$db->quoteName('mt.title', 'menutype_title'),
$db->quoteName('e.enabled'),
$db->quoteName('e.name'),
'CASE WHEN ' . $db->quoteName('a.type') . ' = ' . $db->quote('component')
. ' THEN ' . $db->quoteName('a.published') . ' +2 * (' . $db->quoteName('e.enabled') . ' -1)'
. ' ELSE ' . $db->quoteName('a.published') . ' END AS ' . $db->quoteName('published'),
]
)
->from($db->quoteName('#__menu', 'a'));
// Join over the language
$query->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language'));
// Join over the users.
$query->join('LEFT', $db->quoteName('#__users', 'u'), $db->quoteName('u.id') . ' = ' . $db->quoteName('a.checked_out'));
// Join over components
$query->join('LEFT', $db->quoteName('#__extensions', 'c'), $db->quoteName('c.extension_id') . ' = ' . $db->quoteName('a.component_id'));
// Join over the asset groups.
$query->join('LEFT', $db->quoteName('#__viewlevels', 'ag'), $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access'));
// Join over the menu types.
$query->join('LEFT', $db->quoteName('#__menu_types', 'mt'), $db->quoteName('mt.menutype') . ' = ' . $db->quoteName('a.menutype'));
// Join over the extensions
$query->join('LEFT', $db->quoteName('#__extensions', 'e'), $db->quoteName('e.extension_id') . ' = ' . $db->quoteName('a.component_id'));
// Join over the associations.
if (Associations::isEnabled()) {
$subQuery = $db->getQuery(true)
->select('COUNT(' . $db->quoteName('asso1.id') . ') > 1')
->from($db->quoteName('#__associations', 'asso1'))
->join('INNER', $db->quoteName('#__associations', 'asso2'), $db->quoteName('asso1.key') . ' = ' . $db->quoteName('asso2.key'))
->where(
[
$db->quoteName('asso1.id') . ' = ' . $db->quoteName('a.id'),
$db->quoteName('asso1.context') . ' = ' . $db->quote('com_menus.item'),
]
);
$query->select('(' . $subQuery . ') AS ' . $db->quoteName('association'));
}
// Exclude the root category.
$query->where(
[
$db->quoteName('a.id') . ' > 1',
$db->quoteName('a.client_id') . ' = :clientId',
]
)
->bind(':clientId', $clientId, ParameterType::INTEGER);
// Filter on the published state.
$published = $this->getState('filter.published');
if (is_numeric($published)) {
$published = (int) $published;
$query->where($db->quoteName('a.published') . ' = :published')
->bind(':published', $published, ParameterType::INTEGER);
} elseif ($published === '') {
$query->where($db->quoteName('a.published') . ' IN (0, 1)');
}
// Filter by search in title, alias or id
if ($search = trim($this->getState('filter.search', ''))) {
if (stripos($search, 'id:') === 0) {
$search = (int) substr($search, 3);
$query->where($db->quoteName('a.id') . ' = :search')
->bind(':search', $search, ParameterType::INTEGER);
} elseif (stripos($search, 'link:') === 0) {
if ($search = str_replace(' ', '%', trim(substr($search, 5)))) {
$query->where($db->quoteName('a.link') . ' LIKE :search')
->bind(':search', $search);
}
} else {
$search = '%' . str_replace(' ', '%', trim($search)) . '%';
$query->extendWhere(
'AND',
[
$db->quoteName('a.title') . ' LIKE :search1',
$db->quoteName('a.alias') . ' LIKE :search2',
$db->quoteName('a.note') . ' LIKE :search3',
],
'OR'
)
->bind([':search1', ':search2', ':search3'], $search);
}
}
// Filter the items over the parent id if set.
$parentId = (int) $this->getState('filter.parent_id');
$level = (int) $this->getState('filter.level');
if ($parentId) {
// Create a subquery for the sub-items list
$subQuery = $db->getQuery(true)
->select($db->quoteName('sub.id'))
->from($db->quoteName('#__menu', 'sub'))
->join(
'INNER',
$db->quoteName('#__menu', 'this'),
$db->quoteName('sub.lft') . ' > ' . $db->quoteName('this.lft')
. ' AND ' . $db->quoteName('sub.rgt') . ' < ' . $db->quoteName('this.rgt')
)
->where($db->quoteName('this.id') . ' = :parentId1');
if ($level) {
$subQuery->where($db->quoteName('sub.level') . ' <= ' . $db->quoteName('this.level') . ' + :level - 1');
$query->bind(':level', $level, ParameterType::INTEGER);
}
// Add the subquery to the main query
$query->extendWhere(
'AND',
[
$db->quoteName('a.parent_id') . ' = :parentId2',
$db->quoteName('a.parent_id') . ' IN (' . (string) $subQuery . ')',
],
'OR'
)
->bind([':parentId1', ':parentId2'], $parentId, ParameterType::INTEGER);
} elseif ($level) {
// Filter on the level.
$query->where($db->quoteName('a.level') . ' <= :level')
->bind(':level', $level, ParameterType::INTEGER);
}
// Filter the items over the menu id if set.
$menuType = $this->getState('filter.menutype');
// A value "" means all
if ($menuType == '') {
// Load all menu types we have manage access
$query2 = $db->getQuery(true)
->select(
[
$db->quoteName('id'),
$db->quoteName('menutype'),
]
)
->from($db->quoteName('#__menu_types'))
->where($db->quoteName('client_id') . ' = :clientId')
->bind(':clientId', $clientId, ParameterType::INTEGER)
->order($db->quoteName('title'));
// Show protected items on explicit filter only
$query->where($db->quoteName('a.menutype') . ' != ' . $db->quote('main'));
$menuTypes = $db->setQuery($query2)->loadObjectList();
if ($menuTypes) {
$types = [];
foreach ($menuTypes as $type) {
if ($user->authorise('core.manage', 'com_menus.menu.' . (int) $type->id)) {
$types[] = $type->menutype;
}
}
if ($types) {
$query->whereIn($db->quoteName('a.menutype'), $types);
} else {
$query->where(0);
}
}
} elseif (\strlen($menuType)) {
// Default behavior => load all items from a specific menu
$query->where($db->quoteName('a.menutype') . ' = :menuType')
->bind(':menuType', $menuType);
} else {
// Empty menu type => error
$query->where('1 != 1');
}
// Filter on the access level.
if ($access = (int) $this->getState('filter.access')) {
$query->where($db->quoteName('a.access') . ' = :access')
->bind(':access', $access, ParameterType::INTEGER);
}
// Implement View Level Access
if (!$user->authorise('core.admin')) {
if ($groups = $user->getAuthorisedViewLevels()) {
$query->whereIn($db->quoteName('a.access'), $groups);
}
}
// Filter on the language.
if ($language = $this->getState('filter.language')) {
$query->where($db->quoteName('a.language') . ' = :language')
->bind(':language', $language);
}
// Filter on componentName
if ($componentName = $this->getState('filter.componentName')) {
$query->where($db->quoteName('e.element') . ' = :component')
->bind(':component', $componentName);
}
// Add the list ordering clause.
$query->order($db->escape($this->getState('list.ordering', 'a.lft')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
return $query;
}
/**
* Method to allow derived classes to preprocess the form.
*
* @param Form $form A Form 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(Form $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 boolean $check Flag whether to perform check against ACL as well as existence
*
* @return integer
*
* @since 3.7.0
*/
protected function getMenu($menuType, $check = false)
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select($db->quoteName('a') . '.*')
->from($db->quoteName('#__menu_types', 'a'))
->where($db->quoteName('menutype') . ' = :menuType')
->bind(':menuType', $menuType);
$cMenu = $db->setQuery($query)->loadObject();
if ($check) {
// Check if menu type exists.
if (!$cMenu) {
Log::add(Text::_('COM_MENUS_ERROR_MENUTYPE_NOT_FOUND'), Log::ERROR, 'jerror');
return false;
}
if (!$this->getCurrentUser()->authorise('core.manage', 'com_menus.menu.' . $cMenu->id)) {
// Check if menu type is valid against ACL.
Log::add(Text::_('JERROR_ALERTNOAUTHOR'), Log::ERROR, 'jerror');
return false;
}
}
return $cMenu;
}
/**
* Method to get an array of data items.
*
* @return mixed An array of data items on success, false on failure.
*
* @since 3.0.1
*/
public function getItems()
{
$store = $this->getStoreId();
if (!isset($this->cache[$store])) {
$items = parent::getItems();
$lang = Factory::getLanguage();
$client = $this->state->get('filter.client_id');
if ($items) {
foreach ($items as $item) {
if ($extension = $item->componentname) {
$lang->load("$extension.sys", JPATH_ADMINISTRATOR)
|| $lang->load("$extension.sys", JPATH_ADMINISTRATOR . '/components/' . $extension);
}
// Translate component name
if ($client === 1) {
$item->title = Text::_($item->title);
}
}
}
$this->cache[$store] = $items;
}
return $this->cache[$store];
}
}

View File

@ -0,0 +1,419 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Model;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Table\Table;
use Joomla\Registry\Registry;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu Item Model for Menus.
*
* @since 1.6
*/
class MenuModel extends AdminModel
{
/**
* The prefix to use with controller messages.
*
* @var string
* @since 1.6
*/
protected $text_prefix = 'COM_MENUS_MENU';
/**
* Model context string.
*
* @var string
*/
protected $_context = 'com_menus.menu';
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to delete the record. Defaults to the permission set in the component.
*
* @since 1.6
*/
protected function canDelete($record)
{
return $this->getCurrentUser()->authorise('core.delete', 'com_menus.menu.' . (int) $record->id);
}
/**
* Method to test whether the state of a record can be edited.
*
* @param object $record A record object.
*
* @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component.
*
* @since 1.6
*/
protected function canEditState($record)
{
return $this->getCurrentUser()->authorise('core.edit.state', 'com_menus.menu.' . (int) $record->id);
}
/**
* Returns a Table object, always creating it
*
* @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 Table A database object
*
* @since 1.6
*/
public function getTable($type = 'MenuType', $prefix = '\\Joomla\\CMS\\Table\\', $config = [])
{
return Table::getInstance($type, $prefix, $config);
}
/**
* Auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @return void
*
* @since 1.6
*/
protected function populateState()
{
$app = Factory::getApplication();
// Load the User state.
$id = $app->getInput()->getInt('id');
$this->setState('menu.id', $id);
// Load the parameters.
$params = ComponentHelper::getParams('com_menus');
$this->setState('params', $params);
// Load the clientId.
$clientId = $app->getUserStateFromRequest('com_menus.menus.client_id', 'client_id', 0, 'int');
$this->setState('client_id', $clientId);
}
/**
* Method to get a menu item.
*
* @param integer $itemId The id of the menu item to get.
*
* @return mixed Menu item data object on success, false on failure.
*
* @since 1.6
*/
public function &getItem($itemId = null)
{
$itemId = (!empty($itemId)) ? $itemId : (int) $this->getState('menu.id');
// Get a menu item row instance.
$table = $this->getTable();
// Attempt to load the row.
$return = $table->load($itemId);
// Check for a table object error.
if ($return === false && $table->getError()) {
$this->setError($table->getError());
return false;
}
$properties = $table->getProperties(1);
$value = ArrayHelper::toObject($properties, CMSObject::class);
return $value;
}
/**
* Method to get the menu item form.
*
* @param array $data Data for the form.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return Form|boolean A Form object on success, false on failure
*
* @since 1.6
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_menus.menu', 'menu', ['control' => 'jform', 'load_data' => $loadData]);
if (empty($form)) {
return false;
}
if (!$this->getState('client_id', 0)) {
$form->removeField('preset');
}
return $form;
}
/**
* Method to get the data that should be injected in the form.
*
* @return mixed The data for the form.
*
* @since 1.6
*/
protected function loadFormData()
{
// Check the session for previously entered form data.
$data = Factory::getApplication()->getUserState('com_menus.edit.menu.data', []);
if (empty($data)) {
$data = $this->getItem();
if (empty($data->id)) {
$data->client_id = $this->state->get('client_id', 0);
}
} else {
unset($data['preset']);
}
$this->preprocessData('com_menus.menu', $data);
return $data;
}
/**
* Method to validate the form data.
*
* @param Form $form The form to validate against.
* @param array $data The data to validate.
* @param string $group The name of the field group to validate.
*
* @return array|boolean Array of filtered data if valid, false otherwise.
*
* @see \Joomla\CMS\Form\FormRule
* @see \Joomla\CMS\Filter\InputFilter
* @since 3.9.23
*/
public function validate($form, $data, $group = null)
{
if (!$this->getCurrentUser()->authorise('core.admin', 'com_menus')) {
if (isset($data['rules'])) {
unset($data['rules']);
}
}
return parent::validate($form, $data, $group);
}
/**
* Method to save the form data.
*
* @param array $data The form data.
*
* @return boolean True on success.
*
* @since 1.6
*/
public function save($data)
{
$id = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('menu.id');
$isNew = true;
// Get a row instance.
$table = $this->getTable();
// Include the plugins for the save events.
PluginHelper::importPlugin('content');
// Load the row if saving an existing item.
if ($id > 0) {
$isNew = false;
$table->load($id);
}
// Bind the data.
if (!$table->bind($data)) {
$this->setError($table->getError());
return false;
}
// Check the data.
if (!$table->check()) {
$this->setError($table->getError());
return false;
}
// Trigger the before event.
$result = Factory::getApplication()->triggerEvent('onContentBeforeSave', [$this->_context, &$table, $isNew, $data]);
// Store the data.
if (\in_array(false, $result, true) || !$table->store()) {
$this->setError($table->getError());
return false;
}
// Trigger the after save event.
Factory::getApplication()->triggerEvent('onContentAfterSave', [$this->_context, &$table, $isNew]);
$this->setState('menu.id', $table->id);
// Clean the cache
$this->cleanCache();
return true;
}
/**
* Method to delete groups.
*
* @param array $itemIds An array of item ids.
*
* @return boolean Returns true on success, false on failure.
*
* @since 1.6
*/
public function delete(&$pks)
{
// Sanitize the ids.
$itemIds = ArrayHelper::toInteger((array) $pks);
// Get a group row instance.
$table = $this->getTable();
// Include the plugins for the delete events.
PluginHelper::importPlugin('content');
// Iterate the items to delete each one.
foreach ($itemIds as $itemId) {
if ($table->load($itemId)) {
// Trigger the before delete event.
$result = Factory::getApplication()->triggerEvent('onContentBeforeDelete', [$this->_context, $table]);
if (\in_array(false, $result, true) || !$table->delete($itemId)) {
$this->setError($table->getError());
return false;
}
// Trigger the after delete event.
Factory::getApplication()->triggerEvent('onContentAfterDelete', [$this->_context, $table]);
// @todo: Delete the menu associations - Menu items and Modules
}
}
// Clean the cache
$this->cleanCache();
return true;
}
/**
* Gets a list of all mod_mainmenu modules and collates them by menutype
*
* @return array
*
* @since 1.6
*/
public function &getModules()
{
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select(
[
$db->quoteName('a.id'),
$db->quoteName('a.title'),
$db->quoteName('a.params'),
$db->quoteName('a.position'),
$db->quoteName('ag.title', 'access_title'),
]
)
->from($db->quoteName('#__modules', 'a'))
->join('LEFT', $db->quoteName('#__viewlevels', 'ag'), $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access'))
->where($db->quoteName('a.module') . ' = ' . $db->quote('mod_menu'));
$db->setQuery($query);
$modules = $db->loadObjectList();
$result = [];
foreach ($modules as &$module) {
$params = new Registry($module->params);
$menuType = $params->get('menutype');
if (!isset($result[$menuType])) {
$result[$menuType] = [];
}
$result[$menuType][] = &$module;
}
return $result;
}
/**
* Returns the extension elements for the given items
*
* @param array $itemIds The item ids
*
* @return array
*
* @since 4.2.0
*/
public function getExtensionElementsForMenuItems(array $itemIds): array
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query
->select($db->quoteName('e.element'))
->from($db->quoteName('#__extensions', 'e'))
->join('INNER', $db->quoteName('#__menu', 'm'), $db->quoteName('m.component_id') . ' = ' . $db->quoteName('e.extension_id'))
->whereIn($db->quoteName('m.id'), ArrayHelper::toInteger($itemIds));
return $db->setQuery($query)->loadColumn();
}
/**
* Custom clean the cache
*
* @param string $group Cache group name.
* @param integer $clientId No longer used, will be removed without replacement
* @deprecated 4.3 will be removed in 6.0
*
* @return void
*
* @since 1.6
*/
protected function cleanCache($group = null, $clientId = 0)
{
parent::cleanCache('com_menus');
parent::cleanCache('com_modules');
parent::cleanCache('mod_menu');
}
}

View File

@ -0,0 +1,315 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Model;
use Joomla\CMS\Helper\ModuleHelper;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\DatabaseQuery;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu List Model for Menus.
*
* @since 1.6
*/
class MenusModel extends ListModel
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
* @param MVCFactoryInterface $factory The factory.
*
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
* @since 3.2
*/
public function __construct($config = [], MVCFactoryInterface $factory = null)
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'id', 'a.id',
'title', 'a.title',
'menutype', 'a.menutype',
'client_id', 'a.client_id',
'ordering', 'a.ordering',
];
}
parent::__construct($config, $factory);
}
/**
* Overrides the getItems method to attach additional metrics to the list.
*
* @return mixed An array of data items on success, false on failure.
*
* @since 1.6.1
*/
public function getItems()
{
// Get a storage key.
$store = $this->getStoreId('getItems');
// Try to load the data from internal storage.
if (!empty($this->cache[$store])) {
return $this->cache[$store];
}
// Load the list items.
$items = parent::getItems();
// If empty or an error, just return.
if (empty($items)) {
return [];
}
// Getting the following metric by joins is WAY TOO SLOW.
// Faster to do three queries for very large menu trees.
// Get the menu types of menus in the list.
$db = $this->getDatabase();
$menuTypes = array_column((array) $items, 'menutype');
$query = $db->getQuery(true)
->select(
[
$db->quoteName('m.menutype'),
'COUNT(DISTINCT ' . $db->quoteName('m.id') . ') AS ' . $db->quoteName('count_published'),
]
)
->from($db->quoteName('#__menu', 'm'))
->where($db->quoteName('m.published') . ' = :published')
->whereIn($db->quoteName('m.menutype'), $menuTypes, ParameterType::STRING)
->group($db->quoteName('m.menutype'))
->bind(':published', $published, ParameterType::INTEGER);
$db->setQuery($query);
// Get the published menu counts.
try {
$published = 1;
$countPublished = $db->loadAssocList('menutype', 'count_published');
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());
return false;
}
// Get the unpublished menu counts.
try {
$published = 0;
$countUnpublished = $db->loadAssocList('menutype', 'count_published');
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());
return false;
}
// Get the trashed menu counts.
try {
$published = -2;
$countTrashed = $db->loadAssocList('menutype', 'count_published');
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());
return false;
}
// Inject the values back into the array.
foreach ($items as $item) {
$item->count_published = $countPublished[$item->menutype] ?? 0;
$item->count_unpublished = $countUnpublished[$item->menutype] ?? 0;
$item->count_trashed = $countTrashed[$item->menutype] ?? 0;
}
// Add the items to the internal cache.
$this->cache[$store] = $items;
return $this->cache[$store];
}
/**
* Method to build an SQL query to load the list data.
*
* @return DatabaseQuery An SQL query
*
* @since 1.6
*/
protected function getListQuery()
{
// Create a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true);
$clientId = (int) $this->getState('client_id');
// Select all fields from the table.
$query->select(
$this->getState(
'list.select',
[
$db->quoteName('a.id'),
$db->quoteName('a.menutype'),
$db->quoteName('a.title'),
$db->quoteName('a.description'),
$db->quoteName('a.client_id'),
$db->quoteName('a.ordering'),
]
)
)
->from($db->quoteName('#__menu_types', 'a'))
->where(
[
$db->quoteName('a.id') . ' > 0',
$db->quoteName('a.client_id') . ' = :clientId',
]
)
->bind(':clientId', $clientId, ParameterType::INTEGER);
// Filter by search in title or menutype
if ($search = trim($this->getState('filter.search', ''))) {
$search = '%' . str_replace(' ', '%', $search) . '%';
$query->extendWhere(
'AND',
[
$db->quoteName('a.title') . ' LIKE :search1' ,
$db->quoteName('a.menutype') . ' LIKE :search2',
],
'OR'
)
->bind([':search1', ':search2'], $search);
}
// Add the list ordering clause.
$query->order($db->escape($this->getState('list.ordering', 'a.id')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
return $query;
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
*
* @since 1.6
*/
protected function populateState($ordering = 'a.ordering', $direction = 'asc')
{
$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);
}
/**
* Gets the extension id of the core mod_menu module.
*
* @return integer
*
* @since 2.5
*/
public function getModMenuId()
{
$clientId = (int) $this->getState('client_id');
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('e.extension_id'))
->from($db->quoteName('#__extensions', 'e'))
->where(
[
$db->quoteName('e.type') . ' = ' . $db->quote('module'),
$db->quoteName('e.element') . ' = ' . $db->quote('mod_menu'),
$db->quoteName('e.client_id') . ' = :clientId',
]
)
->bind(':clientId', $clientId, ParameterType::INTEGER);
$db->setQuery($query);
return $db->loadResult();
}
/**
* Gets a list of all mod_mainmenu modules and collates them by menutype
*
* @return array
*
* @since 1.6
*/
public function &getModules()
{
$model = $this->bootComponent('com_menus')
->getMVCFactory()->createModel('Menu', 'Administrator', ['ignore_request' => true]);
$result = $model->getModules();
return $result;
}
/**
* Returns the missing module languages.
*
* @return array
*
* @since 4.2.0
*/
public function getMissingModuleLanguages(): array
{
// Check custom administrator menu modules
if (!ModuleHelper::isAdminMultilang()) {
return [];
}
$languages = LanguageHelper::getInstalledLanguages(1, true);
$langCodes = [];
foreach ($languages as $language) {
$languageName = $language->metadata['nativeName'] ?? $language->metadata['name'];
$langCodes[$language->metadata['tag']] = $languageName;
}
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select($db->quoteName('m.language'))
->from($db->quoteName('#__modules', 'm'))
->where(
[
$db->quoteName('m.module') . ' = ' . $db->quote('mod_menu'),
$db->quoteName('m.published') . ' = 1',
$db->quoteName('m.client_id') . ' = 1',
]
)
->group($db->quoteName('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))) {
return array_intersect_key($langCodes, array_flip($langMissing));
}
return [];
}
}

View File

@ -0,0 +1,584 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Model;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Event\Menu\AfterGetMenuTypeOptionsEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Object\CMSObject;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu Item Types Model for Menus.
*
* @since 1.6
*/
class MenutypesModel extends BaseDatabaseModel
{
/**
* A reverse lookup of the base link URL to Title
*
* @var array
*/
protected $rlu = [];
/**
* 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 3.0.1
*/
protected function populateState()
{
parent::populateState();
$clientId = Factory::getApplication()->getInput()->get('client_id', 0);
$this->state->set('client_id', $clientId);
}
/**
* Method to get the reverse lookup of the base link URL to Title
*
* @return array Array of reverse lookup of the base link URL to Title
*
* @since 1.6
*/
public function getReverseLookup()
{
if (empty($this->rlu)) {
$this->getTypeOptions();
}
return $this->rlu;
}
/**
* Method to get the available menu item type options.
*
* @return array Array of groups with menu item types.
*
* @since 1.6
*/
public function getTypeOptions()
{
$lang = Factory::getLanguage();
$list = [];
// Get the list of components.
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select(
[
$db->quoteName('name'),
$db->quoteName('element', 'option'),
]
)
->from($db->quoteName('#__extensions'))
->where(
[
$db->quoteName('type') . ' = ' . $db->quote('component'),
$db->quoteName('enabled') . ' = 1',
]
)
->order($db->quoteName('name') . ' ASC');
$db->setQuery($query);
$components = $db->loadObjectList();
foreach ($components as $component) {
$options = $this->getTypeOptionsByComponent($component->option);
if ($options) {
$list[$component->name] = $options;
// Create the reverse lookup for link-to-name.
foreach ($options as $option) {
if (isset($option->request)) {
$this->addReverseLookupUrl($option);
if (isset($option->request['option'])) {
$componentLanguageFolder = JPATH_ADMINISTRATOR . '/components/' . $option->request['option'];
$lang->load($option->request['option'] . '.sys', JPATH_ADMINISTRATOR)
|| $lang->load($option->request['option'] . '.sys', $componentLanguageFolder);
}
}
}
}
}
// Allow a system plugin to insert dynamic menu types to the list shown in menus:
return $this->getDispatcher()->dispatch('onAfterGetMenuTypeOptions', new AfterGetMenuTypeOptionsEvent('onAfterGetMenuTypeOptions', [
'items' => &$list, // @todo: Remove reference in Joomla 6, see AfterGetMenuTypeOptionsEvent::__constructor()
'subject' => $this,
]))->getArgument('items', $list);
}
/**
* Method to create the reverse lookup for link-to-name.
* (can be used from onAfterGetMenuTypeOptions handlers)
*
* @param CMSObject $option Object with request array or string and title public variables
*
* @return void
*
* @since 3.1
*/
public function addReverseLookupUrl($option)
{
$this->rlu[MenusHelper::getLinkKey($option->request)] = $option->get('title');
}
/**
* Get menu types by component.
*
* @param string $component Component URL option.
*
* @return array
*
* @since 1.6
*/
protected function getTypeOptionsByComponent($component)
{
$options = [];
$client = ApplicationHelper::getClientInfo($this->getState('client_id'));
$mainXML = $client->path . '/components/' . $component . '/metadata.xml';
if (is_file($mainXML)) {
$options = $this->getTypeOptionsFromXml($mainXML, $component);
}
if (empty($options)) {
$options = $this->getTypeOptionsFromMvc($component);
}
if ($client->id == 1 && empty($options)) {
$options = $this->getTypeOptionsFromManifest($component);
}
return $options;
}
/**
* Get the menu types from an XML file
*
* @param string $file File path
* @param string $component Component option as in URL
*
* @return array|boolean
*
* @since 1.6
*/
protected function getTypeOptionsFromXml($file, $component)
{
$options = [];
// Attempt to load the xml file.
if (!$xml = simplexml_load_file($file)) {
return false;
}
// Look for the first menu node off of the root node.
if (!$menu = $xml->xpath('menu[1]')) {
return false;
}
$menu = $menu[0];
// If we have no options to parse, just add the base component to the list of options.
if (!empty($menu['options']) && $menu['options'] == 'none') {
// Create the menu option for the component.
$o = new CMSObject();
$o->title = (string) $menu['name'];
$o->description = (string) $menu['msg'];
$o->request = ['option' => $component];
$options[] = $o;
return $options;
}
// Look for the first options node off of the menu node.
if (!$optionsNode = $menu->xpath('options[1]')) {
return false;
}
$optionsNode = $optionsNode[0];
// Make sure the options node has children.
if (!$children = $optionsNode->children()) {
return false;
}
// Process each child as an option.
foreach ($children as $child) {
if ($child->getName() == 'option') {
// Create the menu option for the component.
$o = new CMSObject();
$o->title = (string) $child['name'];
$o->description = (string) $child['msg'];
$o->request = ['option' => $component, (string) $optionsNode['var'] => (string) $child['value']];
$options[] = $o;
} elseif ($child->getName() == 'default') {
// Create the menu option for the component.
$o = new CMSObject();
$o->title = (string) $child['name'];
$o->description = (string) $child['msg'];
$o->request = ['option' => $component];
$options[] = $o;
}
}
return $options;
}
/**
* Get menu types from MVC
*
* @param string $component Component option like in URLs
*
* @return array|boolean
*
* @since 1.6
*/
protected function getTypeOptionsFromMvc($component)
{
$options = [];
$views = [];
foreach ($this->getFolders($component) as $path) {
if (!is_dir($path)) {
continue;
}
$views = array_merge($views, Folder::folders($path, '.', false, true));
}
foreach ($views as $viewPath) {
$view = basename($viewPath);
// Ignore private views.
if (strpos($view, '_') !== 0) {
// Determine if a metadata file exists for the view.
$file = $viewPath . '/metadata.xml';
if (is_file($file)) {
// Attempt to load the xml file.
if ($xml = simplexml_load_file($file)) {
// Look for the first view node off of the root node.
if ($menu = $xml->xpath('view[1]')) {
$menu = $menu[0];
// If the view is hidden from the menu, discard it and move on to the next view.
if (!empty($menu['hidden']) && $menu['hidden'] == 'true') {
unset($xml);
continue;
}
// Do we have an options node or should we process layouts?
// Look for the first options node off of the menu node.
if ($optionsNode = $menu->xpath('options[1]')) {
$optionsNode = $optionsNode[0];
// Make sure the options node has children.
if ($children = $optionsNode->children()) {
// Process each child as an option.
foreach ($children as $child) {
if ($child->getName() == 'option') {
// Create the menu option for the component.
$o = new CMSObject();
$o->title = (string) $child['name'];
$o->description = (string) $child['msg'];
$o->request = ['option' => $component, 'view' => $view, (string) $optionsNode['var'] => (string) $child['value']];
$options[] = $o;
} elseif ($child->getName() == 'default') {
// Create the menu option for the component.
$o = new CMSObject();
$o->title = (string) $child['name'];
$o->description = (string) $child['msg'];
$o->request = ['option' => $component, 'view' => $view];
$options[] = $o;
}
}
}
} else {
$options = array_merge($options, (array) $this->getTypeOptionsFromLayouts($component, $view));
}
}
unset($xml);
}
} else {
$options = array_merge($options, (array) $this->getTypeOptionsFromLayouts($component, $view));
}
}
}
return $options;
}
/**
* Get menu types from Component manifest
*
* @param string $component Component option like in URLs
*
* @return array|boolean
*
* @since 3.7.0
*/
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 = [];
// 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'], ['true', 'hidden'])) {
return $options;
}
// Create the root menu option.
$ro = new \stdClass();
$ro->title = (string) trim($rootMenu);
$ro->description = '';
$ro->request = ['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 = [];
$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 CMSObject($o);
// Do not repeat the default view link (index.php?option=com_abc).
if (\count($o->request) == 1) {
$ro = null;
}
}
if ($ro) {
$options[] = new CMSObject($ro);
}
return $options;
}
/**
* Get the menu types from component layouts
*
* @param string $component Component option as in URLs
* @param string $view Name of the view
*
* @return array
*
* @since 1.6
*/
protected function getTypeOptionsFromLayouts($component, $view)
{
$options = [];
$layouts = [];
$layoutNames = [];
$lang = Factory::getLanguage();
$client = ApplicationHelper::getClientInfo($this->getState('client_id'));
// Get the views for this component.
foreach ($this->getFolders($component) as $folder) {
$path = $folder . '/' . $view . '/tmpl';
if (!is_dir($path)) {
$path = $folder . '/' . $view;
}
if (!is_dir($path)) {
continue;
}
$layouts = array_merge($layouts, Folder::files($path, '.xml$', false, true));
}
// Build list of standard layout names
foreach ($layouts as $layout) {
// Ignore private layouts.
if (strpos(basename($layout), '_') === false) {
// Get the layout name.
$layoutNames[] = basename($layout, '.xml');
}
}
// Get the template layouts
// @todo: This should only search one template -- the current template for this item (default of specified)
$folders = Folder::folders($client->path . '/templates', '', false, true);
// Array to hold association between template file names and templates
$templateName = [];
foreach ($folders as $folder) {
if (is_dir($folder . '/html/' . $component . '/' . $view)) {
$template = basename($folder);
$lang->load('tpl_' . $template . '.sys', $client->path)
|| $lang->load('tpl_' . $template . '.sys', $client->path . '/templates/' . $template);
$templateLayouts = Folder::files($folder . '/html/' . $component . '/' . $view, '.xml$', false, true);
foreach ($templateLayouts as $layout) {
// Get the layout name.
$templateLayoutName = basename($layout, '.xml');
// Add to the list only if it is not a standard layout
if (array_search($templateLayoutName, $layoutNames) === false) {
$layouts[] = $layout;
// Set template name array so we can get the right template for the layout
$templateName[$layout] = basename($folder);
}
}
}
}
// Process the found layouts.
foreach ($layouts as $layout) {
// Ignore private layouts.
if (strpos(basename($layout), '_') === false) {
$file = $layout;
// Get the layout name.
$layout = basename($layout, '.xml');
// Create the menu option for the layout.
$o = new CMSObject();
$o->title = ucfirst($layout);
$o->description = '';
$o->request = ['option' => $component, 'view' => $view];
// Only add the layout request argument if not the default layout.
if ($layout != 'default') {
// If the template is set, add in format template:layout so we save the template name
$o->request['layout'] = isset($templateName[$file]) ? $templateName[$file] . ':' . $layout : $layout;
}
// Load layout metadata if it exists.
if (is_file($file)) {
// Attempt to load the xml file.
if ($xml = simplexml_load_file($file)) {
// Look for the first view node off of the root node.
if ($menu = $xml->xpath('layout[1]')) {
$menu = $menu[0];
// If the view is hidden from the menu, discard it and move on to the next view.
if (!empty($menu['hidden']) && $menu['hidden'] == 'true') {
unset($xml);
unset($o);
continue;
}
// Populate the title and description if they exist.
if (!empty($menu['title'])) {
$o->title = trim((string) $menu['title']);
}
if (!empty($menu->message[0])) {
$o->description = trim((string) $menu->message[0]);
}
}
}
}
// Add the layout to the options array.
$options[] = $o;
}
}
return $options;
}
/**
* Get the folders with template files for the given component.
*
* @param string $component Component option as in URLs
*
* @return array
*
* @since 4.0.0
*/
private function getFolders($component)
{
$client = ApplicationHelper::getClientInfo($this->getState('client_id'));
if (!is_dir($client->path . '/components/' . $component)) {
return [];
}
$folders = Folder::folders($client->path . '/components/' . $component, '^view[s]?$', false, true);
$folders = array_merge($folders, Folder::folders($client->path . '/components/' . $component, '^tmpl?$', false, true));
if (!$folders) {
return [];
}
return $folders;
}
}

View File

@ -0,0 +1,132 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Service\HTML;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menus HTML helper class.
*
* @package Joomla.Administrator
* @subpackage com_menus
* @since 1.7
*/
class Menus
{
/**
* Generate the markup to display the item associations
*
* @param int $itemid The menu item id
*
* @return string
*
* @since 3.0
*
* @throws \Exception If there is an error on the query
*/
public function association($itemid)
{
// Defaults
$html = '';
// Get the associations
if ($associations = MenusHelper::getAssociations($itemid)) {
// Get the associated menu items
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select(
[
$db->quoteName('m.id'),
$db->quoteName('m.title'),
$db->quoteName('l.sef', 'lang_sef'),
$db->quoteName('l.lang_code'),
$db->quoteName('mt.title', 'menu_title'),
$db->quoteName('l.image'),
$db->quoteName('l.title', 'language_title'),
]
)
->from($db->quoteName('#__menu', 'm'))
->join('LEFT', $db->quoteName('#__menu_types', 'mt'), $db->quoteName('mt.menutype') . ' = ' . $db->quoteName('m.menutype'))
->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('m.language') . ' = ' . $db->quoteName('l.lang_code'))
->whereIn($db->quoteName('m.id'), array_values($associations))
->where($db->quoteName('m.id') . ' != :itemid')
->bind(':itemid', $itemid, ParameterType::INTEGER);
$db->setQuery($query);
try {
$items = $db->loadObjectList('id');
} catch (\RuntimeException $e) {
throw new \Exception($e->getMessage(), 500);
}
// Construct html
if ($items) {
$languages = LanguageHelper::getContentLanguages([0, 1]);
$content_languages = array_column($languages, 'lang_code');
foreach ($items as &$item) {
if (\in_array($item->lang_code, $content_languages)) {
$text = $item->lang_code;
$url = Route::_('index.php?option=com_menus&task=item.edit&id=' . (int) $item->id);
$tooltip = '<strong>' . htmlspecialchars($item->language_title, ENT_QUOTES, 'UTF-8') . '</strong><br>'
. htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8') . '<br>' . Text::sprintf('COM_MENUS_MENU_SPRINTF', $item->menu_title);
$classes = 'badge bg-secondary';
$item->link = '<a href="' . $url . '" class="' . $classes . '">' . $text . '</a>'
. '<div role="tooltip" id="tip-' . (int) $itemid . '-' . (int) $item->id . '">' . $tooltip . '</div>';
} else {
// Display warning if Content Language is trashed or deleted
Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_ASSOCIATIONS_CONTENTLANGUAGE_WARNING', $item->lang_code), 'warning');
}
}
}
$html = LayoutHelper::render('joomla.content.associations', $items);
}
return $html;
}
/**
* Returns a visibility state on a grid
*
* @param integer $params Params of item.
*
* @return string The Html code
*
* @since 3.7.0
*/
public function visibility($params)
{
$registry = new Registry();
try {
$registry->loadString($params);
} catch (\Exception $e) {
// Invalid JSON
}
$show_menu = $registry->get('menu_show');
return ($show_menu === 0) ? '<span class="badge bg-secondary">' . Text::_('COM_MENUS_LABEL_HIDDEN') . '</span>' : '';
}
}

View File

@ -0,0 +1,95 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Table;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Table\Menu;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu table
*
* @since 1.6
*/
class MenuTable extends Menu
{
/**
* Method to delete a node and, optionally, its child nodes from the table.
*
* @param integer $pk The primary key of the node to delete.
* @param boolean $children True to delete child nodes, false to move them up a level.
*
* @return boolean True on success.
*
* @since 2.5
*/
public function delete($pk = null, $children = false)
{
$return = parent::delete($pk, $children);
if ($return) {
// Delete key from the #__modules_menu table
$db = $this->getDbo();
$query = $db->getQuery(true)
->delete($db->quoteName('#__modules_menu'))
->where($db->quoteName('menuid') . ' = :pk')
->bind(':pk', $pk, ParameterType::INTEGER);
$db->setQuery($query);
$db->execute();
}
return $return;
}
/**
* Overloaded check function
*
* @return boolean True on success, false on failure
*
* @see \Joomla\CMS\Table\Table::check
* @since 4.0.0
*/
public function check()
{
$return = parent::check();
if ($return) {
// Set publish_up to null date if not set
if (!$this->publish_up) {
$this->publish_up = null;
}
// Set publish_down to null date if not set
if (!$this->publish_down) {
$this->publish_down = null;
}
// Check the publish down date is not earlier than publish up.
if (!\is_null($this->publish_down) && !\is_null($this->publish_up) && $this->publish_down < $this->publish_up) {
$this->setError(Text::_('JGLOBAL_START_PUBLISH_AFTER_FINISH'));
return false;
}
if ((int) $this->home) {
// Set the publish down/up always for home.
$this->publish_up = null;
$this->publish_down = null;
}
}
return $return;
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\Table;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Menu table
*
* @since 1.6
*/
class MenuTypeTable extends \Joomla\CMS\Table\MenuType
{
}

View File

@ -0,0 +1,249 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\View\Item;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ContentHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The HTML Menus Menu Item View.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The active item
*
* @var CMSObject
*/
protected $item;
/**
* @var mixed
*/
protected $modules;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* The actions the user is authorised to perform
*
* @var \Joomla\Registry\Registry
* @since 3.7.0
*/
protected $canDo;
/**
* A list of view levels containing the id and title of the view level
*
* @var \stdClass[]
* @since 4.0.0
*/
protected $levels;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 1.6
*/
public function display($tpl = null)
{
$this->state = $this->get('State');
$this->form = $this->get('Form');
$this->item = $this->get('Item');
$this->modules = $this->get('Modules');
$this->levels = $this->get('ViewLevels');
$this->canDo = ContentHelper::getActions('com_menus', 'menu', (int) $this->state->get('item.menutypeid'));
// Check if we're allowed to edit this item
// No need to check for create, because then the moduletype select is empty
if (!empty($this->item->id) && !$this->canDo->get('core.edit')) {
throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403);
}
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
if ($this->getLayout() === 'modalreturn') {
parent::display($tpl);
return;
}
// If we are forcing a language in modal (used for associations).
if ($this->getLayout() === 'modal' && $forcedLanguage = Factory::getApplication()->getInput()->get('forcedLanguage', '', 'cmd')) {
// Set the language field to the forcedLanguage and disable changing it.
$this->form->setValue('language', null, $forcedLanguage);
$this->form->setFieldAttribute('language', 'readonly', 'true');
// Only allow to select categories with All language or with the forced language.
$this->form->setFieldAttribute('parent_id', 'language', '*,' . $forcedLanguage);
}
if ($this->getLayout() !== 'modal') {
$this->addToolbar();
} else {
$this->addModalToolbar();
}
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 1.6
*/
protected function addToolbar()
{
$input = Factory::getApplication()->getInput();
$input->set('hidemainmenu', true);
$user = $this->getCurrentUser();
$isNew = ($this->item->id == 0);
$checkedOut = !(\is_null($this->item->checked_out) || $this->item->checked_out == $user->get('id'));
$canDo = $this->canDo;
$clientId = $this->state->get('item.client_id', 0);
$toolbar = Toolbar::getInstance();
ToolbarHelper::title(Text::_($isNew ? 'COM_MENUS_VIEW_NEW_ITEM_TITLE' : 'COM_MENUS_VIEW_EDIT_ITEM_TITLE'), 'list menu-add');
// If a new item, can save the item. Allow users with edit permissions to apply changes to prevent returning to grid.
if ($isNew && $canDo->get('core.create')) {
if ($canDo->get('core.edit')) {
$toolbar->apply('item.apply');
}
}
// If not checked out, can save the item.
if (!$isNew && !$checkedOut && $canDo->get('core.edit')) {
$toolbar->apply('item.apply');
}
$saveGroup = $toolbar->dropdownButton('save-group');
$saveGroup->configure(
function (Toolbar $childBar) use ($isNew, $checkedOut, $canDo) {
// If a new item, can save the item. Allow users with edit permissions to apply changes to prevent returning to grid.
if ($isNew && $canDo->get('core.create')) {
$childBar->save('item.save');
}
// If not checked out, can save the item.
if (!$isNew && !$checkedOut && $canDo->get('core.edit')) {
$childBar->save('item.save');
}
// If the user can create new items, allow them to see Save & New
if ($canDo->get('core.create')) {
$childBar->save2new('item.save2new');
}
// If an existing item, can save to a copy only if we have create rights.
if (!$isNew && $canDo->get('core.create')) {
$childBar->save2copy('item.save2copy');
}
}
);
if (!$isNew && Associations::isEnabled() && ComponentHelper::isEnabled('com_associations') && $clientId != 1) {
$toolbar->standardButton('associations', 'JTOOLBAR_ASSOCIATIONS', 'item.editAssociations')
->icon('icon-contract')
->listCheck(false);
}
if ($isNew) {
$toolbar->cancel('item.cancel', 'JTOOLBAR_CANCEL');
} else {
$toolbar->cancel('item.cancel');
}
$toolbar->divider();
// Get the help information for the menu item.
$lang = $this->getLanguage();
$help = $this->get('Help');
if ($lang->hasKey($help->url)) {
$debug = $lang->setDebug(false);
$url = Text::_($help->url);
$lang->setDebug($debug);
} else {
$url = $help->url;
}
$toolbar->help($help->key, $help->local, $url);
}
/**
* Add the modal toolbar.
*
* @return void
*
* @since 5.0.0
*
* @throws \Exception
*/
protected function addModalToolbar()
{
$user = $this->getCurrentUser();
$isNew = ($this->item->id == 0);
$checkedOut = !(\is_null($this->item->checked_out) || $this->item->checked_out == $user->get('id'));
$canDo = $this->canDo;
$toolbar = Toolbar::getInstance();
ToolbarHelper::title(Text::_($isNew ? 'COM_MENUS_VIEW_NEW_ITEM_TITLE' : 'COM_MENUS_VIEW_EDIT_ITEM_TITLE'), 'list menu-add');
$canSave = !$checkedOut && ($isNew && $canDo->get('core.create') || $canDo->get('core.edit'));
// For new records, check the create permission.
if ($canSave) {
$toolbar->apply('item.apply');
$toolbar->save('item.save');
}
$toolbar->cancel('item.cancel');
}
}

View File

@ -0,0 +1,384 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\View\Items;
use Joomla\CMS\Event\Menu\BeforeRenderMenuItemsViewEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ContentHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Multilanguage;
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
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The HTML Menus Menu Items View.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* Array used for displaying the levels filter
*
* @var \stdClass[]
* @since 4.0.0
*/
protected $f_levels;
/**
* An array of items
*
* @var array
*/
protected $items;
/**
* The pagination object
*
* @var \Joomla\CMS\Pagination\Pagination
*/
protected $pagination;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* Form object for search filters
*
* @var \Joomla\CMS\Form\Form
*
* @since 4.0.0
*/
public $filterForm;
/**
* The active search filters
*
* @var array
* @since 4.0.0
*/
public $activeFilters;
/**
* Ordering of the items
*
* @var array
* @since 4.0.0
*/
protected $ordering;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 1.6
*/
public function display($tpl = null)
{
$lang = $this->getLanguage();
$this->items = $this->get('Items');
$this->pagination = $this->get('Pagination');
$this->total = $this->get('Total');
$this->state = $this->get('State');
$this->filterForm = $this->get('FilterForm');
$this->activeFilters = $this->get('ActiveFilters');
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
$this->ordering = [];
// Preprocess the list of items to find ordering divisions.
foreach ($this->items as $item) {
$this->ordering[$item->parent_id][] = $item->id;
// Item type text
switch ($item->type) {
case 'url':
$value = Text::_('COM_MENUS_TYPE_EXTERNAL_URL');
break;
case 'alias':
$value = Text::_('COM_MENUS_TYPE_ALIAS');
break;
case 'separator':
$value = Text::_('COM_MENUS_TYPE_SEPARATOR');
break;
case 'heading':
$value = Text::_('COM_MENUS_TYPE_HEADING');
break;
case 'container':
$value = Text::_('COM_MENUS_TYPE_CONTAINER');
break;
case 'component':
default:
// Load language
$lang->load($item->componentname . '.sys', JPATH_ADMINISTRATOR)
|| $lang->load($item->componentname . '.sys', JPATH_ADMINISTRATOR . '/components/' . $item->componentname);
if (!empty($item->componentname)) {
$titleParts = [];
$titleParts[] = Text::_($item->componentname);
$vars = null;
parse_str($item->link, $vars);
if (isset($vars['view'])) {
// Attempt to load the view xml file.
$file = JPATH_SITE . '/components/' . $item->componentname . '/views/' . $vars['view'] . '/metadata.xml';
if (!is_file($file)) {
$file = JPATH_SITE . '/components/' . $item->componentname . '/view/' . $vars['view'] . '/metadata.xml';
}
if (is_file($file) && $xml = simplexml_load_file($file)) {
// Look for the first view node off of the root node.
if ($view = $xml->xpath('view[1]')) {
// Add view title if present.
if (!empty($view[0]['title'])) {
$viewTitle = trim((string) $view[0]['title']);
// Check if the key is valid. Needed due to B/C so we don't show untranslated keys. This check should be removed with Joomla 4.
if ($lang->hasKey($viewTitle)) {
$titleParts[] = Text::_($viewTitle);
}
}
}
}
$vars['layout'] = $vars['layout'] ?? 'default';
// Attempt to load the layout xml file.
// If Alternative Menu Item, get template folder for layout file
if (strpos($vars['layout'], ':') > 0) {
// Use template folder for layout file
$temp = explode(':', $vars['layout']);
$file = JPATH_SITE . '/templates/' . $temp[0] . '/html/' . $item->componentname . '/' . $vars['view'] . '/' . $temp[1] . '.xml';
// Load template language file
$lang->load('tpl_' . $temp[0] . '.sys', JPATH_SITE)
|| $lang->load('tpl_' . $temp[0] . '.sys', JPATH_SITE . '/templates/' . $temp[0]);
} else {
$base = $this->state->get('filter.client_id') == 0 ? JPATH_SITE : JPATH_ADMINISTRATOR;
// Get XML file from component folder for standard layouts
$file = $base . '/components/' . $item->componentname . '/tmpl/' . $vars['view']
. '/' . $vars['layout'] . '.xml';
if (!file_exists($file)) {
$file = $base . '/components/' . $item->componentname . '/views/'
. $vars['view'] . '/tmpl/' . $vars['layout'] . '.xml';
if (!file_exists($file)) {
$file = $base . '/components/' . $item->componentname . '/view/'
. $vars['view'] . '/tmpl/' . $vars['layout'] . '.xml';
}
}
}
if (is_file($file) && $xml = simplexml_load_file($file)) {
// Look for the first view node off of the root node.
if ($layout = $xml->xpath('layout[1]')) {
if (!empty($layout[0]['title'])) {
$titleParts[] = Text::_(trim((string) $layout[0]['title']));
}
}
if (!empty($layout[0]->message[0])) {
$item->item_type_desc = Text::_(trim((string) $layout[0]->message[0]));
}
}
unset($xml);
// Special case if neither a view nor layout title is found
if (\count($titleParts) == 1) {
$titleParts[] = $vars['view'];
}
}
$value = implode(' » ', $titleParts);
} else {
if (preg_match("/^index.php\?option=([a-zA-Z\-0-9_]*)/", $item->link, $result)) {
$value = Text::sprintf('COM_MENUS_TYPE_UNEXISTING', $result[1]);
} else {
$value = Text::_('COM_MENUS_TYPE_UNKNOWN');
}
}
break;
}
$item->item_type = $value;
$item->protected = $item->menutype == 'main';
}
// Levels filter.
$options = [];
$options[] = HTMLHelper::_('select.option', '1', Text::_('J1'));
$options[] = HTMLHelper::_('select.option', '2', Text::_('J2'));
$options[] = HTMLHelper::_('select.option', '3', Text::_('J3'));
$options[] = HTMLHelper::_('select.option', '4', Text::_('J4'));
$options[] = HTMLHelper::_('select.option', '5', Text::_('J5'));
$options[] = HTMLHelper::_('select.option', '6', Text::_('J6'));
$options[] = HTMLHelper::_('select.option', '7', Text::_('J7'));
$options[] = HTMLHelper::_('select.option', '8', Text::_('J8'));
$options[] = HTMLHelper::_('select.option', '9', Text::_('J9'));
$options[] = HTMLHelper::_('select.option', '10', Text::_('J10'));
$this->f_levels = $options;
// We don't need toolbar in the modal window.
if ($this->getLayout() !== 'modal') {
$this->addToolbar();
// We do not need to filter by language when multilingual is disabled
if (!Multilanguage::isEnabled()) {
unset($this->activeFilters['language']);
$this->filterForm->removeField('language', 'filter');
}
} else {
// In menu associations modal we need to remove language filter if forcing a language.
if ($forcedLanguage = Factory::getApplication()->getInput()->get('forcedLanguage', '', 'CMD')) {
// If the language is forced we can't allow to select the language, so transform the language selector filter into a hidden field.
$languageXml = new \SimpleXMLElement('<field name="language" type="hidden" default="' . $forcedLanguage . '" />');
$this->filterForm->setField($languageXml, 'filter', true);
// Also, unset the active language filter so the search tools is not open by default with this filter.
unset($this->activeFilters['language']);
}
}
// Allow a system plugin to insert dynamic menu types to the list shown in menus:
$this->getDispatcher()->dispatch('onBeforeRenderMenuItems', new BeforeRenderMenuItemsViewEvent('onBeforeRenderMenuItems', [
'subject' => $this,
]));
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 1.6
*/
protected function addToolbar()
{
$menutypeId = (int) $this->state->get('menutypeid');
$canDo = ContentHelper::getActions('com_menus', 'menu', (int) $menutypeId);
$user = $this->getCurrentUser();
// Get the menu title
$menuTypeTitle = $this->get('State')->get('menutypetitle');
// Get the toolbar object instance
$toolbar = Toolbar::getInstance('toolbar');
if ($menuTypeTitle) {
ToolbarHelper::title(Text::sprintf('COM_MENUS_VIEW_ITEMS_MENU_TITLE', $menuTypeTitle), 'list menumgr');
} else {
ToolbarHelper::title(Text::_('COM_MENUS_VIEW_ITEMS_ALL_TITLE'), 'list menumgr');
}
if ($canDo->get('core.create')) {
$toolbar->addNew('item.add');
}
$protected = $this->state->get('filter.menutype') == 'main';
if (
($canDo->get('core.edit.state') || $this->getCurrentUser()->authorise('core.admin')) && !$protected
|| $canDo->get('core.edit.state') && $this->state->get('filter.client_id') == 0
) {
$dropdown = $toolbar->dropdownButton('status-group')
->text('JTOOLBAR_CHANGE_STATUS')
->toggleSplit(false)
->icon('icon-ellipsis-h')
->buttonClass('btn btn-action')
->listCheck(true);
$childBar = $dropdown->getChildToolbar();
if ($canDo->get('core.edit.state') && !$protected) {
$childBar->publish('items.publish')->listCheck(true);
$childBar->unpublish('items.unpublish')->listCheck(true);
}
if ($this->getCurrentUser()->authorise('core.admin') && !$protected) {
$childBar->checkin('items.checkin')->listCheck(true);
}
if ($canDo->get('core.edit.state') && $this->state->get('filter.published') != -2) {
if ($this->state->get('filter.client_id') == 0) {
$childBar->makeDefault('items.setDefault')->listCheck(true);
}
if (!$protected) {
$childBar->trash('items.trash')->listCheck(true);
}
}
// Add a batch button
if (
!$protected && $user->authorise('core.create', 'com_menus')
&& $user->authorise('core.edit', 'com_menus')
&& $user->authorise('core.edit.state', 'com_menus')
) {
$childBar->popupButton('batch')
->text('JTOOLBAR_BATCH')
->selector('collapseModal')
->listCheck(true);
}
}
if ($this->getCurrentUser()->authorise('core.admin')) {
$toolbar->standardButton('refresh')
->text('JTOOLBAR_REBUILD')
->task('items.rebuild');
}
if (!$protected && $this->state->get('filter.published') == -2 && $canDo->get('core.delete')) {
$toolbar->delete('items.delete')
->text('JTOOLBAR_EMPTY_TRASH')
->message('JGLOBAL_CONFIRM_DELETE')
->listCheck(true);
}
if ($canDo->get('core.admin') || $canDo->get('core.options')) {
$toolbar->preferences('com_menus');
}
$toolbar->help('Menus:_Items');
}
}

View File

@ -0,0 +1,144 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\View\Menu;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ContentHelper;
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
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The HTML Menus Menu Item View.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The active item
*
* @var object
*/
protected $item;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* The actions the user is authorised to perform
*
* @var \Joomla\Registry\Registry
*/
protected $canDo;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 1.6
*/
public function display($tpl = null)
{
$this->form = $this->get('Form');
$this->item = $this->get('Item');
$this->state = $this->get('State');
$this->canDo = ContentHelper::getActions('com_menus', 'menu', $this->item->id);
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
parent::display($tpl);
$this->addToolbar();
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 1.6
*/
protected function addToolbar()
{
$input = Factory::getApplication()->getInput();
$input->set('hidemainmenu', true);
$isNew = ($this->item->id == 0);
$toolbar = Toolbar::getInstance();
ToolbarHelper::title(Text::_($isNew ? 'COM_MENUS_VIEW_NEW_MENU_TITLE' : 'COM_MENUS_VIEW_EDIT_MENU_TITLE'), 'list menu');
// If a new item, can save the item. Allow users with edit permissions to apply changes to prevent returning to grid.
if ($isNew && $this->canDo->get('core.create') && $this->canDo->get('core.edit')) {
$toolbar->apply('menu.apply');
}
// If user can edit, can save the item.
if (!$isNew && $this->canDo->get('core.edit')) {
$toolbar->apply('menu.apply');
}
$saveGroup = $toolbar->dropdownButton('save-group');
$canDo = $this->canDo;
$saveGroup->configure(
function (Toolbar $childBar) use ($isNew, $canDo) {
// If a new item, can save the item. Allow users with edit permissions to apply changes to prevent returning to grid.
if ($isNew && $canDo->get('core.create')) {
$childBar->save('menu.save');
}
// If user can edit, can save the item.
if (!$isNew && $canDo->get('core.edit')) {
$childBar->save('menu.save');
}
// If the user can create new items, allow them to see Save & New
if ($canDo->get('core.create')) {
$childBar->save2new('menu.save2new');
}
}
);
if ($isNew) {
$toolbar->cancel('menu.cancel', 'JTOOLBAR_CANCEL');
} else {
$toolbar->cancel('menu.cancel');
}
$toolbar->divider();
$toolbar->help('Menus:_Edit');
}
}

View File

@ -0,0 +1,156 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\View\Menu;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Menu\AdministratorMenuItem;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The HTML Menus Menu Item View.
*
* @since 3.8.0
*/
class XmlView extends BaseHtmlView
{
/**
* @var AdministratorMenuItem[]
*
* @since 3.8.0
*/
protected $items;
/**
* @var \Joomla\Registry\Registry
*
* @since 3.8.0
*/
protected $state;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 3.8.0
*/
public function display($tpl = null)
{
$app = Factory::getApplication();
$menutype = $app->getInput()->getCmd('menutype');
if ($menutype) {
$root = MenusHelper::getMenuItems($menutype, true);
}
if (!$root->hasChildren()) {
Log::add(Text::_('COM_MENUS_SELECT_MENU_FIRST_EXPORT'), Log::WARNING, 'jerror');
$app->redirect(Route::_('index.php?option=com_menus&view=menus', false));
return;
}
$this->items = $root->getChildren(true);
$xml = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><menu ' .
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' .
'xmlns="urn:joomla.org" xsi:schemaLocation="urn:joomla.org menu.xsd"' .
'></menu>');
foreach ($this->items as $item) {
$this->addXmlChild($xml, $item);
}
if (headers_sent($file, $line)) {
Log::add("Headers already sent at $file:$line.", Log::ERROR, 'jerror');
return;
}
header('content-type: application/xml');
header('content-disposition: attachment; filename="' . $menutype . '.xml"');
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
$dom = new \DOMDocument();
$dom->preserveWhiteSpace = true;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
echo $dom->saveXML();
$app->close();
}
/**
* Add a child node to the xml
*
* @param \SimpleXMLElement $xml The current XML node which would become the parent to the new node
* @param AdministratorMenuItem $item The menuitem object to create the child XML node from
*
* @return void
*
* @since 3.8.0
*/
protected function addXmlChild($xml, $item)
{
$node = $xml->addChild('menuitem');
$node['type'] = $item->type;
if ($item->title) {
$node['title'] = htmlentities($item->title, ENT_XML1);
}
if ($item->link) {
$node['link'] = $item->link;
}
if ($item->element) {
$node['element'] = $item->element;
}
if (isset($item->class) && $item->class) {
$node['class'] = htmlentities($item->class, ENT_XML1);
}
if ($item->access) {
$node['access'] = $item->access;
}
if ($item->browserNav) {
$node['target'] = '_blank';
}
if ($item->getParams() && $hideitems = $item->getParams()->get('hideitems')) {
$item->getParams()->set('hideitems', $this->getModel('Menu')->getExtensionElementsForMenuItems($hideitems));
$node->addChild('params', htmlentities((string) $item->getParams(), ENT_XML1));
}
if (isset($item->submenu)) {
foreach ($item->submenu as $sub) {
$this->addXmlChild($node, $sub);
}
}
}
}

View File

@ -0,0 +1,153 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\View\Menus;
use Joomla\CMS\Helper\ContentHelper;
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
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The HTML Menus Menu Menus View.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* An array of items
*
* @var array
*/
protected $items;
/**
* List of all mod_mainmenu modules collated by menutype
*
* @var array
*/
protected $modules;
/**
* The pagination object
*
* @var \Joomla\CMS\Pagination\Pagination
*/
protected $pagination;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* Form object for search filters
*
* @var \Joomla\CMS\Form\Form
*
* @since 4.0.0
*/
public $filterForm;
/**
* The active search filters
*
* @var array
* @since 4.0.0
*/
public $activeFilters;
/**
* Ordering of the items
*
* @var array
* @since 5.0.0
*/
protected $ordering;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 1.6
*/
public function display($tpl = null)
{
$this->items = $this->get('Items');
$this->modules = $this->get('Modules');
$this->pagination = $this->get('Pagination');
$this->state = $this->get('State');
if ($this->getLayout() == 'default') {
$this->filterForm = $this->get('FilterForm');
$this->activeFilters = $this->get('ActiveFilters');
}
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
$this->addToolbar();
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 1.6
*/
protected function addToolbar()
{
$canDo = ContentHelper::getActions('com_menus');
$toolbar = Toolbar::getInstance();
ToolbarHelper::title(Text::_('COM_MENUS_VIEW_MENUS_TITLE'), 'list menumgr');
if ($canDo->get('core.create')) {
$toolbar->addNew('menu.add');
}
if ($canDo->get('core.delete')) {
$toolbar->divider();
$toolbar->delete('menus.delete')
->message('COM_MENUS_MENU_CONFIRM_DELETE');
}
if ($canDo->get('core.admin') && $this->state->get('client_id') == 1) {
$toolbar->standardButton('download', 'COM_MENUS_MENU_EXPORT_BUTTON', 'menu.exportXml')
->icon('icon-download')
->listCheck(true);
}
if ($canDo->get('core.admin') || $canDo->get('core.options')) {
$toolbar->divider();
$toolbar->preferences('com_menus');
}
$toolbar->divider();
$toolbar->help('Menus');
}
}

View File

@ -0,0 +1,169 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Administrator\View\Menutypes;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The HTML Menus Menu Item Types View.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* The menu type id
*
* @var integer
* @since 4.0.0
*/
protected $recordId;
/**
* Array of menu types
*
* @var CMSObject[]
*
* @since 3.7.0
*/
protected $types;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 1.6
*/
public function display($tpl = null)
{
$app = Factory::getApplication();
$this->recordId = $app->getInput()->getInt('recordId');
$types = $this->get('TypeOptions');
$this->addCustomTypes($types);
$sortedTypes = [];
foreach ($types as $name => $list) {
$tmp = [];
foreach ($list as $item) {
$tmp[Text::_($item->title)] = $item;
}
uksort($tmp, 'strcasecmp');
$sortedTypes[Text::_($name)] = $tmp;
}
uksort($sortedTypes, 'strcasecmp');
$this->types = $sortedTypes;
if (!$app->getInput()->get('tmpl')) {
$this->addToolbar();
}
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 3.0
*/
protected function addToolbar()
{
// Add page title
ToolbarHelper::title(Text::_('COM_MENUS'), 'list menumgr');
$toolbar = Toolbar::getInstance();
// Cancel
$title = Text::_('JTOOLBAR_CANCEL');
$dhtml = "<button onClick=\"location.href='index.php?option=com_menus&view=items'\" class=\"btn\">
<span class=\"icon-times\" title=\"$title\"></span>
$title</button>";
$toolbar->customButton('new')
->html($dhtml);
}
/**
* Method to add system link types to the link types array
*
* @param array $types The list of link types
*
* @return void
*
* @since 3.7.0
*/
protected function addCustomTypes(&$types)
{
if (empty($types)) {
$types = [];
}
// Adding System Links
$list = [];
$o = new CMSObject();
$o->title = 'COM_MENUS_TYPE_EXTERNAL_URL';
$o->type = 'url';
$o->description = 'COM_MENUS_TYPE_EXTERNAL_URL_DESC';
$o->request = null;
$list[] = $o;
$o = new CMSObject();
$o->title = 'COM_MENUS_TYPE_ALIAS';
$o->type = 'alias';
$o->description = 'COM_MENUS_TYPE_ALIAS_DESC';
$o->request = null;
$list[] = $o;
$o = new CMSObject();
$o->title = 'COM_MENUS_TYPE_SEPARATOR';
$o->type = 'separator';
$o->description = 'COM_MENUS_TYPE_SEPARATOR_DESC';
$o->request = null;
$list[] = $o;
$o = new CMSObject();
$o->title = 'COM_MENUS_TYPE_HEADING';
$o->type = 'heading';
$o->description = 'COM_MENUS_TYPE_HEADING_DESC';
$o->request = null;
$list[] = $o;
if ($this->get('state')->get('client_id') == 1) {
$o = new CMSObject();
$o->title = 'COM_MENUS_TYPE_CONTAINER';
$o->type = 'container';
$o->description = 'COM_MENUS_TYPE_CONTAINER_DESC';
$o->request = null;
$list[] = $o;
}
$types['COM_MENUS_TYPE_SYSTEM'] = $list;
}
}

View File

@ -0,0 +1,177 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
$this->useCoreUI = true;
Text::script('ERROR');
Text::script('JGLOBAL_VALIDATION_FORM_FAILED');
Text::script('JGLOBAL_ROOT_PARENT');
$this->document->addScriptOptions('menu-item', ['itemId' => (int) $this->item->id]);
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('keepalive')
->useScript('form.validate')
->useScript('com_menus.admin-item-edit');
$assoc = Associations::isEnabled();
$input = Factory::getApplication()->getInput();
// In case of modal
$isModal = $input->get('layout') === 'modal';
$layout = $isModal ? 'modal' : 'edit';
$tmpl = $input->get('tmpl');
$tmpl = $tmpl ? '&tmpl=' . $tmpl : '';
$clientId = $this->state->get('item.client_id', 0);
$lang = $this->getLanguage()->getTag();
// Load mod_menu.ini file when client is administrator
if ($clientId === 1) {
$this->getLanguage()->load('mod_menu', JPATH_ADMINISTRATOR);
}
?>
<form action="<?php echo Route::_('index.php?option=com_menus&view=item&client_id=' . $clientId . '&layout=' . $layout . $tmpl . '&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="item-form" aria-label="<?php echo Text::_('COM_MENUS_ITEM_FORM_' . ((int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>" class="form-validate">
<?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?>
<?php // Add the translation of the menu item title when client is administrator ?>
<?php if ($clientId === 1 && $this->item->id != 0) : ?>
<div class="row title-alias form-vertical mb-3">
<div class="col-12">
<div class="control-group">
<div class="control-label">
<label for="menus_title_translation"><?php echo Text::sprintf('COM_MENUS_TITLE_TRANSLATION', $lang); ?></label>
</div>
<div class="controls">
<input id="menus_title_translation" class="form-control" value="<?php echo Text::_($this->item->title); ?>" readonly="readonly" type="text">
</div>
</div>
</div>
</div>
<?php endif; ?>
<div class="main-card">
<?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'details', 'recall' => true, 'breakpoint' => 768]); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'details', Text::_('COM_MENUS_ITEM_DETAILS')); ?>
<div class="row">
<div class="col-lg-9">
<?php
echo $this->form->renderField('type');
if ($this->item->type == 'alias') {
echo $this->form->renderField('aliasoptions', 'params');
}
if ($this->item->type == 'separator') {
echo $this->form->renderField('text_separator', 'params');
}
echo $this->form->renderFieldset('request');
if ($this->item->type == 'url') {
$this->form->setFieldAttribute('link', 'readonly', 'false');
$this->form->setFieldAttribute('link', 'required', 'true');
}
echo $this->form->renderField('link');
if ($this->item->type == 'alias') {
echo $this->form->renderField('alias_redirect', 'params');
}
echo $this->form->renderField('browserNav');
echo $this->form->renderField('template_style_id');
if (!$isModal && $this->item->type == 'container') {
echo $this->loadTemplate('container');
}
?>
</div>
<div class="col-lg-3">
<?php
// Set main fields.
$this->fields = [
'id',
'client_id',
'menutype',
'parent_id',
'menuordering',
'published',
'home',
'publish_up',
'publish_down',
'access',
'language',
'note',
];
if ($this->item->type != 'component') {
$this->fields = array_diff($this->fields, ['home']);
$this->form->setFieldAttribute('publish_up', 'showon', '');
$this->form->setFieldAttribute('publish_down', 'showon', '');
}
echo LayoutHelper::render('joomla.edit.global', $this); ?>
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php
$this->fieldsets = [];
$this->ignore_fieldsets = ['aliasoptions', 'request', 'item_associations'];
echo LayoutHelper::render('joomla.edit.params', $this);
?>
<?php if (!$isModal && $assoc && $this->state->get('item.client_id') != 1) : ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'associations', Text::_('JGLOBAL_FIELDSET_ASSOCIATIONS')); ?>
<fieldset id="fieldset-associations" class="options-form">
<legend><?php echo Text::_('JGLOBAL_FIELDSET_ASSOCIATIONS'); ?></legend>
<div>
<?php echo LayoutHelper::render('joomla.edit.associations', $this); ?>
</div>
</fieldset>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php elseif ($isModal && $assoc) : ?>
<div class="hidden"><?php echo LayoutHelper::render('joomla.edit.associations', $this); ?></div>
<?php endif; ?>
<?php if (!empty($this->modules)) : ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'modules', Text::_('COM_MENUS_ITEM_MODULE_ASSIGNMENT')); ?>
<fieldset id="fieldset-modules" class="options-form">
<legend><?php echo Text::_('COM_MENUS_ITEM_MODULE_ASSIGNMENT'); ?></legend>
<div>
<?php echo $this->loadTemplate('modules'); ?>
</div>
</fieldset>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php endif; ?>
<?php echo HTMLHelper::_('uitab.endTabSet'); ?>
</div>
<input type="hidden" name="task" value="">
<input type="hidden" name="forcedLanguage" value="<?php echo $input->get('forcedLanguage', '', 'cmd'); ?>">
<input type="hidden" name="menutype" value="<?php echo $input->get('menutype', '', 'cmd'); ?>">
<?php echo $this->form->getInput('component_id'); ?>
<?php echo HTMLHelper::_('form.token'); ?>
<input type="hidden" id="fieldtype" name="fieldtype" value="">
</form>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<layout title="COM_MENUS_ITEM_VIEW_EDIT_TITLE">
<message>
<![CDATA[COM_MENUS_ITEM_VIEW_EDIT_DESC]]>
</message>
</layout>
<fieldset name="request">
<fields name="request">
<field
name="menutype"
type="menu"
label="COM_MENUS_ITEMS_CHOOSE_MENU_LABEL"
description="COM_MENUS_ITEMS_CHOOSE_MENU_DESC"
clientid=""
>
<option value="">COM_MENUS_SELECT_MENU</option>
</field>
</fields>
</fieldset>
</metadata>

View File

@ -0,0 +1,105 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
use Joomla\Registry\Registry;
// Initialise related data.
$menuLinks = MenusHelper::getMenuLinks('main');
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('joomla.treeselectmenu')
->useStyle('com_menus.admin-item-edit-container')
->useScript('com_menus.admin-item-edit-container');
?>
<div id="menuselect-group" class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('hideitems', 'params'); ?></div>
<div id="jform_params_hideitems" class="controls">
<?php if (!empty($menuLinks)) : ?>
<?php $id = 'jform_params_hideitems'; ?>
<div class="form-inline">
<span class="small me-2"><?php echo Text::_('COM_MENUS_ACTION_EXPAND'); ?>:
<a id="treeExpandAll" href="javascript://"><?php echo Text::_('JALL'); ?></a>,
<a id="treeCollapseAll" href="javascript://"><?php echo Text::_('JNONE'); ?></a> |
<?php echo Text::_('JSHOW'); ?>:
<a id="treeUncheckAll" href="javascript://"><?php echo Text::_('JALL'); ?></a>,
<a id="treeCheckAll" href="javascript://"><?php echo Text::_('JNONE'); ?></a>
</span>
<input type="text" id="treeselectfilter" name="treeselectfilter" class="form-control search-query"
autocomplete="off" placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>"
aria-invalid="false" aria-label="<?php echo Text::_('JSEARCH_FILTER'); ?>">
</div>
<hr>
<div class="alert alert-info">
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
<?php echo Text::_('COM_MENUS_ITEM_FIELD_COMPONENTS_CONTAINER_HIDE_ITEMS_DESC'); ?>
</div>
<?php if (count($menuLinks)) : ?>
<ul class="treeselect">
<?php $prevlevel = 0; ?>
<li>
<?php
$params = new Registry($this->item->params);
$hiddenLinks = (array) $params->get('hideitems');
foreach ($menuLinks as $i => $link) : ?>
<?php
if ($extension = $link->element) :
$lang->load("$extension.sys", JPATH_ADMINISTRATOR)
|| $lang->load("$extension.sys", JPATH_ADMINISTRATOR . '/components/' . $extension);
endif;
if ($prevlevel < $link->level) {
echo '<ul class="treeselect-sub">';
} elseif ($prevlevel > $link->level) {
echo str_repeat('</li></ul>', $prevlevel - $link->level);
} else {
echo '</li>';
}
$selected = in_array($link->value, $hiddenLinks) ? 1 : 0;
?>
<li>
<div class="treeselect-item">
<input type="checkbox" <?php echo $link->value > 1 ? ' name="jform[params][hideitems][]" ' : ''; ?>
id="<?php echo $id . $link->value; ?>" value="<?php echo (int) $link->value; ?>" class="novalidate checkbox-toggle"
<?php echo $selected ? ' checked="checked"' : ''; ?>>
<?php if ($link->value == 1) : ?>
<label for="<?php echo $id . $link->value; ?>" class="btn btn-sm btn-info"><?php echo Text::_('JALL') ?></label>
<?php else : ?>
<label for="<?php echo $id . $link->value; ?>" class="btn btn-sm btn-danger btn-hide"><?php echo Text::_('JHIDE') ?></label>
<label for="<?php echo $id . $link->value; ?>" class="btn btn-sm btn-success btn-show"><?php echo Text::_('JSHOW') ?></label>
<label for="<?php echo $id . $link->value; ?>"><?php echo Text::_($link->text); ?></label>
<?php endif; ?>
</div>
<?php
if (!isset($menuLinks[$i + 1])) {
echo str_repeat('</li></ul>', $link->level);
}
$prevlevel = $link->level;
?>
<?php endforeach; ?>
</li>
</ul>
<?php endif; ?>
<joomla-alert id="noresultsfound" type="warning" style="display:none"><?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?></joomla-alert>
<?php endif; ?>
</div>
</div>

View File

@ -0,0 +1,148 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
foreach ($this->levels as $key => $value) {
$allLevels[$value->id] = $value->title;
}
$this->document->addScriptOptions('menus-edit-modules', ['viewLevels' => $allLevels, 'itemId' => $this->item->id]);
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('com_menus.admin-item-edit-modules');
// 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' => '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" data-bs-target="#closeBtn">'
. Text::_('JLIB_HTML_BEHAVIOR_CLOSE') . '</button>'
. '<button type="button" class="btn btn-primary" data-bs-dismiss="modal" data-bs-target="#saveBtn">'
. Text::_('JSAVE') . '</button>'
. '<button type="button" class="btn btn-success" data-bs-target="#applyBtn">'
. Text::_('JAPPLY') . '</button>',
]
);
?>
<?php
// Set main fields.
$this->fields = ['toggle_modules_assigned', 'toggle_modules_published'];
echo LayoutHelper::render('joomla.menu.edit_modules', $this); ?>
<table class="table" id="modules_assigned">
<caption class="visually-hidden">
<?php echo Text::_('COM_MENUS_MODULES_TABLE_CAPTION'); ?>
</caption>
<thead>
<tr>
<th scope="col" class="w-40">
<?php echo Text::_('COM_MENUS_HEADING_ASSIGN_MODULE'); ?>
</th>
<th scope="col" class="w-15">
<?php echo Text::_('COM_MENUS_HEADING_LEVELS'); ?>
</th>
<th scope="col" class="w-15">
<?php echo Text::_('COM_MENUS_HEADING_POSITION'); ?>
</th>
<th scope="col">
<?php echo Text::_('COM_MENUS_HEADING_DISPLAY'); ?>
</th>
<th scope="col">
<?php echo Text::_('COM_MENUS_HEADING_PUBLISHED_ITEMS'); ?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->modules as $i => &$module) : ?>
<?php if (is_null($module->menuid)) : ?>
<?php if (!$module->except || $module->menuid < 0) : ?>
<?php $no = 'no '; ?>
<?php else : ?>
<?php $no = ''; ?>
<?php endif; ?>
<?php else : ?>
<?php $no = ''; ?>
<?php endif; ?>
<?php if ($module->published) : ?>
<?php $status = ''; ?>
<?php else : ?>
<?php $status = 'unpublished '; ?>
<?php endif; ?>
<tr id="tr-<?php echo $module->id; ?>" class="<?php echo $no; ?><?php echo $status; ?>row<?php echo $i % 2; ?>">
<th scope="row">
<button type="button"
data-bs-target="#moduleEditModal"
class="btn btn-link module-edit-link"
title="<?php echo Text::_('COM_MENUS_EDIT_MODULE_SETTINGS'); ?>"
id="title-<?php echo $module->id; ?>"
data-module-id="<?php echo $module->id; ?>">
<?php echo $this->escape($module->title); ?></button>
</th>
<td id="access-<?php echo $module->id; ?>">
<?php echo $this->escape($module->access_title); ?>
</td>
<td id="position-<?php echo $module->id; ?>">
<?php echo $this->escape($module->position); ?>
</td>
<td id="menus-<?php echo $module->id; ?>">
<?php if (is_null($module->menuid)) : ?>
<?php if ($module->except) : ?>
<span class="badge bg-success">
<?php echo Text::_('JYES'); ?>
</span>
<?php else : ?>
<span class="badge bg-danger">
<?php echo Text::_('JNO'); ?>
</span>
<?php endif; ?>
<?php elseif ($module->menuid > 0) : ?>
<span class="badge bg-success">
<?php echo Text::_('JYES'); ?>
</span>
<?php elseif ($module->menuid < 0) : ?>
<span class="badge bg-danger">
<?php echo Text::_('JNO'); ?>
</span>
<?php else : ?>
<span class="badge bg-info">
<?php echo Text::_('JALL'); ?>
</span>
<?php endif; ?>
</td>
<td id="status-<?php echo $module->id; ?>">
<?php if ($module->published) : ?>
<span class="badge bg-success">
<?php echo Text::_('JYES'); ?>
</span>
<?php else : ?>
<span class="badge bg-danger">
<?php echo Text::_('JNO'); ?>
</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@ -0,0 +1,20 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
?>
<div class="subhead noshadow mb-3">
<?php echo $this->document->getToolbar('toolbar')->render(); ?>
</div>
<div class="container-popup">
<?php $this->setLayout('edit'); ?>
<?php echo $this->loadTemplate(); ?>
</div>

View File

@ -0,0 +1,42 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_content
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
$icon = 'icon-check';
$title = $this->item ? $this->item->title : '';
$content = $this->item ? $this->item->alias : '';
$data = ['contentType' => 'com_menus.item'];
if ($this->item) {
$data['id'] = $this->item->id;
$data['title'] = $this->item->title;
$data['uri'] = 'index.php?Itemid=' . $this->item->id;
}
// Add Content select script
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('modal-content-select');
// The data for Content select script
$this->document->addScriptOptions('content-select-on-load', $data, false);
?>
<div class="px-4 py-5 my-5 text-center">
<span class="fa-8x mb-4 <?php echo $icon; ?>" aria-hidden="true"></span>
<h1 class="display-5 fw-bold"><?php echo $title; ?></h1>
<div class="col-lg-6 mx-auto">
<p class="lead mb-4">
<?php echo $content; ?>
</p>
</div>
</div>

View File

@ -0,0 +1,290 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('table.columns')
->useScript('multiselect');
$user = $this->getCurrentUser();
$app = Factory::getApplication();
$userId = $user->get('id');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$ordering = ($listOrder == 'a.lft');
$saveOrder = ($listOrder == 'a.lft' && strtolower($listDirn) == 'asc');
$menuType = (string) $app->getUserState('com_menus.items.menutype', '');
if ($saveOrder && $menuType && !empty($this->items)) {
$saveOrderingUrl = 'index.php?option=com_menus&task=items.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1';
HTMLHelper::_('draggablelist.draggable');
}
$assoc = Associations::isEnabled() && $this->state->get('filter.client_id') == 0;
?>
<?php // Set up the filter bar. ?>
<form action="<?php echo Route::_('index.php?option=com_menus&view=items&menutype='); ?>" method="post" name="adminForm"
id="adminForm">
<div class="row">
<div class="col-md-12">
<div id="j-main-container" class="j-main-container">
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this, 'options' => ['selectorFieldName' => 'menutype']]); ?>
<?php if (!empty($this->items)) : ?>
<table class="table" id="menuitemList">
<caption class="visually-hidden">
<?php echo Text::_('COM_MENUS_ITEMS_TABLE_CAPTION'); ?>,
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
</caption>
<thead>
<tr>
<td class="w-1 text-center">
<?php echo HTMLHelper::_('grid.checkall'); ?>
</td>
<?php if ($menuType) : ?>
<th scope="col" class="w-1 text-center d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', '', 'a.lft', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-sort'); ?>
</th>
<?php endif; ?>
<th scope="col" class="w-1 text-center">
<?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 'a.published', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="title">
<?php echo HTMLHelper::_('searchtools.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MENUS_HEADING_MENU', 'menutype_title', $listDirn, $listOrder); ?>
</th>
<?php if ($this->state->get('filter.client_id') == 0) : ?>
<th scope="col" class="w-10 text-center d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MENUS_HEADING_HOME', 'a.home', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<?php if ($this->state->get('filter.client_id') == 0) : ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ACCESS', 'a.access', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<?php if ($assoc) : ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MENUS_HEADING_ASSOCIATION', 'association', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<?php if (($this->state->get('filter.client_id') == 0) && (Multilanguage::isEnabled())) : ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_LANGUAGE', 'language', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<th scope="col" class="w-5 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tbody <?php if ($saveOrder && $menuType) :
?> class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>" data-nested="false"<?php
endif; ?>>
<?php
foreach ($this->items as $i => $item) :
$orderkey = array_search($item->id, $this->ordering[$item->parent_id]);
$canCreate = $user->authorise('core.create', 'com_menus.menu.' . $item->menutype_id);
$canEdit = $user->authorise('core.edit', 'com_menus.menu.' . $item->menutype_id);
$canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || is_null($item->checked_out);
$canChange = $user->authorise('core.edit.state', 'com_menus.menu.' . $item->menutype_id) && $canCheckin;
// Get the parents of item for sorting
if ($item->level > 1) {
$parentsStr = '';
$_currentParentId = $item->parent_id;
$parentsStr = ' ' . $_currentParentId;
for ($j = 0; $j < $item->level; $j++) {
foreach ($this->ordering as $k => $v) {
$v = implode('-', $v);
$v = '-' . $v . '-';
if (strpos($v, '-' . $_currentParentId . '-') !== false) {
$parentsStr .= ' ' . $k;
$_currentParentId = $k;
break;
}
}
}
} else {
$parentsStr = '';
}
?>
<tr class="row<?php echo $i % 2; ?>" data-draggable-group="<?php echo $item->parent_id; ?>"
data-item-id="<?php echo $item->id; ?>" data-parents="<?php echo $parentsStr; ?>"
data-level="<?php echo $item->level; ?>">
<td class="text-center">
<?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', $item->title); ?>
</td>
<?php if ($menuType) : ?>
<td class="text-center d-none d-md-table-cell">
<?php
$iconClass = '';
if (!$canChange) {
$iconClass = ' inactive';
} elseif (!$saveOrder) {
$iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED');
}
?>
<span class="sortable-handler<?php echo $iconClass ?>">
<span class="icon-ellipsis-v" aria-hidden="true"></span>
</span>
<?php if ($canChange && $saveOrder) : ?>
<input type="text" class="hidden" name="order[]" size="5"
value="<?php echo $orderkey + 1; ?>">
<?php endif; ?>
</td>
<?php endif; ?>
<td class="text-center">
<?php if ($item->type === 'component' && !$item->enabled) : ?>
<span class="icon-warning" aria-hidden="true"></span>
<div role="tooltip" id="warning<?php echo $item->id; ?>">
<?php echo Text::_($item->enabled === null ? 'JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND' : 'COM_MENUS_LABEL_DISABLED'); ?>
</div>
<?php else : ?>
<?php echo HTMLHelper::_('jgrid.published', $item->published, $i, 'items.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?>
<?php endif; ?>
</td>
<th scope="row">
<?php $prefix = LayoutHelper::render('joomla.html.treeprefix', ['level' => $item->level]); ?>
<?php echo $prefix; ?>
<?php if ($item->checked_out) : ?>
<?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'items.', $canCheckin); ?>
<?php endif; ?>
<?php if ($canEdit && !$item->protected) : ?>
<a href="<?php echo Route::_('index.php?option=com_menus&task=item.edit&id=' . (int) $item->id); ?>"
title="<?php echo Text::_('JACTION_EDIT'); ?> <?php echo $this->escape($item->title); ?>">
<?php echo $this->escape($item->title); ?></a>
<?php else : ?>
<?php echo $this->escape($item->title); ?>
<?php endif; ?>
<?php echo HTMLHelper::_('menus.visibility', $item->params); ?>
<div>
<?php echo $prefix; ?>
<span class="small">
<?php if ($item->type != 'url') : ?>
<?php if (empty($item->note)) : ?>
<?php echo Text::sprintf('JGLOBAL_LIST_ALIAS', $this->escape($item->alias)); ?>
<?php else : ?>
<?php echo Text::sprintf('JGLOBAL_LIST_ALIAS_NOTE', $this->escape($item->alias), $this->escape($item->note)); ?>
<?php endif; ?>
<?php elseif ($item->type == 'url' && $item->note) : ?>
<?php echo Text::sprintf('JGLOBAL_LIST_NOTE', $this->escape($item->note)); ?>
<?php endif; ?>
</span>
</div>
<div title="<?php echo $this->escape($item->path); ?>">
<?php echo $prefix; ?>
<span class="small"
title="<?php echo isset($item->item_type_desc) ? htmlspecialchars($this->escape($item->item_type_desc), ENT_COMPAT, 'UTF-8') : ''; ?>">
<?php echo $this->escape($item->item_type); ?>
</span>
</div>
<?php if ($item->type === 'component' && !$item->enabled) : ?>
<div>
<span class="badge bg-secondary">
<?php echo Text::_($item->enabled === null ? 'JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND' : 'COM_MENUS_LABEL_DISABLED'); ?>
</span>
</div>
<?php endif; ?>
</th>
<td class="small d-none d-md-table-cell">
<?php echo $this->escape($item->menutype_title ?: ucwords($item->menutype)); ?>
</td>
<?php if ($this->state->get('filter.client_id') == 0) : ?>
<td class="text-center d-none d-md-table-cell">
<?php if ($item->type == 'component') : ?>
<?php if ($item->language == '*' || $item->home == '0') : ?>
<?php echo HTMLHelper::_('jgrid.isdefault', $item->home, $i, 'items.', ($item->language != '*' || !$item->home) && $canChange && !$item->protected, 'cb', null, 'icon-home', 'icon-circle'); ?>
<?php elseif ($canChange) : ?>
<a href="<?php echo Route::_('index.php?option=com_menus&task=items.unsetDefault&cid[]=' . $item->id . '&' . Session::getFormToken() . '=1'); ?>">
<?php if ($item->language_image) : ?>
<?php echo HTMLHelper::_('image', 'mod_languages/' . $item->language_image . '.gif', $item->language_title, ['title' => Text::sprintf('COM_MENUS_GRID_UNSET_LANGUAGE', $item->language_title)], true); ?>
<?php else : ?>
<span class="badge bg-secondary"
title="<?php echo Text::sprintf('COM_MENUS_GRID_UNSET_LANGUAGE', $item->language_title); ?>"><?php echo $item->language; ?></span>
<?php endif; ?>
</a>
<?php else : ?>
<?php if ($item->language_image) : ?>
<?php echo HTMLHelper::_('image', 'mod_languages/' . $item->language_image . '.gif', $item->language_title, ['title' => $item->language_title], true); ?>
<?php else : ?>
<span class="badge bg-secondary"
title="<?php echo $item->language_title; ?>"><?php echo $item->language; ?></span>
<?php endif; ?>
<?php endif; ?>
<?php endif; ?>
</td>
<?php endif; ?>
<?php if ($this->state->get('filter.client_id') == 0) : ?>
<td class="small d-none d-md-table-cell">
<?php echo $this->escape($item->access_level); ?>
</td>
<?php endif; ?>
<?php if ($assoc) : ?>
<td class="small d-none d-md-table-cell">
<?php if ($item->association) : ?>
<?php echo HTMLHelper::_('menus.association', $item->id); ?>
<?php endif; ?>
</td>
<?php endif; ?>
<?php if ($this->state->get('filter.client_id') == 0 && Multilanguage::isEnabled()) : ?>
<td class="small d-none d-md-table-cell">
<?php echo LayoutHelper::render('joomla.content.language', $item); ?>
</td>
<?php endif; ?>
<td class="d-none d-md-table-cell">
<?php echo (int) $item->id; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php // load the pagination. ?>
<?php echo $this->pagination->getListFooter(); ?>
<?php // Load the batch processing form if user is allowed ?>
<?php if ($user->authorise('core.create', 'com_menus') || $user->authorise('core.edit', 'com_menus')) : ?>
<?php echo HTMLHelper::_(
'bootstrap.renderModal',
'collapseModal',
[
'title' => Text::_('COM_MENUS_BATCH_OPTIONS'),
'footer' => $this->loadTemplate('batch_footer')
],
$this->loadTemplate('batch_body')
); ?>
<?php endif; ?>
<?php endif; ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="boxchecked" value="0">
<?php echo HTMLHelper::_('form.token'); ?>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<layout title="COM_MENUS_ITEMS_VIEW_DEFAULT_TITLE">
<message>
<![CDATA[COM_MENUS_ITEMS_VIEW_DEFAULT_DESC]]>
</message>
</layout>
<fieldset name="request">
<fields name="request">
<field
name="menutype"
type="menu"
label="COM_MENUS_ITEMS_CHOOSE_MENU_LABEL"
description="COM_MENUS_ITEMS_CHOOSE_MENU_DESC"
clientid=""
>
<option value="">COM_MENUS_SELECT_MENU</option>
</field>
</fields>
</fieldset>
</metadata>

View File

@ -0,0 +1,88 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
$options = [
HTMLHelper::_('select.option', 'c', Text::_('JLIB_HTML_BATCH_COPY')),
HTMLHelper::_('select.option', 'm', Text::_('JLIB_HTML_BATCH_MOVE'))
];
$published = (int) $this->state->get('filter.published');
$clientId = (int) $this->state->get('filter.client_id');
$menuType = Factory::getApplication()->getUserState('com_menus.items.menutype', '');
if ($clientId == 1) {
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('com_menus.batch-body');
$wa->useScript('joomla.batch-copymove');
}
?>
<div class="p-3">
<?php if (strlen($menuType) && $menuType != '*') : ?>
<?php if ($clientId != 1) : ?>
<div class="row">
<?php if (Multilanguage::isEnabled()) : ?>
<div class="form-group col-md-6">
<div class="controls">
<?php echo LayoutHelper::render('joomla.html.batch.language', []); ?>
</div>
</div>
<?php endif; ?>
<div class="form-group col-md-6">
<div class="controls">
<?php echo LayoutHelper::render('joomla.html.batch.access', []); ?>
</div>
</div>
</div>
<?php endif; ?>
<div class="row">
<?php if ($published >= 0) : ?>
<div class="form-group col-md-6">
<div class="control-group">
<label id="batch-choose-action-lbl" for="batch-menu-id">
<?php echo Text::_('COM_MENUS_BATCH_MENU_LABEL'); ?>
</label>
<select class="form-select" name="batch[menu_id]" id="batch-menu-id">
<option value=""><?php echo Text::_('JLIB_HTML_BATCH_NO_CATEGORY'); ?></option>
<?php
$opts = [
'published' => $this->state->get('filter.published'),
'checkacl' => (int) $this->state->get('menutypeid'),
'clientid' => (int) $clientId,
];
echo HTMLHelper::_('select.options', HTMLHelper::_('menu.menuitems', $opts));
?>
</select>
</div>
<div id="batch-copy-move">
<?php echo Text::_('JLIB_HTML_BATCH_MOVE_QUESTION'); ?>
<?php echo HTMLHelper::_('select.radiolist', $options, 'batch[move_copy]', '', 'value', 'text', 'm'); ?>
</div>
</div>
<?php endif; ?>
<?php if ($published < 0 && $clientId == 1) : ?>
<p><?php echo Text::_('COM_MENUS_SELECT_MENU_FILTER_NOT_TRASHED'); ?></p>
<?php endif; ?>
</div>
<?php else : ?>
<div class="row">
<p><?php echo Text::_('COM_MENUS_SELECT_MENU_FIRST'); ?></p>
</div>
<?php endif; ?>
</div>

View File

@ -0,0 +1,27 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
$published = $this->state->get('filter.published');
$clientId = $this->state->get('filter.client_id');
$menuType = Factory::getApplication()->getUserState('com_menus.items.menutype', '');
?>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('batch-menu-id').value='';document.getElementById('batch-access').value='';document.getElementById('batch-language-id').value=''" data-bs-dismiss="modal">
<?php echo Text::_('JCANCEL'); ?>
</button>
<?php if ((strlen($menuType) && $menuType != '*' && $clientId == 0) || ($published >= 0 && $clientId == 1)) : ?>
<button type="submit" class="btn btn-success" onclick="Joomla.submitbutton('item.batch');return false;">
<?php echo Text::_('JGLOBAL_BATCH_PROCESS'); ?>
</button>
<?php endif; ?>

View File

@ -0,0 +1,194 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$app = Factory::getApplication();
if ($app->isClient('site')) {
Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
}
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('com_menus.admin-items-modal')->useScript('modal-content-select');
// @todo: Use of Function and Editor is deprecated and should be removed in 6.0. It stays only for backward compatibility.
$function = $app->getInput()->get('function', 'jSelectMenuItem', 'cmd');
$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';
$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';
}
?>
<div class="container-popup">
<form action="<?php echo Route::_($link); ?>" method="post" name="adminForm" id="adminForm">
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this, 'options' => ['selectorFieldName' => 'menutype']]); ?>
<?php if (empty($this->items)) : ?>
<div class="alert alert-info">
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
</div>
<?php else : ?>
<table class="table table-sm">
<caption class="visually-hidden">
<?php echo Text::_('COM_MENUS_ITEMS_TABLE_CAPTION'); ?>,
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
</caption>
<thead>
<tr>
<th scope="col" class="w-1 text-center">
<?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 'a.published', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="title">
<?php echo HTMLHelper::_('searchtools.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MENUS_HEADING_MENU', 'menutype_title', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-5 text-center d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MENUS_HEADING_HOME', 'a.home', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ACCESS', 'a.access', $listDirn, $listOrder); ?>
</th>
<?php if ($multilang) : ?>
<th scope="col" class="w-15 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_LANGUAGE', 'language', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<th scope="col" class="w-1 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->items as $i => $item) : ?>
<?php
$language = '';
if ($item->language && $multilang) {
if ($item->language !== '*') {
$language = $item->language;
}
}
$link = 'index.php?Itemid=' . $item->id;
$itemHtml = '<a href="' . $link . ($language ? '&lang=' . $language : '') . '">' . $item->title . '</a>';
$attribs = 'data-content-select data-content-type="com_menus.item"'
. 'data-function="' . $this->escape($function) . '"'
. ' data-id="' . $item->id . '"'
. ' data-title="' . $this->escape($item->title) . '"'
. ' data-uri="' . $this->escape($link) . '"'
. ' data-language="' . $this->escape($language) . '"'
. ' data-html="' . $this->escape($itemHtml) . '"';
?>
<tr class="row<?php echo $i % 2; ?>">
<td class="text-center">
<?php echo HTMLHelper::_('jgrid.published', $item->published, $i, 'items.', false, 'cb', $item->publish_up, $item->publish_down); ?>
</td>
<th scope="row">
<?php $prefix = LayoutHelper::render('joomla.html.treeprefix', ['level' => $item->level]); ?>
<?php echo $prefix; ?>
<a class="select-link" href="javascript:void(0)" <?php echo $attribs; ?>>
<?php echo $this->escape($item->title); ?>
</a>
<?php echo HTMLHelper::_('menus.visibility', $item->params); ?>
<div>
<?php echo $prefix; ?>
<span class="small">
<?php if (empty($item->note)) : ?>
<?php echo Text::sprintf('JGLOBAL_LIST_ALIAS', $this->escape($item->alias)); ?>
<?php else : ?>
<?php echo Text::sprintf('JGLOBAL_LIST_ALIAS_NOTE', $this->escape($item->alias), $this->escape($item->note)); ?>
<?php endif; ?>
</span>
</div>
<div title="<?php echo $this->escape($item->path); ?>">
<?php echo $prefix; ?>
<span class="small" title="<?php echo isset($item->item_type_desc) ? htmlspecialchars($this->escape($item->item_type_desc), ENT_COMPAT, 'UTF-8') : ''; ?>">
<?php echo $this->escape($item->item_type); ?>
</span>
</div>
<?php if ($item->type === 'component' && !$item->enabled) : ?>
<div>
<span class="badge bg-secondary">
<?php echo Text::_($item->enabled === null ? 'JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND' : 'COM_MENUS_LABEL_DISABLED'); ?>
</span>
</div>
<?php endif; ?>
</th>
<td class="small d-none d-md-table-cell">
<?php echo $this->escape($item->menutype_title); ?>
</td>
<td class="text-center d-none d-md-table-cell">
<?php if ($item->type == 'component') : ?>
<?php if ($item->language == '*' || $item->home == '0') : ?>
<?php echo HTMLHelper::_('jgrid.isdefault', $item->home, $i, 'items.', ($item->language != '*' || !$item->home) && false && !$item->protected, 'cb', null, 'home', 'circle'); ?>
<?php else : ?>
<?php if ($item->language_image) : ?>
<?php echo HTMLHelper::_('image', 'mod_languages/' . $item->language_image . '.gif', $item->language_title, ['title' => $item->language_title], true); ?>
<?php else : ?>
<span class="badge bg-secondary" title="<?php echo $item->language_title; ?>"><?php echo $item->language; ?></span>
<?php endif; ?>
<?php endif; ?>
<?php endif; ?>
</td>
<td class="small d-none d-md-table-cell">
<?php echo $this->escape($item->access_level); ?>
</td>
<?php if ($multilang) : ?>
<td class="small d-none d-md-table-cell">
<?php if ($item->language == '') : ?>
<?php echo Text::_('COM_MENUS_HOME'); ?>
<?php elseif ($item->language == '*') : ?>
<?php echo Text::alt('JALL', 'language'); ?>
<?php else : ?>
<?php echo LayoutHelper::render('joomla.content.language', $item); ?>
<?php endif; ?>
</td>
<?php endif; ?>
<td class="d-none d-md-table-cell">
<?php echo (int) $item->id; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php // load the pagination. ?>
<?php echo $this->pagination->getListFooter(); ?>
<?php endif; ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="boxchecked" value="0">
<input type="hidden" name="function" value="<?php echo $function; ?>">
<input type="hidden" name="forcedLanguage" value="<?php echo $app->getInput()->get('forcedLanguage', '', 'cmd'); ?>">
<?php echo HTMLHelper::_('form.token'); ?>
</form>
</div>

View File

@ -0,0 +1,70 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('core')
->useScript('keepalive')
->useScript('form.validate');
Text::script('ERROR');
?>
<form action="<?php echo Route::_('index.php?option=com_menus&layout=edit&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="item-form" aria-label="<?php echo Text::_('COM_MENUS_MENU_FORM_' . ((int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>" class="form-validate">
<?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?>
<div class="main-card">
<?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'details', 'recall' => true, 'breakpoint' => 768]); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'details', Text::_('COM_MENUS_MENU_DETAILS')); ?>
<fieldset id="fieldset-details" class="options-form">
<legend><?php echo Text::_('COM_MENUS_MENU_DETAILS'); ?></legend>
<div>
<div>
<?php
echo $this->form->renderField('menutype');
echo $this->form->renderField('description');
echo $this->form->renderField('client_id');
echo $this->form->renderField('preset');
?>
</div>
</div>
</fieldset>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php if ($this->canDo->get('core.admin')) : ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'permissions', Text::_('COM_MENUS_FIELDSET_RULES')); ?>
<fieldset id="fieldset-rules" class="options-form">
<legend><?php echo Text::_('COM_MENUS_FIELDSET_RULES'); ?></legend>
<div>
<?php echo $this->form->getInput('rules'); ?>
</div>
</fieldset>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php endif; ?>
<?php echo HTMLHelper::_('uitab.endTabSet'); ?>
<input type="hidden" name="task" value="">
<?php echo HTMLHelper::_('form.token'); ?>
</div>
</form>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<layout title="COM_MENUS_MENU_VIEW_EDIT_TITLE">
<message>
<![CDATA[COM_MENUS_MENU_VIEW_EDIT_DESC]]>
</message>
</layout>
</metadata>

View File

@ -0,0 +1,300 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('table.columns')
->useScript('multiselect')
->useScript('com_menus.admin-menus');
$uri = Uri::getInstance();
$return = base64_encode($uri);
$user = $this->getCurrentUser();
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$modMenuId = (int) $this->get('ModMenuId');
$itemIds = [];
foreach ($this->items as $item) {
if ($user->authorise('core.edit', 'com_menus')) {
$itemIds[] = $item->id;
}
}
$saveOrder = $listOrder == 'a.ordering';
if ($saveOrder) {
$saveOrderingUrl = 'index.php?option=com_menus&task=menus.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1';
HTMLHelper::_('draggablelist.draggable');
}
$this->document->addScriptOptions('menus-default', ['items' => $itemIds]);
?>
<form action="<?php echo Route::_('index.php?option=com_menus&view=menus'); ?>" method="post" name="adminForm" id="adminForm">
<div class="row">
<div class="col-md-12">
<div id="j-main-container" class="j-main-container">
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this, 'options' => ['filterButton' => false]]); ?>
<?php if (empty($this->items)) : ?>
<div class="alert alert-info">
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
</div>
<?php else : ?>
<table class="table" id="menuList">
<caption class="visually-hidden">
<?php echo Text::_('COM_MENUS_MENUS_TABLE_CAPTION'); ?>,
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
</caption>
<thead>
<tr>
<td class="w-1 text-center">
<?php echo HTMLHelper::_('grid.checkall'); ?>
</td>
<th scope="col" class="w-1 text-center d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', '', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-sort'); ?>
</th>
<th scope="col">
<?php echo HTMLHelper::_('searchtools.sort', 'JGLOBAL_TITLE', 'a.title', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-5 text-center">
<?php echo Text::_('COM_MENUS_MENUS'); ?>
</th>
<th scope="col" class="w-10 text-center d-none d-md-table-cell">
<span class="icon-check" aria-hidden="true"></span>
<span class="d-none d-md-inline"><?php echo Text::_('COM_MENUS_HEADING_PUBLISHED_ITEMS'); ?></span>
</th>
<th scope="col" class="w-10 text-center d-none d-md-table-cell">
<span class="icon-times" aria-hidden="true"></span>
<span class="d-none d-md-inline"><?php echo Text::_('COM_MENUS_HEADING_UNPUBLISHED_ITEMS'); ?></span>
</th>
<th scope="col" class="w-10 text-center d-none d-md-table-cell">
<span class="icon-trash" aria-hidden="true"></span>
<span class="d-none d-md-inline"><?php echo Text::_('COM_MENUS_HEADING_TRASHED_ITEMS'); ?></span>
</th>
<th scope="col" class="w-10 text-center d-none d-lg-table-cell">
<span class="icon-cube" aria-hidden="true"></span>
<span class="d-none d-md-inline"><?php echo Text::_('COM_MENUS_HEADING_LINKED_MODULES'); ?></span>
</th>
<th scope="col" class="w-5 d-none d-lg-table-cell text-center">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tbody <?php if ($saveOrder) :
?> class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>" data-nested="false"<?php
endif; ?>>
<?php foreach ($this->items as $i => $item) :
$ordering = ($listOrder == 'a.ordering');
$canEdit = $user->authorise('core.edit', 'com_menus.menu.' . (int) $item->id);
$canManageItems = $user->authorise('core.manage', 'com_menus.menu.' . (int) $item->id);
$canChange = $user->authorise('core.edit.state', 'com_menus.menu.' . (int) $item->id);
?>
<tr class="row<?php echo $i % 2; ?>" data-draggable-group="0">
<td class="text-center">
<?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', $item->title); ?>
</td>
<td class="text-center d-none d-md-table-cell">
<?php
$iconClass = '';
if (!$canChange) {
$iconClass = ' inactive';
} elseif (!$saveOrder) {
$iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED');
}
?>
<span class="sortable-handler<?php echo $iconClass; ?>">
<span class="icon-ellipsis-v" aria-hidden="true"></span>
</span>
<?php if ($canChange && $saveOrder) : ?>
<input type="text" name="order[]" size="5" value="<?php echo $item->ordering; ?>" class="width-20 text-area-order hidden">
<?php endif; ?>
</td>
<th scope="row">
<div class="name break-word">
<?php if ($canEdit) : ?>
<a href="<?php echo Route::_('index.php?option=com_menus&task=menu.edit&id=' . $item->id); ?>">
<span class="visually-hidden"><?php echo Text::_('COM_MENUS_EDIT_MENU'); ?></span><?php echo $this->escape($item->title); ?>
</a>
<?php else : ?>
<?php echo $this->escape($item->title); ?>
<?php endif; ?>
<?php if (!empty($item->description)) : ?>
<div class="small">
(<?php echo $this->escape($item->description); ?>)
</div>
<?php endif; ?>
</div>
</th>
<td class="text-center btns">
<?php if ($canManageItems) : ?>
<a href="<?php echo Route::_('index.php?option=com_menus&view=items&menutype=' . $item->menutype); ?>">
<span class="icon-list" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('COM_MENUS_MENUS'); ?></span>
</a>
<?php endif; ?>
</td>
<td class="text-center btns d-none d-md-table-cell itemnumber">
<?php if ($canManageItems) : ?>
<a class="btn<?php echo ($item->count_published > 0) ? ' btn-success' : ' btn-secondary'; ?>"
href="<?php echo Route::_('index.php?option=com_menus&view=items&menutype=' . $item->menutype . '&filter[published]=1'); ?>"
aria-describedby="tip-publish<?php echo $i; ?>">
<?php echo $item->count_published; ?>
</a>
<?php else : ?>
<span class="btn<?php echo ($item->count_published > 0) ? ' btn-success' : ' btn-secondary'; ?>" tabindex="0"
aria-describedby="tip-publish<?php echo $i; ?>">
<?php echo $item->count_published; ?>
</span>
<?php endif; ?>
<div role="tooltip" id="tip-publish<?php echo $i; ?>">
<?php echo Text::_('COM_MENUS_COUNT_PUBLISHED_ITEMS'); ?>
</div>
</td>
<td class="text-center btns d-none d-md-table-cell itemnumber">
<?php if ($canManageItems) : ?>
<a class="btn<?php echo ($item->count_unpublished > 0) ? ' btn-danger' : ' btn-secondary'; ?>"
href="<?php echo Route::_('index.php?option=com_menus&view=items&menutype=' . $item->menutype . '&filter[published]=0'); ?>"
aria-describedby="tip-unpublish<?php echo $i; ?>">
<?php echo $item->count_unpublished; ?>
</a>
<?php else : ?>
<span class="btn<?php echo ($item->count_unpublished > 0) ? ' btn-danger' : ' btn-secondary'; ?>" tabindex="0"
aria-describedby="tip-unpublish<?php echo $i; ?>">
<?php echo $item->count_unpublished; ?>
</span>
<?php endif; ?>
<div role="tooltip" id="tip-unpublish<?php echo $i; ?>">
<?php echo Text::_('COM_MENUS_COUNT_UNPUBLISHED_ITEMS'); ?>
</div>
</td>
<td class="text-center btns d-none d-md-table-cell itemnumber">
<?php if ($canManageItems) : ?>
<a class="btn<?php echo ($item->count_trashed > 0) ? ' btn-danger' : ' btn-secondary'; ?>"
href="<?php echo Route::_('index.php?option=com_menus&view=items&menutype=' . $item->menutype . '&filter[published]=-2'); ?>"
aria-describedby="tip-trash<?php echo $i; ?>">
<?php echo $item->count_trashed; ?>
</a>
<?php else : ?>
<span class="btn<?php echo ($item->count_trashed > 0) ? ' btn-danger' : ' btn-secondary'; ?>" tabindex="0"
aria-describedby="tip-trash<?php echo $i; ?>">
<?php echo $item->count_trashed; ?>
</span>
<?php endif; ?>
<div role="tooltip" id="tip-trash<?php echo $i; ?>">
<?php echo Text::_('COM_MENUS_COUNT_TRASHED_ITEMS'); ?>
</div>
</td>
<td class="text-center d-none d-lg-table-cell itemnumber">
<?php if (isset($this->modules[$item->menutype])) : ?>
<div class="dropdown">
<button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown">
<?php echo Text::_('COM_MENUS_MODULES'); ?>
<span class="caret"></span>
</button>
<div class="dropdown-menu dropdown-menu-end">
<?php foreach ($this->modules[$item->menutype] as &$module) : ?>
<?php if ($user->authorise('core.edit', 'com_modules.module.' . (int) $module->id)) : ?>
<?php $link = Route::_('index.php?option=com_modules&task=module.edit&id=' . $module->id . '&return=' . $return . '&tmpl=component&layout=modal'); ?>
<button type="button" class="dropdown-item" data-bs-target="#moduleEdit<?php echo $module->id; ?>Modal" data-bs-toggle="modal" title="<?php echo Text::_('COM_MENUS_EDIT_MODULE_SETTINGS'); ?>">
<?php echo Text::sprintf('COM_MENUS_MODULE_ACCESS_POSITION', $this->escape($module->title), $this->escape($module->access_title), $this->escape($module->position)); ?></button>
<?php else : ?>
<span class="dropdown-item"><?php echo Text::sprintf('COM_MENUS_MODULE_ACCESS_POSITION', $this->escape($module->title), $this->escape($module->access_title), $this->escape($module->position)); ?></span>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php foreach ($this->modules[$item->menutype] as &$module) : ?>
<?php if ($user->authorise('core.edit', 'com_modules.module.' . (int) $module->id)) : ?>
<?php $link = Route::_('index.php?option=com_modules&task=module.edit&id=' . $module->id . '&return=' . $return . '&tmpl=component&layout=modal'); ?>
<?php echo HTMLHelper::_(
'bootstrap.renderModal',
'moduleEdit' . $module->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' => '<button type="button" class="btn btn-danger" data-bs-dismiss="modal"'
. ' onclick="Joomla.iframeButtonClick({iframeSelector: \'#moduleEdit' . $module->id . 'Modal\', buttonSelector: \'#closeBtn\'})">'
. Text::_('JLIB_HTML_BEHAVIOR_CLOSE') . '</button>'
. '<button type="button" class="btn btn-success"'
. ' onclick="Joomla.iframeButtonClick({iframeSelector: \'#moduleEdit' . $module->id . 'Modal\', buttonSelector: \'#saveBtn\'})">'
. Text::_('JSAVE') . '</button>'
. '<button type="button" class="btn btn-success"'
. ' onclick="Joomla.iframeButtonClick({iframeSelector: \'#moduleEdit' . $module->id . 'Modal\', buttonSelector: \'#applyBtn\'})">'
. Text::_('JAPPLY') . '</button>',
]
); ?>
<?php endif; ?>
<?php endforeach; ?>
<?php elseif ($modMenuId) : ?>
<?php $link = Route::_('index.php?option=com_modules&task=module.add&eid=' . $modMenuId . '&params[menutype]=' . $item->menutype . '&tmpl=component&layout=modal'); ?>
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#moduleAddModal"><?php echo Text::_('COM_MENUS_ADD_MENU_MODULE'); ?></button>
<?php echo HTMLHelper::_(
'bootstrap.renderModal',
'moduleAddModal',
[
'title' => Text::_('COM_MENUS_ADD_MENU_MODULE'),
'backdrop' => 'static',
'keyboard' => false,
'closeButton' => false,
'url' => $link,
'height' => '400px',
'width' => '800px',
'bodyHeight' => 70,
'modalWidth' => 80,
'footer' => '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"'
. ' onclick="Joomla.iframeButtonClick({iframeSelector: \'#moduleAddModal\', buttonSelector: \'#closeBtn\'})">'
. Text::_('JLIB_HTML_BEHAVIOR_CLOSE') . '</button>'
. '<button type="button" class="btn btn-primary"'
. ' onclick="Joomla.iframeButtonClick({iframeSelector: \'#moduleAddModal\', buttonSelector: \'#saveBtn\'})">'
. Text::_('JSAVE') . '</button>'
. '<button type="button" class="btn btn-success"'
. ' onclick="Joomla.iframeButtonClick({iframeSelector: \'#moduleAddModal\', buttonSelector: \'#applyBtn\'})">'
. Text::_('JAPPLY') . '</button>',
]
); ?>
<?php endif; ?>
</td>
<td class="d-none d-lg-table-cell">
<?php echo $item->id; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php // load the pagination. ?>
<?php echo $this->pagination->getListFooter(); ?>
<?php endif; ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="boxchecked" value="0">
<?php echo HTMLHelper::_('form.token'); ?>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<layout title="COM_MENUS_MENUS_VIEW_DEFAULT_TITLE">
<message>
<![CDATA[COM_MENUS_MENUS_VIEW_DEFAULT_DESC]]>
</message>
</layout>
</metadata>

View File

@ -0,0 +1,67 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_menus
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Session\Session;
$input = Factory::getApplication()->getInput();
// Checking if loaded via index.php or component.php
$tmpl = $input->getCmd('tmpl') ? '1' : '';
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('com_menus.admin-item-modal');
if ($tmpl) {
$wa->useScript('modal-content-select');
}
?>
<?php echo HTMLHelper::_('bootstrap.startAccordion', 'collapseTypes', ['active' => 'slide1']); ?>
<?php $i = 0; ?>
<?php foreach ($this->types as $name => $list) : ?>
<?php echo HTMLHelper::_('bootstrap.addSlide', 'collapseTypes', $name, 'collapse' . ($i++)); ?>
<div class="list-group">
<?php foreach ($list as $title => $item) :
$menutype = ['id' => $this->recordId, 'title' => $item->type ?? $item->title, 'request' => $item->request];
$encoded = base64_encode(json_encode($menutype));
if ($tmpl) {
$attrs = 'data-content-select data-content-type="com_menus.menutype" data-message-type="joomla:content-select-menutype"'
. ' data-item-id="' . (int) $this->recordId . '"'
. ' data-type="' . $this->escape($item->type ?? $item->title) . '"'
. ' data-request="' . ($item->request ? $this->escape(json_encode($item->request)) : '') . '"'
. ' data-encoded="' . $this->escape($encoded) . '"';
$link = '#';
} else {
$attrs = '';
$link = $this->escape('index.php?option=com_menus&view=item&task=item.setType&layout=edit&type=' . $encoded . '&' . Session::getFormToken() . '=1');
}
?>
<a href="<?php echo $link; ?>" class="choose_type list-group-item list-group-item-action" <?php echo $attrs; ?>>
<div class="pe-2">
<?php echo $title; ?>
</div>
<small class="text-muted">
<?php echo Text::_($item->description); ?>
</small>
</a>
<?php endforeach; ?>
</div>
<?php echo HTMLHelper::_('bootstrap.endSlide'); ?>
<?php endforeach; ?>
<?php echo HTMLHelper::_('bootstrap.endSlide'); ?>
<?php echo HTMLHelper::_('bootstrap.endAccordion');