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,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<access component="com_modules">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" />
<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" />
<action name="module.edit.frontend" title="COM_MODULES_ACTION_EDITFRONTEND" />
</section>
<section name="module">
<action name="core.delete" title="JACTION_DELETE" />
<action name="core.edit" title="JACTION_EDIT" />
<action name="core.edit.state" title="JACTION_EDITSTATE" />
<action name="module.edit.frontend" title="COM_MODULES_ACTION_EDITFRONTEND" />
</section>
</access>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<help key="Modules:_Options"/>
<inlinehelp button="show"/>
<fieldset
name="modules"
label="COM_MODULES_GENERAL"
description="COM_MODULES_GENERAL_FIELDSET_DESC"
>
<field
name="redirect_edit"
type="list"
class="advancedSelect"
default="site"
label="COM_MODULES_REDIRECT_EDIT_LABEL"
description="COM_MODULES_REDIRECT_EDIT_DESC"
validate="options"
>
<option value="admin">JADMINISTRATOR</option>
<option value="site">JSITE</option>
</field>
</fieldset>
<fieldset
name="admin_modules"
label="COM_MODULES_ADMIN_LANG_FILTER_FIELDSET_LABEL"
>
<field
name="adminlangfilter"
type="radio"
label="COM_MODULES_ADMIN_LANG_FILTER_LABEL"
description="COM_MODULES_ADMIN_LANG_FILTER_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</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_modules"
section="component"
/>
</fieldset>
</config>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset
name="advanced">
<field
name="module_tag"
type="moduletag"
label="COM_MODULES_FIELD_MODULE_TAG_LABEL"
default="div"
validate="options"
/>
<field
name="bootstrap_size"
type="integer"
label="COM_MODULES_FIELD_BOOTSTRAP_SIZE_LABEL"
first="0"
last="12"
step="1"
/>
<field
name="header_tag"
type="headertag"
label="COM_MODULES_FIELD_HEADER_TAG_LABEL"
default="h3"
validate="options"
/>
<field
name="header_class"
type="textarea"
label="COM_MODULES_FIELD_HEADER_CLASS_LABEL"
rows="3"
validate="CssIdentifier"
/>
<field
name="style"
type="chromestyle"
label="COM_MODULES_FIELD_MODULE_STYLE_LABEL"
/>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<form addfieldprefix="Joomla\Component\Modules\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>
<fields name="filter">
<field
name="search"
type="text"
inputmode="search"
label="COM_MODULES_MODULES_FILTER_SEARCH_LABEL"
description="COM_MODULES_MODULES_FILTER_SEARCH_DESC"
hint="JSEARCH_FILTER"
noresults="COM_MODULES_MSG_MANAGE_NO_MODULES"
/>
<field
name="state"
type="status"
label="JSTATUS"
optionsFilter="*,-2,0,1"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_PUBLISHED</option>
</field>
<field
name="position"
type="ModulesPosition"
label="COM_MODULES_FIELD_POSITION_LABEL"
client="site"
class="js-select-submit-on-change"
>
<option value="">COM_MODULES_OPTION_SELECT_POSITION</option>
</field>
<field
name="module"
type="ModulesModule"
label="COM_MODULES_HEADING_MODULE"
client="site"
class="js-select-submit-on-change"
>
<option value="">COM_MODULES_OPTION_SELECT_MODULE</option>
</field>
<field
name="menuitem"
type="menuitem"
label="JGLOBAL_MENU_SELECTION"
disable="separator,alias,heading,url"
class="js-select-submit-on-change"
>
<option value="">COM_MODULES_OPTION_SELECT_MENU_ITEM</option>
<option value="-1">COM_MODULES_NONE</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>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
statuses="*,0,1,-2"
class="js-select-submit-on-change"
default="a.position 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.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="a.position ASC">COM_MODULES_HEADING_POSITION_ASC</option>
<option value="a.position DESC">COM_MODULES_HEADING_POSITION_DESC</option>
<option value="name ASC">COM_MODULES_HEADING_MODULE_ASC</option>
<option value="name DESC">COM_MODULES_HEADING_MODULE_DESC</option>
<option value="pages ASC">COM_MODULES_HEADING_PAGES_ASC</option>
<option value="pages DESC">COM_MODULES_HEADING_PAGES_DESC</option>
<option value="ag.title ASC">JGRID_HEADING_ACCESS_ASC</option>
<option value="ag.title DESC">JGRID_HEADING_ACCESS_DESC</option>
<option value="l.title ASC" requires="multilanguage">JGRID_HEADING_LANGUAGE_ASC</option>
<option value="l.title 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,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset addfieldprefix="Joomla\Component\Modules\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>
<fields name="filter">
<field
name="search"
type="text"
inputmode="search"
label="COM_MODULES_MODULES_FILTER_SEARCH_LABEL"
description="COM_MODULES_MODULES_FILTER_SEARCH_DESC"
hint="JSEARCH_FILTER"
noresults="COM_MODULES_MSG_MANAGE_NO_MODULES"
/>
<field
name="state"
type="status"
label="JSTATUS"
optionsFilter="*,-2,0,1"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_PUBLISHED</option>
</field>
<field
name="position"
type="ModulesPosition"
label="COM_MODULES_FIELD_POSITION_LABEL"
client="administrator"
class="js-select-submit-on-change"
>
<option value="">COM_MODULES_OPTION_SELECT_POSITION</option>
</field>
<field
name="module"
type="ModulesModule"
label="COM_MODULES_HEADING_MODULE"
client="administrator"
class="js-select-submit-on-change"
>
<option value="">COM_MODULES_OPTION_SELECT_MODULE</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="language"
label="JGRID_HEADING_LANGUAGE"
client="administrator"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_LANGUAGE</option>
<option value="*">JALL</option>
</field>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
statuses="*,0,1,-2"
class="js-select-submit-on-change"
default="a.position 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.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="a.position ASC">COM_MODULES_HEADING_POSITION_ASC</option>
<option value="a.position DESC">COM_MODULES_HEADING_POSITION_DESC</option>
<option value="name ASC">COM_MODULES_HEADING_MODULE_ASC</option>
<option value="name DESC">COM_MODULES_HEADING_MODULE_DESC</option>
<option value="ag.title ASC">JGRID_HEADING_ACCESS_ASC</option>
<option value="ag.title DESC">JGRID_HEADING_ACCESS_DESC</option>
<option value="a.language ASC" requires="adminlanguage">JGRID_HEADING_LANGUAGE_ASC</option>
<option value="a.language DESC" requires="adminlanguage">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,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<config>
<inlinehelp button="show"/>
</config>
<fieldset addfieldprefix="Joomla\Component\Modules\Administrator\Field">
<field
name="id"
type="number"
label="JGLOBAL_FIELD_ID_LABEL"
default="0"
readonly="true"
/>
<field
name="title"
type="text"
label="JGLOBAL_TITLE"
maxlength="100"
required="true"
/>
<field
name="note"
type="text"
label="COM_MODULES_FIELD_NOTE_LABEL"
maxlength="255"
/>
<field
name="module"
type="hidden"
label="COM_MODULES_FIELD_MODULE_LABEL"
readonly="readonly"
/>
<field
name="showtitle"
type="radio"
label="COM_MODULES_FIELD_SHOWTITLE_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="published"
type="list"
label="JSTATUS"
class="form-select-color-state"
default="1"
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="COM_MODULES_FIELD_PUBLISH_UP_LABEL"
filter="user_utc"
translateformat="true"
showtime="true"
/>
<field
name="publish_down"
type="calendar"
label="COM_MODULES_FIELD_PUBLISH_DOWN_LABEL"
filter="user_utc"
translateformat="true"
showtime="true"
/>
<field
name="client_id"
type="hidden"
label="COM_MODULES_FIELD_CLIENT_ID_LABEL"
readonly="true"
/>
<field
name="position"
type="ModulesPositionedit"
label="COM_MODULES_FIELD_POSITION_LABEL"
default=""
maxlength="50"
client="site"
/>
<field
name="access"
type="accesslevel"
label="JFIELD_ACCESS_LABEL"
filter="UINT"
validate="options"
/>
<field
name="ordering"
type="moduleorder"
label="JFIELD_ORDERING_LABEL"
linked="position"
/>
<field
name="content"
type="editor"
label="COM_MODULES_FIELD_CONTENT_LABEL"
buttons="true"
filter="\Joomla\CMS\Component\ComponentHelper::filterText"
hide="readmore,pagebreak,module"
/>
<field
name="language"
type="contentlanguage"
label="JFIELD_LANGUAGE_LABEL"
>
<option value="*">JALL</option>
</field>
<field
name="assignment"
type="hidden"
/>
<field
name="assigned"
type="hidden"
/>
<field
name="asset_id"
type="hidden"
filter="unset"
/>
<field
name="rules"
type="rules"
label="JFIELD_RULES_LABEL"
translate_label="false"
filter="rules"
component="com_modules"
section="module"
validate="rules"
/>
</fieldset>
</form>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<config>
<inlinehelp button="show"/>
</config>
<fieldset addfieldprefix="Joomla\Component\Modules\Administrator\Field">
<field
name="id"
type="number"
label="JGLOBAL_FIELD_ID_LABEL"
default="0"
readonly="true"
/>
<field
name="title"
type="text"
label="JGLOBAL_TITLE"
maxlength="100"
required="true"
/>
<field
name="note"
type="text"
label="COM_MODULES_FIELD_NOTE_LABEL"
maxlength="255"
/>
<field
name="module"
type="hidden"
label="COM_MODULES_FIELD_MODULE_LABEL"
readonly="readonly"
/>
<field
name="showtitle"
type="radio"
label="COM_MODULES_FIELD_SHOWTITLE_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="published"
type="list"
label="JSTATUS"
class="form-select-color-state"
default="1"
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="COM_MODULES_FIELD_PUBLISH_UP_LABEL"
filter="user_utc"
translateformat="true"
showtime="true"
/>
<field
name="publish_down"
type="calendar"
label="COM_MODULES_FIELD_PUBLISH_DOWN_LABEL"
filter="user_utc"
translateformat="true"
showtime="true"
/>
<field
name="client_id"
type="hidden"
label="COM_MODULES_FIELD_CLIENT_ID_LABEL"
readonly="true"
/>
<field
name="position"
type="ModulesPositionedit"
label="COM_MODULES_FIELD_POSITION_LABEL"
default=""
maxlength="50"
client="administrator"
/>
<field
name="access"
type="accesslevel"
label="JFIELD_ACCESS_LABEL"
filter="UINT"
validate="options"
/>
<field
name="ordering"
type="moduleorder"
label="JFIELD_ORDERING_LABEL"
linked="position"
/>
<field
name="language"
type="language"
label="JFIELD_LANGUAGE_LABEL"
default="*"
client="administrator"
>
<option value="*">JALL</option>
</field>
<field
name="content"
type="editor"
label="COM_MODULES_FIELD_CONTENT_LABEL"
buttons="true"
filter="\Joomla\CMS\Component\ComponentHelper::filterText"
hide="readmore,pagebreak,module,menu,fields,contact,article"
/>
<field name="assignment" type="hidden" />
<field name="assigned" type="hidden" />
<field name="asset_id" type="hidden"
filter="unset"
/>
<field
name="rules"
type="rules"
label="JFIELD_RULES_LABEL"
translate_label="false"
filter="rules"
component="com_modules"
section="module"
validate="rules"
/>
</fieldset>
</form>

View File

@ -0,0 +1,27 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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
/**
* Modules component helper.
*
* @since 1.6
*
* @deprecated 4.3 will be removed in 6.0
* Use \Joomla\Component\Modules\Administrator\Helper\ModulesHelper instead
*/
abstract class ModulesHelper extends \Joomla\Component\Modules\Administrator\Helper\ModulesHelper
{
}

View File

@ -0,0 +1,87 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Factory;
use Joomla\CMS\HTML\HTMLHelper;
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 array $checkedOptions Options that will be set as checked.
* @var boolean $hasValue Has this field a value assigned?
* @var array $options Options available for this field.
* @var array $inputType Options available for this field.
* @var string $accept File types that are accepted.
* @var array $positions Array of the positions
*/
$attributes = [
'class="' . $class . '"',
' allow-custom',
' search-placeholder="' . $this->escape(Text::_('COM_MODULES_TYPE_OR_SELECT_POSITION')) . '" ',
];
$selectAttr = [
$disabled ? 'disabled' : '',
$readonly ? 'readonly' : '',
strlen($hint) ? 'placeholder="' . $this->escape($hint) . '"' : '',
$onchange ? ' onchange="' . $onchange . '"' : '',
$autofocus ? ' autofocus' : '',
];
if ($required) {
$selectAttr[] = ' required class="required"';
$attributes[] = ' required';
}
Text::script('JGLOBAL_SELECT_NO_RESULTS_MATCH');
Text::script('JGLOBAL_SELECT_PRESS_TO_SELECT');
Factory::getDocument()->getWebAssetManager()
->usePreset('choicesjs')
->useScript('webcomponent.field-fancy-select');
?>
<joomla-field-fancy-select <?php echo implode(' ', $attributes); ?>><?php
echo HTMLHelper::_('select.groupedlist', $positions, $name, [
'id' => $id,
'list.select' => $value,
'list.attr' => implode(' ', $selectAttr),
]);
?></joomla-field-fancy-select>

View File

@ -0,0 +1,21 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Language\Text;
$text = Text::_('JTOOLBAR_CANCEL');
?>
<joomla-toolbar-button>
<button onclick="location.href='index.php?option=com_modules&view=modules&client_id=<?php echo $displayData['client_id']; ?>'" class="btn btn-danger">
<span class="icon-times" aria-hidden="true"></span> <?php echo $text; ?>
</button>
</joomla-toolbar-button>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="component" method="upgrade">
<name>com_modules</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_MODULES_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Component\Modules</namespace>
<files folder="site">
<folder>forms</folder>
<folder>src</folder>
</files>
<media destination="com_modules" folder="media">
<folder>js</folder>
</media>
<administration>
<files folder="admin">
<filename>access.xml</filename>
<filename>config.xml</filename>
<filename>modules.xml</filename>
<folder>forms</folder>
<folder>helpers</folder>
<folder>layouts</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
<languages folder="admin">
<language tag="en-GB">language/en-GB/com_modules.ini</language>
<language tag="en-GB">language/en-GB/com_modules.sys.ini</language>
</languages>
</administration>
</extension>

View File

@ -0,0 +1,55 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\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\Modules\Administrator\Extension\ModulesComponent;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
/**
* The module 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->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Modules'));
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Modules'));
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new ModulesComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
$component->setRegistry($container->get(Registry::class));
return $component;
}
);
}
};

View File

@ -0,0 +1,87 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\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
/**
* Modules manager display controller.
*
* @since 1.6
*/
class DisplayController extends BaseController
{
/**
* The default view.
*
* @var string
* @since 1.6
*/
protected $default_view = 'modules';
/**
* 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|boolean This object to support chaining or false on failure.
*
* @since 1.5
*/
public function display($cachable = false, $urlparams = false)
{
$layout = $this->input->get('layout', 'edit');
$id = $this->input->getInt('id');
// Verify client
$clientId = $this->input->post->getInt('client_id');
if (!\is_null($clientId)) {
$uri = Uri::getInstance();
if ((int) $uri->getVar('client_id') !== (int) $clientId) {
$this->setRedirect(Route::_('index.php?option=com_modules&view=modules&client_id=' . $clientId, false));
return false;
}
}
// Check for edit form.
if ($layout == 'edit' && !$this->checkEditId('com_modules.edit.module', $id)) {
// Somehow the person just went to the form - we don't allow that.
if (!\count($this->app->getMessageQueue())) {
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 'error');
}
$this->setRedirect(Route::_('index.php?option=com_modules&view=modules&client_id=' . $this->input->getInt('client_id'), false));
return false;
}
// Check if we have a mod_menu module set to All languages or a mod_menu module for each admin language.
$factory = $this->app->bootComponent('menus')->getMVCFactory();
if ($langMissing = $factory->createModel('Menus', 'Administrator')->getMissingModuleLanguages()) {
$this->app->enqueueMessage(Text::sprintf('JMENU_MULTILANG_WARNING_MISSING_MODULES', implode(', ', $langMissing)), 'warning');
}
return parent::display();
}
}

View File

@ -0,0 +1,348 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\Controller;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Module controller class.
*
* @since 1.6
*/
class ModuleController extends FormController
{
/**
* Override parent add method.
*
* @return \Exception|void True if the record can be added, a \Exception object if not.
*
* @since 1.6
*/
public function add()
{
$app = $this->app;
// Get the result of the parent method. If an error, just return it.
$result = parent::add();
if ($result instanceof \Exception) {
return $result;
}
// Look for the Extension ID.
$extensionId = $this->input->get('eid', 0, 'int');
if (empty($extensionId)) {
$redirectUrl = 'index.php?option=' . $this->option . '&view=' . $this->view_item . '&layout=edit';
$this->setRedirect(Route::_($redirectUrl, false));
$app->enqueueMessage(Text::_('COM_MODULES_ERROR_INVALID_EXTENSION'), 'warning');
}
$app->setUserState('com_modules.add.module.extension_id', $extensionId);
$app->setUserState('com_modules.add.module.params', null);
// Parameters could be coming in for a new item, so let's set them.
$params = $this->input->get('params', [], 'array');
$app->setUserState('com_modules.add.module.params', $params);
}
/**
* Override parent cancel method to reset the add module state.
*
* @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)
{
$result = parent::cancel();
$this->app->setUserState('com_modules.add.module.extension_id', null);
$this->app->setUserState('com_modules.add.module.params', null);
if ($return = $this->input->get('return', '', 'BASE64')) {
$return = base64_decode($return);
// Don't redirect to an external URL.
if (!Uri::isInternal($return)) {
$return = Uri::base();
}
$this->app->redirect($return);
}
return $result;
}
/**
* Override parent allowSave method.
*
* @param array $data An array of input data.
* @param string $key The name of the key for the primary key.
*
* @return boolean
*
* @since 1.6
*/
protected function allowSave($data, $key = 'id')
{
// Use custom position if selected
if (isset($data['custom_position'])) {
if (empty($data['position'])) {
$data['position'] = $data['custom_position'];
}
unset($data['custom_position']);
}
return parent::allowSave($data, $key);
}
/**
* Method override to check if you can edit an existing record.
*
* @param array $data An array of input data.
* @param string $key The name of the key for the primary key.
*
* @return boolean
*
* @since 3.2
*/
protected function allowEdit($data = [], $key = 'id')
{
// Initialise variables.
$recordId = (int) isset($data[$key]) ? $data[$key] : 0;
// Zero record (id:0), return component edit permission by calling parent controller method
if (!$recordId) {
return parent::allowEdit($data, $key);
}
// Check edit on the record asset (explicit or inherited)
if ($this->app->getIdentity()->authorise('core.edit', 'com_modules.module.' . $recordId)) {
return true;
}
return false;
}
/**
* Method to run batch operations.
*
* @param string $model The model
*
* @return boolean True on success.
*
* @since 1.7
*/
public function batch($model = null)
{
$this->checkToken();
// Set the model
$model = $this->getModel('Module', 'Administrator', []);
// Preset the redirect
$redirectUrl = 'index.php?option=com_modules&view=modules' . $this->getRedirectToListAppend();
$this->setRedirect(Route::_($redirectUrl, false));
return parent::batch($model);
}
/**
* Function that allows child controller access to model data after the data has been saved.
*
* @param BaseDatabaseModel $model The data model object.
* @param array $validData The validated data.
*
* @return void
*
* @since 1.6
*/
protected function postSaveHook(BaseDatabaseModel $model, $validData = [])
{
$task = $this->getTask();
switch ($task) {
case 'save2new':
$this->app->setUserState('com_modules.add.module.extension_id', $model->getState('module.extension_id'));
break;
default:
$this->app->setUserState('com_modules.add.module.extension_id', null);
break;
}
$this->app->setUserState('com_modules.add.module.params', null);
}
/**
* 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
*
* @return boolean True if successful, false otherwise.
*/
public function save($key = null, $urlVar = null)
{
$this->checkToken();
if ($this->app->getDocument()->getType() == 'json') {
$model = $this->getModel();
$data = $this->input->post->get('jform', [], 'array');
$item = $model->getItem($this->input->get('id'));
$properties = $item->getProperties();
if (isset($data['params'])) {
unset($properties['params']);
}
// Replace changed properties
$data = array_replace_recursive($properties, $data);
if (!empty($data['assigned'])) {
$data['assigned'] = array_map('abs', $data['assigned']);
}
// Add new data to input before process by parent save()
$this->input->post->set('jform', $data);
// Add path of forms directory
Form::addFormPath(JPATH_ADMINISTRATOR . '/components/com_modules/models/forms');
}
return parent::save($key, $urlVar);
}
/**
* Method to get the other modules in the same position
*
* @return string The data for the Ajax request.
*
* @since 3.6.3
*/
public function orderPosition()
{
$app = $this->app;
// Send json mime type.
$app->mimeType = 'application/json';
$app->setHeader('Content-Type', $app->mimeType . '; charset=' . $app->charSet);
$app->sendHeaders();
// Check if user token is valid.
if (!Session::checkToken('get')) {
$app->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'error');
echo new JsonResponse();
$app->close();
}
$clientId = $this->input->getValue('client_id');
$position = $this->input->getValue('position');
$moduleId = $this->input->getValue('module_id');
// Access check.
if (
!$this->app->getIdentity()->authorise('core.create', 'com_modules')
&& !$this->app->getIdentity()->authorise('core.edit.state', 'com_modules')
&& ($moduleId && !$this->app->getIdentity()->authorise('core.edit.state', 'com_modules.module.' . $moduleId))
) {
$app->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'), 'error');
echo new JsonResponse();
$app->close();
}
$model = $this->getModel('Modules', 'Administrator', ['ignore_request' => true]);
$model->setState('client_id', $clientId);
$model->setState('filter.position', $position);
$model->setState('list.ordering', 'a.ordering');
try {
$orders = $model->getItems();
} catch (\RuntimeException $e) {
$app->enqueueMessage($e->getMessage(), 'error');
return '';
}
$orders2 = [];
$n = \count($orders);
if ($n > 0) {
for ($i = 0; $i < $n; $i++) {
if (!isset($orders2[$orders[$i]->position])) {
$orders2[$orders[$i]->position] = 0;
}
$orders2[$orders[$i]->position]++;
$ord = $orders2[$orders[$i]->position];
$title = Text::sprintf('COM_MODULES_OPTION_ORDER_POSITION', $ord, htmlspecialchars($orders[$i]->title, ENT_QUOTES, 'UTF-8'));
$html[] = $orders[$i]->position . ',' . $ord . ',' . $title;
}
} else {
$html[] = $position . ',' . 1 . ',' . Text::_('JNONE');
}
echo new JsonResponse($html);
$app->close();
}
/**
* 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 4.0.0
*/
protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id')
{
$append = parent::getRedirectToItemAppend($recordId);
$append .= '&client_id=' . $this->input->getInt('client_id');
return $append;
}
/**
* 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()
{
$append = parent::getRedirectToListAppend();
$append .= '&client_id=' . $this->input->getInt('client_id');
return $append;
}
}

View File

@ -0,0 +1,115 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\AdminController;
use Joomla\CMS\Response\JsonResponse;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Modules list controller class.
*
* @since 1.6
*/
class ModulesController extends AdminController
{
/**
* Method to clone an existing module.
*
* @return void
*
* @since 1.6
*/
public function duplicate()
{
// Check for request forgeries
$this->checkToken();
$pks = (array) $this->input->post->get('cid', [], 'int');
// Remove zero values resulting from input filter
$pks = array_filter($pks);
try {
if (empty($pks)) {
throw new \Exception(Text::_('COM_MODULES_ERROR_NO_MODULES_SELECTED'));
}
$model = $this->getModel();
$model->duplicate($pks);
$this->setMessage(Text::plural('COM_MODULES_N_MODULES_DUPLICATED', \count($pks)));
} catch (\Exception $e) {
$this->app->enqueueMessage($e->getMessage(), 'warning');
}
$this->setRedirect('index.php?option=com_modules&view=modules' . $this->getRedirectToListAppend());
}
/**
* 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 = 'Module', $prefix = 'Administrator', $config = ['ignore_request' => true])
{
return parent::getModel($name, $prefix, $config);
}
/**
* Method to get the number of frontend modules
*
* @return void
*
* @since 4.0.0
*/
public function getQuickiconContent()
{
$model = $this->getModel('Modules');
$model->setState('filter.state', 1);
$model->setState('filter.client_id', 0);
$amount = (int) $model->getTotal();
$result = [];
$result['amount'] = $amount;
$result['sronly'] = Text::plural('COM_MODULES_N_QUICKICON_SRONLY', $amount);
$result['name'] = Text::plural('COM_MODULES_N_QUICKICON', $amount);
echo new JsonResponse($result);
}
/**
* 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()
{
$append = parent::getRedirectToListAppend();
$append .= '&client_id=' . $this->input->getInt('client_id');
return $append;
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\Extension;
use Joomla\CMS\Extension\BootableExtensionInterface;
use Joomla\CMS\Extension\MVCComponent;
use Joomla\CMS\HTML\HTMLRegistryAwareTrait;
use Joomla\Component\Modules\Administrator\Service\HTML\Modules;
use Psr\Container\ContainerInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Component class for com_modules
*
* @since 4.0.0
*/
class ModulesComponent extends MVCComponent implements BootableExtensionInterface
{
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('modules', new Modules());
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\Field;
use Joomla\CMS\Form\Field\ListField;
use Joomla\Component\Modules\Administrator\Helper\ModulesHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Modules Module field.
*
* @since 3.4.2
*/
class ModulesModuleField extends ListField
{
/**
* The form field type.
*
* @var string
* @since 3.4.2
*/
protected $type = 'ModulesModule';
/**
* Client name.
*
* @var string
* @since 4.0.0
*/
protected $client;
/**
* 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 4.0.0
*/
public function __get($name)
{
switch ($name) {
case 'client':
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 4.0.0
*/
public function __set($name, $value)
{
switch ($name) {
case 'client':
$this->$name = (string) $value;
break;
default:
parent::__set($name, $value);
}
}
/**
* 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. 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 4.0.0
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$result = parent::setup($element, $value, $group);
if ($result === true) {
$this->client = $this->element['client'] ? (string) $this->element['client'] : 'site';
}
return $result;
}
/**
* Method to get the field options.
*
* @return array The field option objects.
*
* @since 3.4.2
*/
public function getOptions()
{
$clientId = $this->client === 'administrator' ? 1 : 0;
$options = ModulesHelper::getModules($clientId);
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\Field;
use Joomla\CMS\Form\Field\ListField;
use Joomla\Component\Modules\Administrator\Helper\ModulesHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Modules Position field.
*
* @since 3.4.2
*/
class ModulesPositionField extends ListField
{
/**
* The form field type.
*
* @var string
* @since 3.4.2
*/
protected $type = 'ModulesPosition';
/**
* Client name.
*
* @var string
* @since 4.0.0
*/
protected $client;
/**
* 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 4.0.0
*/
public function __get($name)
{
switch ($name) {
case 'client':
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 4.0.0
*/
public function __set($name, $value)
{
switch ($name) {
case 'client':
$this->$name = (string) $value;
break;
default:
parent::__set($name, $value);
}
}
/**
* 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. 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 4.0.0
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$result = parent::setup($element, $value, $group);
if ($result === true) {
$this->client = $this->element['client'] ? (string) $this->element['client'] : 'site';
}
return $result;
}
/**
* Method to get the field options.
*
* @return array The field option objects.
*
* @since 3.4.2
*/
public function getOptions()
{
$clientId = $this->client === 'administrator' ? 1 : 0;
$options = ModulesHelper::getPositions($clientId);
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,140 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\Field;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\HTML\HTMLHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Edit Modules Position field.
*
* @since 4.0.0
*/
class ModulesPositioneditField extends FormField
{
/**
* The form field type.
*
* @var string
* @since 4.0.0
*/
protected $type = 'ModulesPositionedit';
/**
* Name of the layout being used to render the field
*
* @var string
* @since 4.0.0
*/
protected $layout = 'joomla.form.field.modulespositionedit';
/**
* Client name.
*
* @var string
* @since 4.0.0
*/
protected $client;
/**
* 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 4.0.0
*/
public function __get($name)
{
switch ($name) {
case 'client':
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 4.0.0
*/
public function __set($name, $value)
{
switch ($name) {
case 'client':
$this->$name = (string) $value;
break;
default:
parent::__set($name, $value);
}
}
/**
* 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. 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 4.0.0
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$result = parent::setup($element, $value, $group);
if ($result === true) {
$this->client = $this->element['client'] ? (string) $this->element['client'] : 'site';
}
return $result;
}
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*
* @since 4.0.0
*/
protected function getInput()
{
$data = $this->getLayoutData();
$clientId = $this->client === 'administrator' ? 1 : 0;
$positions = HTMLHelper::_('modules.positions', $clientId, 1, $this->value);
$data['client'] = $clientId;
$data['positions'] = $positions;
$renderer = $this->getRenderer($this->layout);
$renderer->setComponent('com_modules');
$renderer->setClient(1);
return $renderer->render($data);
}
}

View File

@ -0,0 +1,312 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\Helper;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Database\ParameterType;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Modules component helper.
*
* @since 1.6
*/
abstract class ModulesHelper
{
/**
* Get a list of filter options for the state of a module.
*
* @return array An array of \JHtmlOption elements.
*/
public static function getStateOptions()
{
// Build the filter options.
$options = [];
$options[] = HTMLHelper::_('select.option', '1', Text::_('JPUBLISHED'));
$options[] = HTMLHelper::_('select.option', '0', Text::_('JUNPUBLISHED'));
$options[] = HTMLHelper::_('select.option', '-2', Text::_('JTRASHED'));
$options[] = HTMLHelper::_('select.option', '*', Text::_('JALL'));
return $options;
}
/**
* Get a list of filter options for the application clients.
*
* @return array An array of \JHtmlOption elements.
*/
public static function getClientOptions()
{
// Build the filter options.
$options = [];
$options[] = HTMLHelper::_('select.option', '0', Text::_('JSITE'));
$options[] = HTMLHelper::_('select.option', '1', Text::_('JADMINISTRATOR'));
return $options;
}
/**
* Get a list of modules positions
*
* @param integer $clientId Client ID
* @param boolean $editPositions Allow to edit the positions
*
* @return array A list of positions
*/
public static function getPositions($clientId, $editPositions = false)
{
$db = Factory::getDbo();
$clientId = (int) $clientId;
$query = $db->getQuery(true)
->select('DISTINCT ' . $db->quoteName('position'))
->from($db->quoteName('#__modules'))
->where($db->quoteName('client_id') . ' = :clientid')
->order($db->quoteName('position'))
->bind(':clientid', $clientId, ParameterType::INTEGER);
$db->setQuery($query);
try {
$positions = $db->loadColumn();
$positions = \is_array($positions) ? $positions : [];
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
return;
}
// Build the list
$options = [];
foreach ($positions as $position) {
if (!$position && !$editPositions) {
$options[] = HTMLHelper::_('select.option', 'none', Text::_('COM_MODULES_NONE'));
} elseif (!$position) {
$options[] = HTMLHelper::_('select.option', '', Text::_('COM_MODULES_NONE'));
} else {
$options[] = HTMLHelper::_('select.option', $position, $position);
}
}
return $options;
}
/**
* Return a list of templates
*
* @param integer $clientId Client ID
* @param string $state State
* @param string $template Template name
*
* @return array List of templates
*/
public static function getTemplates($clientId = 0, $state = '', $template = '')
{
$db = Factory::getDbo();
$clientId = (int) $clientId;
// Get the database object and a new query object.
$query = $db->getQuery(true);
// Build the query.
$query->select($db->quoteName(['element', 'name', 'enabled']))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('client_id') . ' = :clientid')
->where($db->quoteName('type') . ' = ' . $db->quote('template'));
if ($state != '') {
$query->where($db->quoteName('enabled') . ' = :state')
->bind(':state', $state);
}
if ($template != '') {
$query->where($db->quoteName('element') . ' = :element')
->bind(':element', $template);
}
$query->bind(':clientid', $clientId, ParameterType::INTEGER);
// Set the query and load the templates.
$db->setQuery($query);
$templates = $db->loadObjectList('element');
return $templates;
}
/**
* Get a list of the unique modules installed in the client application.
*
* @param int $clientId The client id.
*
* @return array Array of unique modules
*/
public static function getModules($clientId)
{
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('element AS value, name AS text')
->from('#__extensions as e')
->where('e.client_id = ' . (int) $clientId)
->where('type = ' . $db->quote('module'))
->join('LEFT', '#__modules as m ON m.module=e.element AND m.client_id=e.client_id')
->where('m.module IS NOT NULL')
->group('element,name');
$db->setQuery($query);
$modules = $db->loadObjectList();
$lang = Factory::getLanguage();
foreach ($modules as $i => $module) {
$extension = $module->value;
$path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE;
$source = $path . "/modules/$extension";
$lang->load("$extension.sys", $path)
|| $lang->load("$extension.sys", $source);
$modules[$i]->text = Text::_($module->text);
}
$modules = ArrayHelper::sortObjects($modules, 'text', 1, true, true);
return $modules;
}
/**
* Get a list of the assignment options for modules to menus.
*
* @param int $clientId The client id.
*
* @return array
*/
public static function getAssignmentOptions($clientId)
{
$options = [];
$options[] = HTMLHelper::_('select.option', '0', 'COM_MODULES_OPTION_MENU_ALL');
$options[] = HTMLHelper::_('select.option', '-', 'COM_MODULES_OPTION_MENU_NONE');
if ($clientId == 0) {
$options[] = HTMLHelper::_('select.option', '1', 'COM_MODULES_OPTION_MENU_INCLUDE');
$options[] = HTMLHelper::_('select.option', '-1', 'COM_MODULES_OPTION_MENU_EXCLUDE');
}
return $options;
}
/**
* Return a translated module position name
*
* @param integer $clientId Application client id 0: site | 1: admin
* @param string $template Template name
* @param string $position Position name
*
* @return string Return a translated position name
*
* @since 3.0
*/
public static function getTranslatedModulePosition($clientId, $template, $position)
{
// Template translation
$lang = Factory::getLanguage();
$path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE;
$loaded = $lang->getPaths('tpl_' . $template . '.sys');
// Only load the template's language file if it hasn't been already
if (!$loaded) {
$lang->load('tpl_' . $template . '.sys', $path, null, false, false)
|| $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, null, false, false)
|| $lang->load('tpl_' . $template . '.sys', $path, $lang->getDefault(), false, false)
|| $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, $lang->getDefault(), false, false);
}
$langKey = strtoupper('TPL_' . $template . '_POSITION_' . $position);
$text = Text::_($langKey);
// Avoid untranslated strings
if (!self::isTranslatedText($langKey, $text)) {
// Modules component translation
$langKey = strtoupper('COM_MODULES_POSITION_' . $position);
$text = Text::_($langKey);
// Avoid untranslated strings
if (!self::isTranslatedText($langKey, $text)) {
// Try to humanize the position name
$text = ucfirst(preg_replace('/^' . $template . '\-/', '', $position));
$text = ucwords(str_replace(['-', '_'], ' ', $text));
}
}
return $text;
}
/**
* Check if the string was translated
*
* @param string $langKey Language file text key
* @param string $text The "translated" text to be checked
*
* @return boolean Return true for translated text
*
* @since 3.0
*/
public static function isTranslatedText($langKey, $text)
{
return $text !== $langKey;
}
/**
* Create and return a new Option
*
* @param string $value The option value [optional]
* @param string $text The option text [optional]
*
* @return object The option as an object (\stdClass instance)
*
* @since 3.0
*/
public static function createOption($value = '', $text = '')
{
if (empty($text)) {
$text = $value;
}
$option = new \stdClass();
$option->value = $value;
$option->text = $text;
return $option;
}
/**
* Create and return a new Option Group
*
* @param string $label Value and label for group [optional]
* @param array $options Array of options to insert into group [optional]
*
* @return array Return the new group as an array
*
* @since 3.0
*/
public static function createOptionGroup($label = '', $options = [])
{
$group = [];
$group['value'] = $label;
$group['text'] = $label;
$group['items'] = $options;
return $group;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,443 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\Model;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\DatabaseQuery;
use Joomla\Database\ParameterType;
use Joomla\String\StringHelper;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Modules Component Module Model
*
* @since 1.5
*/
class ModulesModel extends ListModel
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
*
* @see \JController
* @since 1.6
*/
public function __construct($config = [])
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'id', 'a.id',
'title', 'a.title',
'checked_out', 'a.checked_out',
'checked_out_time', 'a.checked_out_time',
'published', 'a.published', 'state',
'access', 'a.access',
'ag.title', 'access_level',
'ordering', 'a.ordering',
'module', 'a.module',
'language', 'a.language',
'l.title', 'language_title',
'publish_up', 'a.publish_up',
'publish_down', 'a.publish_down',
'client_id', 'a.client_id',
'position', 'a.position',
'pages',
'name', 'e.name',
'menuitem',
];
}
parent::__construct($config);
}
/**
* 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.position', $direction = 'asc')
{
$app = Factory::getApplication();
$layout = $app->getInput()->get('layout', '', 'cmd');
// Adjust the context to support modal layouts.
if ($layout) {
$this->context .= '.' . $layout;
}
// Make context client aware
$this->context .= '.' . $app->getInput()->get->getInt('client_id', 0);
// Load the filter state.
$this->setState('filter.search', $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search', '', 'string'));
$this->setState('filter.position', $this->getUserStateFromRequest($this->context . '.filter.position', 'filter_position', '', 'string'));
$this->setState('filter.module', $this->getUserStateFromRequest($this->context . '.filter.module', 'filter_module', '', 'string'));
$this->setState('filter.menuitem', $this->getUserStateFromRequest($this->context . '.filter.menuitem', 'filter_menuitem', '', 'cmd'));
$this->setState('filter.access', $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', '', 'cmd'));
// If in modal layout on the frontend, state and language are always forced.
if ($app->isClient('site') && $layout === 'modal') {
$this->setState('filter.language', 'current');
$this->setState('filter.state', 1);
} else {
// If in backend (modal or not) we get the same fields from the user request.
$this->setState('filter.language', $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', '', 'string'));
$this->setState('filter.state', $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string'));
}
// Special case for the client id.
if ($app->isClient('site') || $layout === 'modal') {
$this->setState('client_id', 0);
$clientId = 0;
} else {
$clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int');
$clientId = (!\in_array($clientId, [0, 1])) ? 0 : $clientId;
$this->setState('client_id', $clientId);
}
// Use a different filter file when client is administrator
if ($clientId == 1) {
$this->filterFormName = 'filter_modulesadmin';
}
// Load the parameters.
$params = ComponentHelper::getParams('com_modules');
$this->setState('params', $params);
// List state information.
parent::populateState($ordering, $direction);
}
/**
* 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.
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('client_id');
$id .= ':' . $this->getState('filter.search');
$id .= ':' . $this->getState('filter.state');
$id .= ':' . $this->getState('filter.position');
$id .= ':' . $this->getState('filter.module');
$id .= ':' . $this->getState('filter.menuitem');
$id .= ':' . $this->getState('filter.access');
$id .= ':' . $this->getState('filter.language');
return parent::getStoreId($id);
}
/**
* Returns an object list
*
* @param DatabaseQuery $query The query
* @param int $limitstart Offset
* @param int $limit The number of records
*
* @return array
*/
protected function _getList($query, $limitstart = 0, $limit = 0)
{
$listOrder = $this->getState('list.ordering', 'a.position');
$listDirn = $this->getState('list.direction', 'asc');
$db = $this->getDatabase();
// If ordering by fields that need translate we need to sort the array of objects after translating them.
if (\in_array($listOrder, ['pages', 'name'])) {
// Fetch the results.
$db->setQuery($query);
$result = $db->loadObjectList();
// Translate the results.
$this->translate($result);
// Sort the array of translated objects.
$result = ArrayHelper::sortObjects($result, $listOrder, strtolower($listDirn) == 'desc' ? -1 : 1, true, true);
// Process pagination.
$total = \count($result);
$this->cache[$this->getStoreId('getTotal')] = $total;
if ($total < $limitstart) {
$limitstart = 0;
$this->setState('list.start', 0);
}
return \array_slice($result, $limitstart, $limit ?: null);
}
// If ordering by fields that doesn't need translate just order the query.
if ($listOrder === 'a.ordering') {
$query->order($db->quoteName('a.position') . ' ASC')
->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn));
} elseif ($listOrder === 'a.position') {
$query->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn))
->order($db->quoteName('a.ordering') . ' ASC');
} else {
$query->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn));
}
// Process pagination.
$result = parent::_getList($query, $limitstart, $limit);
// Translate the results.
$this->translate($result);
return $result;
}
/**
* Translate a list of objects
*
* @param array &$items The array of objects
*
* @return void
*/
protected function translate(&$items)
{
$lang = Factory::getLanguage();
$clientPath = $this->getState('client_id') ? JPATH_ADMINISTRATOR : JPATH_SITE;
foreach ($items as $item) {
$extension = $item->module;
$source = $clientPath . "/modules/$extension";
$lang->load("$extension.sys", $clientPath)
|| $lang->load("$extension.sys", $source);
$item->name = Text::_($item->name);
if (\is_null($item->pages)) {
$item->pages = Text::_('JNONE');
} elseif ($item->pages < 0) {
$item->pages = Text::_('COM_MODULES_ASSIGNED_VARIES_EXCEPT');
} elseif ($item->pages > 0) {
$item->pages = Text::_('COM_MODULES_ASSIGNED_VARIES_ONLY');
} else {
$item->pages = Text::_('JALL');
}
}
}
/**
* Build an SQL query to load the list data.
*
* @return DatabaseQuery
*/
protected function getListQuery()
{
// Create a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true);
// Select the required fields.
$query->select(
$this->getState(
'list.select',
'a.id, a.title, a.note, a.position, a.module, a.language,' .
'a.checked_out, a.checked_out_time, a.published AS published, e.enabled AS enabled, a.access, a.ordering, a.publish_up, a.publish_down'
)
);
// From modules table.
$query->from($db->quoteName('#__modules', 'a'));
// Join over the language
$query->select($db->quoteName('l.title', 'language_title'))
->select($db->quoteName('l.image', 'language_image'))
->join('LEFT', $db->quoteName('#__languages', 'l') . ' ON ' . $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language'));
// Join over the users for the checked out user.
$query->select($db->quoteName('uc.name', 'editor'))
->join('LEFT', $db->quoteName('#__users', 'uc') . ' ON ' . $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out'));
// Join over the asset groups.
$query->select($db->quoteName('ag.title', 'access_level'))
->join('LEFT', $db->quoteName('#__viewlevels', 'ag') . ' ON ' . $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access'));
// Join over the module menus
$query->select('MIN(mm.menuid) AS pages')
->join('LEFT', $db->quoteName('#__modules_menu', 'mm') . ' ON ' . $db->quoteName('mm.moduleid') . ' = ' . $db->quoteName('a.id'));
// Join over the extensions
$query->select($db->quoteName('e.name', 'name'))
->join('LEFT', $db->quoteName('#__extensions', 'e') . ' ON ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('a.module'));
// Group (careful with PostgreSQL)
$query->group(
'a.id, a.title, a.note, a.position, a.module, a.language, a.checked_out, '
. 'a.checked_out_time, a.published, a.access, a.ordering, l.title, l.image, uc.name, ag.title, e.name, '
. 'l.lang_code, uc.id, ag.id, mm.moduleid, e.element, a.publish_up, a.publish_down, e.enabled'
);
// Filter by client.
$clientId = (int) $this->getState('client_id');
$query->where($db->quoteName('a.client_id') . ' = :aclientid')
->where($db->quoteName('e.client_id') . ' = :eclientid')
->bind(':aclientid', $clientId, ParameterType::INTEGER)
->bind(':eclientid', $clientId, ParameterType::INTEGER);
// Filter by current user access level.
$user = $this->getCurrentUser();
// Get the current user for authorisation checks
if ($user->authorise('core.admin') !== true) {
$groups = $user->getAuthorisedViewLevels();
$query->whereIn($db->quoteName('a.access'), $groups);
}
// Filter by access level.
if ($access = $this->getState('filter.access')) {
$access = (int) $access;
$query->where($db->quoteName('a.access') . ' = :access')
->bind(':access', $access, ParameterType::INTEGER);
}
// Filter by published state.
$state = $this->getState('filter.state');
if (is_numeric($state)) {
$state = (int) $state;
$query->where($db->quoteName('a.published') . ' = :state')
->bind(':state', $state, ParameterType::INTEGER);
} elseif ($state === '') {
$query->whereIn($db->quoteName('a.published'), [0, 1]);
}
// Filter by position.
if ($position = $this->getState('filter.position')) {
$position = ($position === 'none') ? '' : $position;
$query->where($db->quoteName('a.position') . ' = :position')
->bind(':position', $position);
}
// Filter by module.
if ($module = $this->getState('filter.module')) {
$query->where($db->quoteName('a.module') . ' = :module')
->bind(':module', $module);
}
// Filter by menuitem id (only for site client).
if ((int) $clientId === 0 && $menuItemId = $this->getState('filter.menuitem')) {
// If user selected the modules not assigned to any page (menu item).
if ((int) $menuItemId === -1) {
$query->having('MIN(' . $db->quoteName('mm.menuid') . ') IS NULL');
} else {
// If user selected the modules assigned to some particular page (menu item).
// Modules in "All" pages.
$subQuery1 = $db->getQuery(true);
$subQuery1->select('MIN(' . $db->quoteName('menuid') . ')')
->from($db->quoteName('#__modules_menu'))
->where($db->quoteName('moduleid') . ' = ' . $db->quoteName('a.id'));
// Modules in "Selected" pages that have the chosen menu item id.
$menuItemId = (int) $menuItemId;
$minusMenuItemId = $menuItemId * -1;
$subQuery2 = $db->getQuery(true);
$subQuery2->select($db->quoteName('moduleid'))
->from($db->quoteName('#__modules_menu'))
->where($db->quoteName('menuid') . ' = :menuitemid2');
// Modules in "All except selected" pages that doesn't have the chosen menu item id.
$subQuery3 = $db->getQuery(true);
$subQuery3->select($db->quoteName('moduleid'))
->from($db->quoteName('#__modules_menu'))
->where($db->quoteName('menuid') . ' = :menuitemid3');
// Filter by modules assigned to the selected menu item.
$query->where('(
(' . $subQuery1 . ') = 0
OR ((' . $subQuery1 . ') > 0 AND ' . $db->quoteName('a.id') . ' IN (' . $subQuery2 . '))
OR ((' . $subQuery1 . ') < 0 AND ' . $db->quoteName('a.id') . ' NOT IN (' . $subQuery3 . '))
)');
$query->bind(':menuitemid2', $menuItemId, ParameterType::INTEGER);
$query->bind(':menuitemid3', $minusMenuItemId, ParameterType::INTEGER);
}
}
// Filter by search in title or note or id:.
$search = $this->getState('filter.search');
if (!empty($search)) {
if (stripos($search, 'id:') === 0) {
$ids = (int) substr($search, 3);
$query->where($db->quoteName('a.id') . ' = :id')
->bind(':id', $ids, ParameterType::INTEGER);
} else {
$search = '%' . StringHelper::strtolower($search) . '%';
$query->extendWhere(
'AND',
[
'LOWER(' . $db->quoteName('a.title') . ') LIKE :title',
'LOWER(' . $db->quoteName('a.note') . ') LIKE :note',
],
'OR'
)
->bind(':title', $search)
->bind(':note', $search);
}
}
// Filter on the language.
if ($language = $this->getState('filter.language')) {
if ($language === 'current') {
$language = [Factory::getLanguage()->getTag(), '*'];
$query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING);
} else {
$query->where($db->quoteName('a.language') . ' = :language')
->bind(':language', $language);
}
}
return $query;
}
/**
* Manipulate the query to be used to evaluate if this is an Empty State to provide specific conditions for this extension.
*
* @return DatabaseQuery
*
* @since 4.0.0
*/
protected function getEmptyStateQuery()
{
$query = parent::getEmptyStateQuery();
$clientId = (int) $this->getState('client_id');
$query->where($this->getDatabase()->quoteName('a.client_id') . ' = :client_id')
->bind(':client_id', $clientId, ParameterType::INTEGER);
return $query;
}
}

View File

@ -0,0 +1,229 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\Model;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Component\Modules\Administrator\Helper\ModulesHelper;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\Path;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Modules Component Positions Model
*
* @since 1.6
*/
class PositionsModel extends ListModel
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
*
* @see \JController
* @since 1.6
*/
public function __construct($config = [])
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'value',
'templates',
];
}
parent::__construct($config);
}
/**
* 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 = 'ordering', $direction = 'asc')
{
// Load the filter state.
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
$state = $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string');
$this->setState('filter.state', $state);
$template = $this->getUserStateFromRequest($this->context . '.filter.template', 'filter_template', '', 'string');
$this->setState('filter.template', $template);
$type = $this->getUserStateFromRequest($this->context . '.filter.type', 'filter_type', '', 'string');
$this->setState('filter.type', $type);
// Special case for the client id.
$clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int');
$clientId = (!\in_array((int) $clientId, [0, 1])) ? 0 : (int) $clientId;
$this->setState('client_id', $clientId);
// Load the parameters.
$params = ComponentHelper::getParams('com_modules');
$this->setState('params', $params);
// List state information.
parent::populateState($ordering, $direction);
}
/**
* Method to get an array of data items.
*
* @return mixed An array of data items on success, false on failure.
*
* @since 1.6
*/
public function getItems()
{
if (!isset($this->items)) {
$lang = Factory::getLanguage();
$search = $this->getState('filter.search');
$state = $this->getState('filter.state');
$clientId = $this->getState('client_id');
$filter_template = $this->getState('filter.template');
$type = $this->getState('filter.type');
$ordering = $this->getState('list.ordering');
$direction = $this->getState('list.direction');
$limitstart = $this->getState('list.start');
$limit = $this->getState('list.limit');
$client = ApplicationHelper::getClientInfo($clientId);
if ($type != 'template') {
$clientId = (int) $clientId;
// Get the database object and a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('DISTINCT ' . $db->quoteName('position', 'value'))
->from($db->quoteName('#__modules'))
->where($db->quoteName('client_id') . ' = :clientid')
->bind(':clientid', $clientId, ParameterType::INTEGER);
if ($search) {
$search = '%' . str_replace(' ', '%', trim($search), true) . '%';
$query->where($db->quoteName('position') . ' LIKE :position')
->bind(':position', $search);
}
$db->setQuery($query);
try {
$positions = $db->loadObjectList('value');
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());
return false;
}
foreach ($positions as $value => $position) {
$positions[$value] = [];
}
} else {
$positions = [];
}
// Load the positions from the installed templates.
foreach (ModulesHelper::getTemplates($clientId) as $template) {
$path = Path::clean($client->path . '/templates/' . $template->element . '/templateDetails.xml');
if (file_exists($path)) {
$xml = simplexml_load_file($path);
if (isset($xml->positions[0])) {
$lang->load('tpl_' . $template->element . '.sys', $client->path)
|| $lang->load('tpl_' . $template->element . '.sys', $client->path . '/templates/' . $template->element);
foreach ($xml->positions[0] as $position) {
$value = (string) $position['value'];
$label = (string) $position;
if (!$value) {
$value = $label;
$label = preg_replace('/[^a-zA-Z0-9_\-]/', '_', 'TPL_' . $template->element . '_POSITION_' . $value);
$altlabel = preg_replace('/[^a-zA-Z0-9_\-]/', '_', 'COM_MODULES_POSITION_' . $value);
if (!$lang->hasKey($label) && $lang->hasKey($altlabel)) {
$label = $altlabel;
}
}
if ($type == 'user' || ($state != '' && $state != $template->enabled)) {
unset($positions[$value]);
} elseif (preg_match(\chr(1) . $search . \chr(1) . 'i', $value) && ($filter_template == '' || $filter_template == $template->element)) {
if (!isset($positions[$value])) {
$positions[$value] = [];
}
$positions[$value][$template->name] = $label;
}
}
}
}
}
$this->total = \count($positions);
if ($limitstart >= $this->total) {
$limitstart = $limitstart < $limit ? 0 : $limitstart - $limit;
$this->setState('list.start', $limitstart);
}
if ($ordering == 'value') {
if ($direction == 'asc') {
ksort($positions);
} else {
krsort($positions);
}
} else {
if ($direction == 'asc') {
asort($positions);
} else {
arsort($positions);
}
}
$this->items = \array_slice($positions, $limitstart, $limit ?: null);
}
return $this->items;
}
/**
* Method to get the total number of items.
*
* @return integer The total number of items.
*
* @since 1.6
*/
public function getTotal()
{
if (!isset($this->total)) {
$this->getItems();
}
return $this->total;
}
}

View File

@ -0,0 +1,163 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\Model;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\Path;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Module model.
*
* @since 1.6
*/
class SelectModel extends ListModel
{
/**
* 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 = null, $direction = null)
{
$app = Factory::getApplication();
// Load the filter state.
$clientId = $app->getUserStateFromRequest('com_modules.modules.client_id', 'client_id', 0);
$this->setState('client_id', (int) $clientId);
// Load the parameters.
$params = ComponentHelper::getParams('com_modules');
$this->setState('params', $params);
// Manually set limits to get all modules.
$this->setState('list.limit', 0);
$this->setState('list.start', 0);
$this->setState('list.ordering', 'a.name');
$this->setState('list.direction', 'ASC');
}
/**
* 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.
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('client_id');
return parent::getStoreId($id);
}
/**
* Build an SQL query to load the list data.
*
* @return \Joomla\Database\DatabaseQuery
*/
protected function getListQuery()
{
// Create a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true);
// Select the required fields from the table.
$query->select(
$this->getState(
'list.select',
'a.extension_id, a.name, a.element AS module'
)
);
$query->from($db->quoteName('#__extensions', 'a'));
// Filter by module
$query->where($db->quoteName('a.type') . ' = ' . $db->quote('module'));
// Filter by client.
$clientId = (int) $this->getState('client_id');
$query->where($db->quoteName('a.client_id') . ' = :clientid')
->bind(':clientid', $clientId, ParameterType::INTEGER);
// Filter by enabled
$query->where($db->quoteName('a.enabled') . ' = 1');
// Add the list ordering clause.
$query->order($db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
return $query;
}
/**
* Method to get a list of items.
*
* @return mixed An array of objects on success, false on failure.
*/
public function getItems()
{
// Get the list of items from the database.
$items = parent::getItems();
$client = ApplicationHelper::getClientInfo($this->getState('client_id', 0));
$lang = Factory::getLanguage();
// Loop through the results to add the XML metadata,
// and load language support.
foreach ($items as &$item) {
$path = Path::clean($client->path . '/modules/' . $item->module . '/' . $item->module . '.xml');
if (file_exists($path)) {
$item->xml = simplexml_load_file($path);
} else {
$item->xml = null;
}
// 1.5 Format; Core files or language packs then
// 1.6 3PD Extension Support
$lang->load($item->module . '.sys', $client->path)
|| $lang->load($item->module . '.sys', $client->path . '/modules/' . $item->module);
$item->name = Text::_($item->name);
if (isset($item->xml) && $text = trim($item->xml->description)) {
$item->desc = Text::_($text);
} else {
$item->desc = Text::_('COM_MODULES_NODESCRIPTION');
}
}
$items = ArrayHelper::sortObjects($items, 'name', 1, true, true);
// @todo: Use the cached XML from the extensions table?
return $items;
}
}

View File

@ -0,0 +1,259 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\Service\HTML;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Component\Modules\Administrator\Helper\ModulesHelper;
use Joomla\Component\Templates\Administrator\Helper\TemplatesHelper;
use Joomla\Database\ParameterType;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* HTMLHelper module helper class.
*
* @since 1.6
*/
class Modules
{
/**
* Builds an array of template options
*
* @param integer $clientId The client id.
* @param string $state The state of the template.
*
* @return array
*/
public function templates($clientId = 0, $state = '')
{
$options = [];
$templates = ModulesHelper::getTemplates($clientId, $state);
foreach ($templates as $template) {
$options[] = HTMLHelper::_('select.option', $template->element, $template->name);
}
return $options;
}
/**
* Builds an array of template type options
*
* @return array
*/
public function types()
{
$options = [];
$options[] = HTMLHelper::_('select.option', 'user', 'COM_MODULES_OPTION_POSITION_USER_DEFINED');
$options[] = HTMLHelper::_('select.option', 'template', 'COM_MODULES_OPTION_POSITION_TEMPLATE_DEFINED');
return $options;
}
/**
* Builds an array of template state options
*
* @return array
*/
public function templateStates()
{
$options = [];
$options[] = HTMLHelper::_('select.option', '1', 'JENABLED');
$options[] = HTMLHelper::_('select.option', '0', 'JDISABLED');
return $options;
}
/**
* Returns a published state on a grid
*
* @param integer $value The state value.
* @param integer $i The row index
* @param boolean $enabled An optional setting for access control on the action.
* @param string $checkbox An optional prefix for checkboxes.
*
* @return string The Html code
*
* @see HTMLHelperJGrid::state
* @since 1.7.1
*/
public function state($value, $i, $enabled = true, $checkbox = 'cb')
{
$states = [
1 => [
'unpublish',
'COM_MODULES_EXTENSION_PUBLISHED_ENABLED',
'COM_MODULES_HTML_UNPUBLISH_ENABLED',
'COM_MODULES_EXTENSION_PUBLISHED_ENABLED',
true,
'publish',
'publish',
],
0 => [
'publish',
'COM_MODULES_EXTENSION_UNPUBLISHED_ENABLED',
'COM_MODULES_HTML_PUBLISH_ENABLED',
'COM_MODULES_EXTENSION_UNPUBLISHED_ENABLED',
true,
'unpublish',
'unpublish',
],
-1 => [
'unpublish',
'COM_MODULES_EXTENSION_PUBLISHED_DISABLED',
'COM_MODULES_HTML_UNPUBLISH_DISABLED',
'COM_MODULES_EXTENSION_PUBLISHED_DISABLED',
true,
'warning',
'warning',
],
-2 => [
'publish',
'COM_MODULES_EXTENSION_UNPUBLISHED_DISABLED',
'COM_MODULES_HTML_PUBLISH_DISABLED',
'COM_MODULES_EXTENSION_UNPUBLISHED_DISABLED',
true,
'unpublish',
'unpublish',
],
];
return HTMLHelper::_('jgrid.state', $states, $value, $i, 'modules.', $enabled, true, $checkbox);
}
/**
* Display a batch widget for the module position selector.
*
* @param integer $clientId The client ID.
* @param integer $state The state of the module (enabled, unenabled, trashed).
* @param string $selectedPosition The currently selected position for the module.
*
* @return string The necessary positions for the widget.
*
* @since 2.5
*/
public function positions($clientId, $state = 1, $selectedPosition = '')
{
$templates = array_keys(ModulesHelper::getTemplates($clientId, $state));
$templateGroups = [];
// Add an empty value to be able to deselect a module position
$option = ModulesHelper::createOption('', Text::_('COM_MODULES_NONE'));
$templateGroups[''] = ModulesHelper::createOptionGroup('', [$option]);
// Add positions from templates
$isTemplatePosition = false;
foreach ($templates as $template) {
$options = [];
$positions = TemplatesHelper::getPositions($clientId, $template);
if (\is_array($positions)) {
foreach ($positions as $position) {
$text = ModulesHelper::getTranslatedModulePosition($clientId, $template, $position) . ' [' . $position . ']';
$options[] = ModulesHelper::createOption($position, $text);
if (!$isTemplatePosition && $selectedPosition === $position) {
$isTemplatePosition = true;
}
}
$options = ArrayHelper::sortObjects($options, 'text');
}
$templateGroups[$template] = ModulesHelper::createOptionGroup(ucfirst($template), $options);
}
// Add custom position to options
$customGroupText = Text::_('COM_MODULES_CUSTOM_POSITION');
$editPositions = true;
$customPositions = ModulesHelper::getPositions($clientId, $editPositions);
$app = Factory::getApplication();
$position = $app->getUserState('com_modules.modules.' . $clientId . '.filter.position');
if ($position) {
$customPositions[] = HTMLHelper::_('select.option', $position);
$customPositions = array_unique($customPositions, SORT_REGULAR);
}
$templateGroups[$customGroupText] = ModulesHelper::createOptionGroup($customGroupText, $customPositions);
return $templateGroups;
}
/**
* Get a select with the batch action options
*
* @return void
*/
public function batchOptions()
{
// Create the copy/move options.
$options = [
HTMLHelper::_('select.option', 'c', Text::_('JLIB_HTML_BATCH_COPY')),
HTMLHelper::_('select.option', 'm', Text::_('JLIB_HTML_BATCH_MOVE')),
];
echo HTMLHelper::_('select.radiolist', $options, 'batch[move_copy]', '', 'value', 'text', 'm');
}
/**
* Method to get the field options.
*
* @param integer $clientId The client ID
*
* @return array The field option objects.
*
* @since 2.5
*
* @deprecated 4.3 will be removed in 6.0
* Will be removed with no replacement
*/
public function positionList($clientId = 0)
{
$clientId = (int) $clientId;
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('DISTINCT ' . $db->quoteName('position', 'value'))
->select($db->quoteName('position', 'text'))
->from($db->quoteName('#__modules'))
->where($db->quoteName('client_id') . ' = :clientid')
->order($db->quoteName('position'))
->bind(':clientid', $clientId, ParameterType::INTEGER);
// Get the options.
$db->setQuery($query);
try {
$options = $db->loadObjectList();
} catch (\RuntimeException $e) {
Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
}
// Pop the first item off the array if it's blank
if (\count($options)) {
if (\strlen($options[0]->text) < 1) {
array_shift($options);
}
}
return $options;
}
}

View File

@ -0,0 +1,164 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\View\Module;
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
/**
* View to edit a module.
*
* @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
*
* @since 4.0.0
*/
protected $canDo;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*/
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_modules', 'module', $this->item->id);
// 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()
{
Factory::getApplication()->getInput()->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;
$toolbar = Toolbar::getInstance();
ToolbarHelper::title(Text::sprintf('COM_MODULES_MANAGER_MODULE', Text::_($this->item->module)), 'cube module');
// For new records, check the create permission.
if ($isNew && $canDo->get('core.create')) {
$toolbar->apply('module.apply');
$saveGroup = $toolbar->dropdownButton('save-group');
$saveGroup->configure(
function (Toolbar $childBar) {
$childBar->save('module.save');
$childBar->save2new('module.save2new');
}
);
$toolbar->cancel('module.cancel', 'JTOOLBAR_CANCEL');
} else {
// Can't save the record if it's checked out.
if (!$checkedOut && $canDo->get('core.edit')) {
$toolbar->apply('module.apply');
}
$saveGroup = $toolbar->dropdownButton('save-group');
$saveGroup->configure(
function (Toolbar $childBar) use ($checkedOut, $canDo) {
// Can't save the record if it's checked out. Since it's an existing record, check the edit permission.
if (!$checkedOut && $canDo->get('core.edit')) {
$childBar->save('module.save');
// We can save this record, but check the create permission to see if we can return to make a new one.
if ($canDo->get('core.create')) {
$childBar->save2new('module.save2new');
}
}
// If checked out, we can still save
if ($canDo->get('core.create')) {
$childBar->save2copy('module.save2copy');
}
}
);
$toolbar->cancel('module.cancel');
}
// 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 = null;
}
$toolbar->inlinehelp();
$toolbar->help($help->key, false, $url);
}
}

View File

@ -0,0 +1,243 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Administrator\View\Modules;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ContentHelper;
use Joomla\CMS\Helper\ModuleHelper;
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\Button\DropdownButton;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* View class for a list of modules.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* 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;
/**
* Is this view an Empty State
*
* @var boolean
* @since 4.0.0
*/
private $isEmptyState = false;
/**
* 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->pagination = $this->get('Pagination');
$this->state = $this->get('State');
$this->total = $this->get('Total');
$this->filterForm = $this->get('FilterForm');
$this->activeFilters = $this->get('ActiveFilters');
$this->clientId = $this->state->get('client_id');
if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) {
$this->setLayout('emptystate');
}
/**
* The code below make sure the remembered position will be available from filter dropdown even if there are no
* modules available for this position. This will make the UI less confusing for users in case there is only one
* module in the selected position and user:
* 1. Edit the module, change it to new position, save it and come back to Modules Management Screen
* 2. Or move that module to new position using Batch action
*/
if (\count($this->items) === 0 && $this->state->get('filter.position')) {
$selectedPosition = $this->state->get('filter.position');
$positionField = $this->filterForm->getField('position', 'filter');
$positionExists = false;
foreach ($positionField->getOptions() as $option) {
if ($option->value === $selectedPosition) {
$positionExists = true;
break;
}
}
if ($positionExists === false) {
$positionField->addOption($selectedPosition, ['value' => $selectedPosition]);
}
}
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
// We do not need the Language filter when modules are not filtered
if ($this->clientId == 1 && !ModuleHelper::isAdminMultilang()) {
unset($this->activeFilters['language']);
$this->filterForm->removeField('language', 'filter');
}
// We don't need the 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 {
// If in modal layout.
// Client id selector should not exist.
$this->filterForm->removeField('client_id', '');
// If in the frontend state and language should not activate the search tools.
if (Factory::getApplication()->isClient('site')) {
unset($this->activeFilters['state']);
unset($this->activeFilters['language']);
}
}
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 1.6
*/
protected function addToolbar()
{
$state = $this->get('State');
$canDo = ContentHelper::getActions('com_modules');
$user = $this->getCurrentUser();
// Get the toolbar object instance
$toolbar = Toolbar::getInstance();
if ($state->get('client_id') == 1) {
ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_ADMIN'), 'cube module');
} else {
ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_SITE'), 'cube module');
}
if ($canDo->get('core.create')) {
$toolbar->standardButton('new', 'JTOOLBAR_NEW')
->onclick("location.href='index.php?option=com_modules&amp;view=select&amp;client_id=" . $this->state->get('client_id', 0) . "'");
}
if (!$this->isEmptyState && ($canDo->get('core.edit.state') || $this->getCurrentUser()->authorise('core.admin'))) {
/** @var DropdownButton $dropdown */
$dropdown = $toolbar->dropdownButton('status-group', 'JTOOLBAR_CHANGE_STATUS')
->toggleSplit(false)
->icon('icon-ellipsis-h')
->buttonClass('btn btn-action')
->listCheck(true);
$childBar = $dropdown->getChildToolbar();
if ($canDo->get('core.edit.state')) {
$childBar->publish('modules.publish')->listCheck(true);
$childBar->unpublish('modules.unpublish')->listCheck(true);
}
if ($this->getCurrentUser()->authorise('core.admin')) {
$childBar->checkin('modules.checkin')->listCheck(true);
}
if ($canDo->get('core.edit.state') && $this->state->get('filter.published') != -2) {
$childBar->trash('modules.trash')->listCheck(true);
}
// Add a batch button
if (
$user->authorise('core.create', 'com_modules') && $user->authorise('core.edit', 'com_modules')
&& $user->authorise('core.edit.state', 'com_modules')
) {
$childBar->popupButton('batch', 'JTOOLBAR_BATCH')
->selector('collapseModal')
->listCheck(true);
}
if ($canDo->get('core.create')) {
$childBar->standardButton('copy', 'JTOOLBAR_DUPLICATE', 'modules.duplicate')
->listCheck(true);
}
}
if (!$this->isEmptyState && ($state->get('filter.state') == -2 && $canDo->get('core.delete'))) {
$toolbar->delete('modules.delete', 'JTOOLBAR_EMPTY_TRASH')
->message('JGLOBAL_CONFIRM_DELETE')
->listCheck(true);
}
if ($canDo->get('core.admin')) {
$toolbar->preferences('com_modules');
}
$toolbar->help('Modules');
}
}

View File

@ -0,0 +1,100 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Modules\Administrator\View\Select;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\FileLayout;
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
/**
* HTML View class for the Modules component
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* An array of items
*
* @var array
*/
protected $items;
/**
* A suffix for links for modal use
*
* @var string
*/
protected $modalLink;
/**
* Display the view
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*/
public function display($tpl = null)
{
$this->state = $this->get('State');
$this->items = $this->get('Items');
$this->modalLink = '';
// 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()
{
$state = $this->get('State');
$clientId = (int) $state->get('client_id', 0);
$toolbar = Toolbar::getInstance();
// Add page title
ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_SITE'), 'cube module');
if ($clientId === 1) {
ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_ADMIN'), 'cube module');
}
// Instantiate a new FileLayout instance and render the layout
$layout = new FileLayout('toolbar.cancelselect');
$toolbar->customButton('new')
->html($layout->render(['client_id' => $clientId]));
}
}

View File

@ -0,0 +1,197 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
HTMLHelper::_('behavior.combobox');
$hasContent = isset($this->item->xml->customContent);
$hasContentFieldName = 'content';
// For a later improvement
if ($hasContent) {
$hasContentFieldName = 'content';
}
// Get Params Fieldsets
$this->fieldsets = $this->form->getFieldsets('params');
$this->useCoreUI = true;
Text::script('JYES');
Text::script('JNO');
Text::script('JALL');
Text::script('JTRASHED');
$this->document->addScriptOptions('module-edit', ['itemId' => $this->item->id, 'state' => (int) $this->item->id == 0 ? 'Add' : 'Edit']);
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('keepalive')
->useScript('form.validate')
->useScript('com_modules.admin-module-edit');
$input = Factory::getApplication()->getInput();
// In case of modal
$isModal = $input->get('layout') === 'modal';
$layout = $isModal ? 'modal' : 'edit';
$tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : '';
?>
<form action="<?php echo Route::_('index.php?option=com_modules&layout=' . $layout . $tmpl . '&client_id=' . $this->form->getValue('client_id') . '&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="module-form" aria-label="<?php echo Text::_('COM_MODULES_FORM_TITLE_' . ((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' => 'general', 'recall' => true, 'breakpoint' => 768]); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'general', Text::_('COM_MODULES_MODULE')); ?>
<div class="row">
<div class="col-lg-9">
<?php if ($this->item->xml) : ?>
<?php if ($this->item->xml->description) : ?>
<h2>
<?php
if ($this->item->xml) {
echo ($text = (string) $this->item->xml->name) ? Text::_($text) : $this->item->module;
} else {
echo Text::_('COM_MODULES_ERR_XML');
}
?>
</h2>
<div class="info-labels">
<span class="badge bg-secondary">
<?php echo $this->item->client_id == 0 ? Text::_('JSITE') : Text::_('JADMINISTRATOR'); ?>
</span>
</div>
<div>
<?php
$this->fieldset = 'description';
$short_description = Text::_($this->item->xml->description);
$long_description = LayoutHelper::render('joomla.edit.fieldset', $this);
if (!$long_description) {
$truncated = HTMLHelper::_('string.truncate', $short_description, 550, true, false);
if (strlen($truncated) > 500) {
$long_description = $short_description;
$short_description = HTMLHelper::_('string.truncate', $truncated, 250);
if ($short_description == $long_description) {
$long_description = '';
}
}
}
?>
<p><?php echo $short_description; ?></p>
<?php if ($long_description) : ?>
<p class="readmore">
<a href="#" onclick="document.getElementById('myTab').activateTab(document.getElementById('description'));">
<?php echo Text::_('JGLOBAL_SHOW_FULL_DESCRIPTION'); ?>
</a>
</p>
<?php endif; ?>
</div>
<?php endif; ?>
<?php else : ?>
<div class="alert alert-danger">
<span class="icon-exclamation-triangle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('ERROR'); ?></span>
<?php echo Text::_('COM_MODULES_ERR_XML'); ?>
</div>
<?php endif; ?>
<?php
if ($hasContent) {
echo $this->form->getInput($hasContentFieldName);
}
$this->fieldset = 'basic';
$html = LayoutHelper::render('joomla.edit.fieldset', $this);
echo $html ? '<hr>' . $html : '';
?>
</div>
<div class="col-lg-3">
<?php
// Set main fields.
$this->fields = [
'showtitle',
'position',
'published',
'publish_up',
'publish_down',
'access',
'ordering',
'language',
'note'
];
?>
<?php if ($this->item->client_id == 0) : ?>
<?php echo LayoutHelper::render('joomla.edit.global', $this); ?>
<?php else : ?>
<?php echo LayoutHelper::render('joomla.edit.admin_modules', $this); ?>
<?php endif; ?>
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php if (isset($long_description) && $long_description != '') : ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'description', Text::_('JGLOBAL_FIELDSET_DESCRIPTION')); ?>
<div class="card">
<div class="card-body">
<?php echo $long_description; ?>
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php endif; ?>
<?php if ($this->item->client_id == 0) : ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'assignment', Text::_('COM_MODULES_MENU_ASSIGNMENT')); ?>
<fieldset id="fieldset-assignment" class="options-form">
<legend><?php echo Text::_('COM_MODULES_MENU_ASSIGNMENT'); ?></legend>
<div>
<?php echo $this->loadTemplate('assignment'); ?>
</div>
</fieldset>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php endif; ?>
<?php
$this->fieldsets = [];
$this->ignore_fieldsets = ['basic', 'description'];
echo LayoutHelper::render('joomla.edit.params', $this);
?>
<?php if ($this->canDo->get('core.admin')) : ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'permissions', Text::_('COM_MODULES_FIELDSET_RULES')); ?>
<fieldset id="fieldset-permissions" class="options-form">
<legend><?php echo Text::_('COM_MODULES_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="">
<input type="hidden" name="return" value="<?php echo $input->get('return', null, 'BASE64'); ?>">
<?php echo HTMLHelper::_('form.token'); ?>
<?php echo $this->form->getInput('module'); ?>
<?php echo $this->form->getInput('client_id'); ?>
</div>
</form>

View File

@ -0,0 +1,151 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
use Joomla\Component\Modules\Administrator\Helper\ModulesHelper;
// Initialise related data.
$menuTypes = MenusHelper::getMenuLinks();
$this->document->getWebAssetManager()
->useScript('joomla.treeselectmenu')
->useScript('com_modules.admin-module-edit-assignment');
?>
<div class="control-group">
<label id="jform_menus-lbl" class="control-label" for="jform_assignment"><?php echo Text::_('COM_MODULES_MODULE_ASSIGN'); ?></label>
<div id="jform_menus" class="controls">
<select class="form-select" name="jform[assignment]" id="jform_assignment">
<?php echo HTMLHelper::_('select.options', ModulesHelper::getAssignmentOptions($this->item->client_id), 'value', 'text', $this->item->assignment, true); ?>
</select>
</div>
</div>
<div id="menuselect-group" class="control-group">
<label id="jform_menuselect-lbl" class="control-label" for="jform_menuselect"><?php echo Text::_('JGLOBAL_MENU_SELECTION'); ?></label>
<div id="jform_menuselect" class="controls">
<?php if (!empty($menuTypes)) : ?>
<div class="card-header">
<section class="d-flex align-items-center flex-wrap w-100" aria-label="<?php echo Text::_('COM_MODULES_GLOBAL'); ?>">
<div class="d-flex align-items-center flex-fill mb-1" role="group" aria-label="<?php echo Text::_('COM_MODULES_GLOBAL_ASSIGN'); ?>"><?php echo Text::_('COM_MODULES_GLOBAL_ASSIGN'); ?>
<button id="treeCheckAll" class="btn btn-secondary btn-sm mx-1" type="button">
<?php echo Text::_('JALL'); ?>
</button>
<button id="treeUncheckAll" class="btn btn-secondary btn-sm mx-1" type="button">
<?php echo Text::_('JNONE'); ?>
</button>
</div>
<div class="d-flex align-items-center mb-1 flex-fill" role="group" aria-label="<?php echo Text::_('COM_MODULES_GLOBAL_TREE_EXPAND'); ?>"><?php echo Text::_('COM_MODULES_GLOBAL_TREE_EXPAND'); ?>
<button id="treeExpandAll" class="btn btn-secondary btn-sm mx-1" type="button">
<?php echo Text::_('JALL'); ?>
</button>
<button id="treeCollapseAll" class="btn btn-secondary btn-sm mx-1" type="button">
<?php echo Text::_('JNONE'); ?>
</button>
</div>
<div role="search" class="flex-grow-1">
<label for="treeselectfilter" class="visually-hidden"><?php echo Text::_('COM_MODULES_SEARCH_MENUITEM'); ?></label>
<input type="text" id="treeselectfilter" name="treeselectfilter" class="form-control search-query" autocomplete="off" placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>">
</div>
</section>
</div>
<div class="card-body">
<ul class="treeselect">
<?php foreach ($menuTypes as &$type) : ?>
<?php if (count($type->links)) : ?>
<?php $prevlevel = 0; ?>
<li>
<div class="treeselect-item treeselect-header">
<label class="nav-header"><?php echo $type->title; ?></label></div>
<?php foreach ($type->links as $i => $link) : ?>
<?php
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 = 0;
if ($this->item->assignment == 0) {
$selected = 1;
} elseif ($this->item->assignment < 0) {
$selected = in_array(-$link->value, $this->item->assigned);
} elseif ($this->item->assignment > 0) {
$selected = in_array($link->value, $this->item->assigned);
}
?>
<li>
<div class="treeselect-item">
<?php
$uselessMenuItem = in_array($link->type, ['separator', 'heading', 'alias', 'url']);
$id = 'jform_menuselect';
?>
<input type="checkbox" class="novalidate form-check-input" name="jform[assigned][]" id="<?php echo $id . $link->value; ?>" value="<?php echo (int) $link->value; ?>"<?php echo $selected ? ' checked="checked"' : '';
echo $uselessMenuItem ? ' disabled="disabled"' : ''; ?>>
<label for="<?php echo $id . $link->value; ?>" class="">
<?php echo $link->text; ?>
<?php if (Multilanguage::isEnabled() && $link->language != '' && $link->language != '*') : ?>
<?php if ($link->language_image) : ?>
<?php echo HTMLHelper::_('image', 'mod_languages/' . $link->language_image . '.gif', $link->language_title, ['title' => $link->language_title], true); ?>
<?php else : ?>
<?php echo '<span class="badge bg-secondary" title="' . $link->language_title . '">' . $link->language_sef . '</span>'; ?>
<?php endif; ?>
<?php endif; ?>
<?php if ($link->published == 0) : ?>
<?php echo ' <span class="badge bg-secondary">' . Text::_('JUNPUBLISHED') . '</span>'; ?>
<?php endif; ?>
<?php if ($uselessMenuItem) : ?>
<?php echo ' <span class="badge bg-secondary">' . Text::_('COM_MODULES_MENU_ITEM_' . strtoupper($link->type)) . '</span>'; ?>
<?php endif; ?>
</label>
</div>
<?php
if (!isset($type->links[$i + 1])) {
echo str_repeat('</li></ul>', $link->level);
}
$prevlevel = $link->level;
?>
<?php endforeach; ?>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<joomla-alert id="noresultsfound" type="warning" style="display:none"><?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?></joomla-alert>
<div class="hidden" id="treeselectmenu">
<div class="nav-hover treeselect-menu">
<div class="dropdown">
<button type="button" data-bs-toggle="dropdown" class="dropdown-toggle btn btn-sm btn-light">
<span class="caret"></span>
<span class="visually-hidden"><?php echo Text::sprintf('JGLOBAL_TOGGLE_DROPDOWN'); ?></span>
</button>
<div class="dropdown-menu">
<h1 class="dropdown-header"><?php echo Text::_('COM_MODULES_SUBITEMS'); ?></h1>
<div class="dropdown-divider"></div>
<a class="dropdown-item checkall" href="javascript://"><span class="icon-check-square" aria-hidden="true"></span> <?php echo Text::_('JSELECT'); ?></a>
<a class="dropdown-item uncheckall" href="javascript://"><span class="icon-square" aria-hidden="true"></span> <?php echo Text::_('COM_MODULES_DESELECT'); ?></a>
<div class="treeselect-menu-expand">
<div class="dropdown-divider"></div>
<a class="dropdown-item expandall" href="javascript://"><span class="icon-plus" aria-hidden="true"></span> <?php echo Text::_('COM_MODULES_EXPAND'); ?></a>
<a class="dropdown-item collapseall" href="javascript://"><span class="icon-minus" aria-hidden="true"></span> <?php echo Text::_('COM_MODULES_COLLAPSE'); ?></a>
</div>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>

View File

@ -0,0 +1,34 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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;
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->addInlineScript('
document.addEventListener("DOMContentLoaded", function() {
const saveCloseButton = window.parent.document.getElementById("btnModalSaveAndClose");
if (saveCloseButton) {
saveCloseButton.classList.remove("hidden");
}
});
');
?>
<button id="applyBtn" type="button" class="hidden" onclick="Joomla.submitbutton('module.apply');"></button>
<button id="saveBtn" type="button" class="hidden" onclick="Joomla.submitbutton('module.save');"></button>
<button id="closeBtn" type="button" class="hidden" onclick="Joomla.submitbutton('module.cancel');"></button>
<div class="container-popup">
<?php $this->setLayout('edit'); ?>
<?php echo $this->loadTemplate(); ?>
</div>

View File

@ -0,0 +1,220 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2008 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\Helper\ModuleHelper;
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;
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('table.columns')
->useScript('multiselect');
$clientId = (int) $this->state->get('client_id', 0);
$user = $this->getCurrentUser();
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$saveOrder = ($listOrder == 'a.ordering');
if ($saveOrder && !empty($this->items)) {
$saveOrderingUrl = 'index.php?option=com_modules&task=modules.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1';
HTMLHelper::_('draggablelist.draggable');
}
?>
<form action="<?php echo Route::_('index.php?option=com_modules&view=modules&client_id=' . $clientId); ?>" method="post" name="adminForm" id="adminForm">
<div id="j-main-container" class="j-main-container">
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?>
<?php if ($this->total > 0) : ?>
<table class="table" id="moduleList">
<caption class="visually-hidden">
<?php echo Text::_('COM_MODULES_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" 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_MODULES_HEADING_POSITION', 'a.position', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MODULES_HEADING_MODULE', 'name', $listDirn, $listOrder); ?>
</th>
<?php if ($clientId === 0) : ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MODULES_HEADING_PAGES', 'pages', $listDirn, $listOrder); ?>
</th>
<?php endif; ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ACCESS', 'ag.title', $listDirn, $listOrder); ?>
</th>
<?php if (($clientId === 0) && (Multilanguage::isEnabled())) : ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_LANGUAGE', 'l.title', $listDirn, $listOrder); ?>
</th>
<?php elseif ($clientId === 1 && ModuleHelper::isAdminMultilang()) : ?>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_LANGUAGE', 'a.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) :
?> 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');
$canCreate = $user->authorise('core.create', 'com_modules');
$canEdit = $user->authorise('core.edit', 'com_modules.module.' . $item->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_modules.module.' . $item->id) && $canCheckin;
?>
<tr class="row<?php echo $i % 2; ?>" data-draggable-group="<?php echo $item->position ?: 'none'; ?>">
<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"></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>
<td class="text-center">
<?php // Check if extension is enabled ?>
<?php if ($item->enabled > 0) : ?>
<?php echo HTMLHelper::_('jgrid.published', $item->published, $i, 'modules.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?>
<?php else : ?>
<?php // Extension is not enabled, show a message that indicates this. ?>
<span class="tbody-icon" title="<?php echo Text::sprintf('COM_MODULES_MSG_MANAGE_EXTENSION_DISABLED', $this->escape($item->name)); ?>">
<span class="icon-minus-circle" aria-hidden="true"></span>
</span>
<?php endif; ?>
</td>
<th scope="row" class="has-context">
<div>
<?php if ($item->checked_out) : ?>
<?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'modules.', $canCheckin); ?>
<?php endif; ?>
<?php if ($canEdit) : ?>
<a href="<?php echo Route::_('index.php?option=com_modules&task=module.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 if (!empty($item->note)) : ?>
<div class="small">
<?php echo Text::sprintf('JGLOBAL_LIST_NOTE', $this->escape($item->note)); ?>
</div>
<?php endif; ?>
</div>
</th>
<td class="d-none d-md-table-cell">
<?php if ($item->position) : ?>
<span class="badge bg-info">
<?php echo $item->position; ?>
</span>
<?php else : ?>
<span class="badge bg-secondary">
<?php echo Text::_('JNONE'); ?>
</span>
<?php endif; ?>
</td>
<td class="small d-none d-md-table-cell">
<?php echo $item->name; ?>
</td>
<?php if ($clientId === 0) : ?>
<td class="small d-none d-md-table-cell">
<?php echo $item->pages; ?>
</td>
<?php endif; ?>
<td class="small d-none d-md-table-cell">
<?php echo $this->escape($item->access_level); ?>
</td>
<?php if (($clientId === 0) && (Multilanguage::isEnabled())) : ?>
<td class="small d-none d-md-table-cell">
<?php echo LayoutHelper::render('joomla.content.language', $item); ?>
</td>
<?php elseif ($clientId === 1 && ModuleHelper::isAdminMultilang()) : ?>
<td class="small d-none d-md-table-cell">
<?php if ($item->language == '') :?>
<?php echo Text::_('JUNDEFINED'); ?>
<?php elseif ($item->language == '*') :?>
<?php echo Text::alt('JALL', 'language'); ?>
<?php else :?>
<?php echo $this->escape($item->language); ?>
<?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; ?>
<?php // Load the batch processing form. ?>
<?php
if (
$user->authorise('core.create', 'com_modules')
&& $user->authorise('core.edit', 'com_modules')
&& $user->authorise('core.edit.state', 'com_modules')
) : ?>
<?php echo HTMLHelper::_(
'bootstrap.renderModal',
'collapseModal',
[
'title' => Text::_('COM_MODULES_BATCH_OPTIONS'),
'footer' => $this->loadTemplate('batch_footer'),
],
$this->loadTemplate('batch_body')
); ?>
<?php endif; ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="boxchecked" value="0">
<?php echo HTMLHelper::_('form.token'); ?>
</div>
</form>

View File

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

View File

@ -0,0 +1,83 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Helper\ModuleHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\Component\Modules\Administrator\Helper\ModulesHelper;
$clientId = $this->state->get('client_id');
// Show only Module Positions of published Templates
$published = 1;
$positions = HTMLHelper::_('modules.positions', $clientId, $published);
$positions['']['items'][] = ModulesHelper::createOption('nochange', Text::_('COM_MODULES_BATCH_POSITION_NOCHANGE'));
$positions['']['items'][] = ModulesHelper::createOption('noposition', Text::_('COM_MODULES_BATCH_POSITION_NOPOSITION'));
// Build field
$attr = [
'id' => 'batch-position-id',
];
Text::script('JGLOBAL_SELECT_NO_RESULTS_MATCH');
Text::script('JGLOBAL_SELECT_PRESS_TO_SELECT');
$this->document->getWebAssetManager()
->usePreset('choicesjs')
->useScript('webcomponent.field-fancy-select')
->useScript('joomla.batch-copymove');
?>
<div class="p-3">
<p><?php echo Text::_('COM_MODULES_BATCH_TIP'); ?></p>
<div class="row">
<?php if ($clientId != 1) : ?>
<div class="form-group col-md-6">
<div class="controls">
<?php echo LayoutHelper::render('joomla.html.batch.language', []); ?>
</div>
</div>
<?php elseif ($clientId == 1 && ModuleHelper::isAdminMultilang()) : ?>
<div class="form-group col-md-6">
<div class="controls">
<?php echo LayoutHelper::render('joomla.html.batch.adminlanguage', []); ?>
</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>
<div class="row">
<?php if ($published >= 0) : ?>
<div class="col-md-6">
<div class="controls">
<label id="batch-choose-action-lbl" for="batch-choose-action">
<?php echo Text::_('COM_MODULES_BATCH_POSITION_LABEL'); ?>
</label>
<div id="batch-choose-action">
<joomla-field-fancy-select allow-custom search-placeholder="<?php echo $this->escape(Text::_('COM_MODULES_TYPE_OR_SELECT_POSITION')); ?>">
<?php echo HTMLHelper::_('select.groupedlist', $positions, 'batch[position_id]', $attr); ?>
</joomla-field-fancy-select>
<div id="batch-copy-move" class="control-group radio">
<?php echo HTMLHelper::_('modules.batchOptions'); ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>

View File

@ -0,0 +1,21 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Language\Text;
?>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('batch-position-id').value='';document.getElementById('batch-access').value='';document.getElementById('batch-language-id').value=''" data-bs-dismiss="modal">
<?php echo Text::_('JCANCEL'); ?>
</button>
<button type="submit" class="btn btn-success" onclick="Joomla.submitbutton('module.batch');return false;">
<?php echo Text::_('JGLOBAL_BATCH_PROCESS'); ?>
</button>

View File

@ -0,0 +1,29 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2021 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\CMS\Layout\LayoutHelper;
$displayData = [
'textPrefix' => 'COM_MODULES',
'formURL' => 'index.php?option=com_modules&view=select&client_id=' . $this->clientId,
'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Module',
'icon' => 'icon-cube module',
// Although it is (almost) impossible to get to this page with no created Administrator Modules, we add this for completeness.
'title' => Text::_('COM_MODULES_EMPTYSTATE_TITLE_' . ($this->clientId ? 'ADMINISTRATOR' : 'SITE')),
];
if ($this->getCurrentUser()->authorise('core.create', 'com_modules')) {
$displayData['createURL'] = 'index.php?option=com_modules&view=select&client_id=' . $this->clientId;
}
echo LayoutHelper::render('joomla.content.emptystate', $displayData);

View File

@ -0,0 +1,150 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
if (Factory::getApplication()->isClient('site')) {
Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
}
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('com_modules.admin-modules-modal')->useScript('modal-content-select');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
$editor = Factory::getApplication()->getInput()->get('editor', '', 'cmd');
$link = 'index.php?option=com_modules&view=modules&layout=modal&tmpl=component&' . Session::getFormToken() . '=1';
if (!empty($editor)) {
$link .= '&editor=' . $editor;
}
?>
<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]); ?>
<?php if ($this->total > 0) : ?>
<table class="table" id="moduleList">
<caption class="visually-hidden">
<?php echo Text::_('COM_MODULES_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="w-15 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MODULES_HEADING_POSITION', 'a.position', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MODULES_HEADING_MODULE', 'name', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'COM_MODULES_HEADING_PAGES', 'pages', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ACCESS', 'ag.title', $listDirn, $listOrder); ?>
</th>
<th scope="col" class="w-10 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_LANGUAGE', 'l.title', $listDirn, $listOrder); ?>
</th>
<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
$iconStates = [
-2 => 'icon-trash',
0 => 'icon-times',
1 => 'icon-check',
2 => 'icon-folder',
];
foreach ($this->items as $i => $item) :
$attrs = 'data-content-select data-content-type="com_modules.module"'
. ' data-id="' . $item->id . '"'
. ' data-title="' . $this->escape($item->title) . '"'
. ' data-position="' . $this->escape($item->position) . '"'
. ' data-module-element="' . $this->escape($item->module) . '"'
// @TODO: Remove data-editor and data-module after full transition to postMessage()
. ' data-editor="' . $this->escape($editor) . '"'
. ' data-module="' . ((int) $item->id) . '"';
$attrs1 = $attrs;
$attrs1 .= ' data-html="{loadmoduleid ' . ((int) $item->id) . '}"';
$attrs2 = $attrs;
$attrs2 .= ' data-html="{loadposition ' . $this->escape($item->position) . '}"';
?>
<tr class="row<?php echo $i % 2; ?>">
<td class="text-center">
<span class="tbody-icon">
<span class="<?php echo $iconStates[$this->escape($item->published)]; ?>" aria-hidden="true"></span>
</span>
</td>
<th scope="row" class="has-context">
<button type="button" class="js-module-insert btn btn-sm btn-success w-100" <?php echo $attrs1; ?>>
<?php echo $this->escape($item->title); ?>
</button>
</th>
<td class="small d-none d-md-table-cell">
<?php if ($item->position) : ?>
<button type="button" class="js-position-insert btn btn-sm btn-warning w-100" <?php echo $attrs2; ?>><?php echo $this->escape($item->position); ?></button>
<?php else : ?>
<span class="btn btn-sm btn-secondary w-100"><?php echo Text::_('JNONE'); ?></span>
<?php endif; ?>
</td>
<td class="small d-none d-md-table-cell">
<?php echo $item->name; ?>
</td>
<td class="small d-none d-md-table-cell">
<?php echo $item->pages; ?>
</td>
<td class="small d-none d-md-table-cell">
<?php echo $this->escape($item->access_level); ?>
</td>
<td class="small d-none d-md-table-cell">
<?php echo LayoutHelper::render('joomla.content.language', $item); ?>
</td>
<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="editor" value="<?php echo $editor; ?>" />
<?php echo HTMLHelper::_('form.token'); ?>
</form>
</div>

View File

@ -0,0 +1,82 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @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\Text;
use Joomla\CMS\Router\Route;
$app = Factory::getApplication();
$function = $app->getInput()->getCmd('function');
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('com_modules.admin-module-search');
if ($function) :
$wa->useScript('com_modules.admin-select-modal');
endif;
?>
<div class="d-none" id="comModulesSelectSearchContainer">
<div class="d-flex mt-2">
<div class="m-auto">
<label class="visually-hidden" for="comModulesSelectSearch">
<?php echo Text::_('COM_MODULES_TYPE_CHOOSE'); ?>
</label>
<div class="input-group mb-3 me-sm-2">
<input type="text" value=""
class="form-control" id="comModulesSelectSearch"
placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>"
>
<div class="input-group-text">
<span class="icon-search" aria-hidden="true"></span>
</div>
</div>
</div>
</div>
</div>
<div id="new-modules-list">
<div class="new-modules">
<div class="modules-alert alert alert-info d-none">
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
<?php echo Text::_('COM_MODULES_MSG_MANAGE_NO_MODULES'); ?>
</div>
<h2 class="pb-3 ms-3" id="comModulesSelectTypeHeader">
<?php echo Text::_('COM_MODULES_TYPE_CHOOSE'); ?>
</h2>
<div class="main-card card-columns p-4" id="comModulesSelectResultsContainer">
<?php foreach ($this->items as &$item) : ?>
<?php // Prepare variables for the link. ?>
<?php $link = 'index.php?option=com_modules&task=module.add&client_id=' . $this->state->get('client_id', 0) . $this->modalLink . '&eid=' . $item->extension_id; ?>
<?php $name = $this->escape($item->name); ?>
<?php $desc = HTMLHelper::_('string.truncate', $this->escape(strip_tags($item->desc)), 200); ?>
<a href="<?php echo Route::_($link); ?>" class="new-module mb-3 comModulesSelectCard"
<?php echo !empty($function) ? 'data-function="' . $this->escape($function) . '"' : ''; ?>
aria-label="<?php echo Text::sprintf('COM_MODULES_SELECT_MODULE', $name); ?>">
<div class="new-module-details">
<h3 class="new-module-title"><?php echo $name; ?></h3>
<p class="new-module-caption p-0">
<?php echo $desc; ?>
</p>
</div>
<span class="new-module-link">
<span class="icon-plus" aria-hidden="true"></span>
</span>
</a>
<?php endforeach; ?>
</div>
</div>
</div>

View File

@ -0,0 +1,18 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_modules
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
$this->modalLink = '&tmpl=component&view=module&layout=modal';
?>
<div class="container-popup">
<?php $this->setLayout('default'); ?>
<?php echo $this->loadTemplate(); ?>
</div>