primo commit
This commit is contained in:
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Templates\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Templates manager display controller.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class DisplayController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var string The default view.
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $default_view = 'styles';
|
||||
|
||||
/**
|
||||
* Method to display a view.
|
||||
*
|
||||
* @param boolean $cachable If true, the view output will be cached
|
||||
* @param 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)
|
||||
{
|
||||
$view = $this->input->get('view', 'styles');
|
||||
$layout = $this->input->get('layout', 'default');
|
||||
$id = $this->input->getInt('id');
|
||||
|
||||
// For JSON requests
|
||||
if ($this->app->getDocument()->getType() == 'json') {
|
||||
return parent::display();
|
||||
}
|
||||
|
||||
// Check for edit form.
|
||||
if ($view == 'style' && $layout == 'edit' && !$this->checkEditId('com_templates.edit.style', $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_templates&view=styles', false));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::display();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Application\CMSWebApplicationInterface;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\FormController;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template style controller class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class StyleController extends FormController
|
||||
{
|
||||
/**
|
||||
* The prefix to use with controller messages.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $text_prefix = 'COM_TEMPLATES_STYLE';
|
||||
|
||||
/**
|
||||
* Method to save a template style.
|
||||
*
|
||||
* @param string $key The name of the primary key of the URL variable.
|
||||
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
|
||||
*
|
||||
* @return boolean True if successful, false otherwise.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function save($key = null, $urlVar = null)
|
||||
{
|
||||
$this->checkToken();
|
||||
|
||||
if ($this->app->getDocument()->getType() === 'json') {
|
||||
$model = $this->getModel('Style', 'Administrator');
|
||||
$table = $model->getTable();
|
||||
$data = $this->input->post->get('params', [], 'array');
|
||||
$checkin = $table->hasField('checked_out');
|
||||
$context = $this->option . '.edit.' . $this->context;
|
||||
|
||||
$item = $model->getItem($this->app->getTemplate(true)->id);
|
||||
|
||||
// Setting received params
|
||||
$item->set('params', $data);
|
||||
|
||||
$data = $item->getProperties();
|
||||
unset($data['xml']);
|
||||
|
||||
$key = $table->getKeyName();
|
||||
|
||||
// Access check.
|
||||
if (!$this->allowSave($data, $key)) {
|
||||
$this->app->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Form::addFormPath(JPATH_ADMINISTRATOR . '/components/com_templates/forms');
|
||||
|
||||
// Validate the posted data.
|
||||
// Sometimes the form needs some posted data, such as for plugins and modules.
|
||||
$form = $model->getForm($data, false);
|
||||
|
||||
if (!$form) {
|
||||
$this->app->enqueueMessage($model->getError(), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test whether the data is valid.
|
||||
$validData = $model->validate($form, $data);
|
||||
|
||||
if ($validData === false) {
|
||||
// Get the validation messages.
|
||||
$errors = $model->getErrors();
|
||||
|
||||
// Push up to three validation messages out to the user.
|
||||
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
|
||||
if ($errors[$i] instanceof \Exception) {
|
||||
$this->app->enqueueMessage($errors[$i]->getMessage(), CMSWebApplicationInterface::MSG_ERROR);
|
||||
} else {
|
||||
$this->app->enqueueMessage($errors[$i], CMSWebApplicationInterface::MSG_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the data in the session.
|
||||
$this->app->setUserState($context . '.data', $data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($validData['tags'])) {
|
||||
$validData['tags'] = null;
|
||||
}
|
||||
|
||||
// Attempt to save the data.
|
||||
if (!$model->save($validData)) {
|
||||
// Save the data in the session.
|
||||
$this->app->setUserState($context . '.data', $validData);
|
||||
|
||||
$this->app->enqueueMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save succeeded, so check-in the record.
|
||||
if ($checkin && $model->checkin($validData[$key]) === false) {
|
||||
// Save the data in the session.
|
||||
$this->app->setUserState($context . '.data', $validData);
|
||||
|
||||
// Check-in failed, so go back to the record and display a notice.
|
||||
$this->app->enqueueMessage(Text::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Redirect the user and adjust session state
|
||||
// Set the record data in the session.
|
||||
$recordId = $model->getState($this->context . '.id');
|
||||
$this->holdEditId($context, $recordId);
|
||||
$this->app->setUserState($context . '.data', null);
|
||||
$model->checkout($recordId);
|
||||
|
||||
// Invoke the postSave method to allow for the child class to access the model.
|
||||
$this->postSaveHook($model, $validData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::save($key, $urlVar);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\AdminController;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template styles list controller class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class StylesController extends AdminController
|
||||
{
|
||||
/**
|
||||
* Method to clone and existing template style.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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_TEMPLATES_NO_TEMPLATE_SELECTED'));
|
||||
}
|
||||
|
||||
$model = $this->getModel();
|
||||
$model->duplicate($pks);
|
||||
$this->setMessage(Text::_('COM_TEMPLATES_SUCCESS_DUPLICATED'));
|
||||
} catch (\Exception $e) {
|
||||
$this->app->enqueueMessage($e->getMessage(), 'error');
|
||||
}
|
||||
|
||||
$this->setRedirect('index.php?option=com_templates&view=styles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy for getModel.
|
||||
*
|
||||
* @param string $name The model name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $config Configuration array for model. Optional.
|
||||
*
|
||||
* @return BaseDatabaseModel
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function getModel($name = 'Style', $prefix = 'Administrator', $config = [])
|
||||
{
|
||||
return parent::getModel($name, $prefix, ['ignore_request' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the home template for a client.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function setDefault()
|
||||
{
|
||||
// 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_TEMPLATES_NO_TEMPLATE_SELECTED'));
|
||||
}
|
||||
|
||||
// Pop off the first element.
|
||||
$id = array_shift($pks);
|
||||
|
||||
/** @var \Joomla\Component\Templates\Administrator\Model\StyleModel $model */
|
||||
$model = $this->getModel();
|
||||
$model->setHome($id);
|
||||
$this->setMessage(Text::_('COM_TEMPLATES_SUCCESS_HOME_SET'));
|
||||
} catch (\Exception $e) {
|
||||
$this->setMessage($e->getMessage(), 'warning');
|
||||
}
|
||||
|
||||
$this->setRedirect('index.php?option=com_templates&view=styles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to unset the default template for a client and for a language
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function unsetDefault()
|
||||
{
|
||||
// Check for request forgeries
|
||||
$this->checkToken('request');
|
||||
|
||||
$pks = (array) $this->input->get->get('cid', [], 'int');
|
||||
|
||||
// Remove zero values resulting from input filter
|
||||
$pks = array_filter($pks);
|
||||
|
||||
try {
|
||||
if (empty($pks)) {
|
||||
throw new \Exception(Text::_('COM_TEMPLATES_NO_TEMPLATE_SELECTED'));
|
||||
}
|
||||
|
||||
// Pop off the first element.
|
||||
$id = array_shift($pks);
|
||||
|
||||
/** @var \Joomla\Component\Templates\Administrator\Model\StyleModel $model */
|
||||
$model = $this->getModel();
|
||||
$model->unsetHome($id);
|
||||
$this->setMessage(Text::_('COM_TEMPLATES_SUCCESS_HOME_UNSET'));
|
||||
} catch (\Exception $e) {
|
||||
$this->setMessage($e->getMessage(), 'warning');
|
||||
}
|
||||
|
||||
$this->setRedirect('index.php?option=com_templates&view=styles');
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Extension;
|
||||
|
||||
use Joomla\CMS\Extension\BootableExtensionInterface;
|
||||
use Joomla\CMS\Extension\MVCComponent;
|
||||
use Joomla\CMS\HTML\HTMLRegistryAwareTrait;
|
||||
use Joomla\Component\Templates\Administrator\Service\HTML\Templates;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Component class for com_templates
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class TemplatesComponent 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('templates', new Templates());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Field;
|
||||
|
||||
use Joomla\CMS\Form\Field\ListField;
|
||||
use Joomla\Component\Templates\Administrator\Helper\TemplatesHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template Location field.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class TemplatelocationField extends ListField
|
||||
{
|
||||
/**
|
||||
* The form field type.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.5
|
||||
*/
|
||||
protected $type = 'TemplateLocation';
|
||||
|
||||
/**
|
||||
* Method to get the field options.
|
||||
*
|
||||
* @return array The field option objects.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
$options = TemplatesHelper::getClientOptions();
|
||||
|
||||
return array_merge(parent::getOptions(), $options);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Field;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Form\Field\ListField;
|
||||
use Joomla\Component\Templates\Administrator\Helper\TemplatesHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template Name field.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class TemplatenameField extends ListField
|
||||
{
|
||||
/**
|
||||
* The form field type.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.5
|
||||
*/
|
||||
protected $type = 'TemplateName';
|
||||
|
||||
/**
|
||||
* Method to get the field options.
|
||||
*
|
||||
* @return array The field option objects.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
// Get the client_id filter from the user state.
|
||||
$clientId = Factory::getApplication()->getUserStateFromRequest('com_templates.styles.client_id', 'client_id', '0', 'string');
|
||||
|
||||
// Get the templates for the selected client_id.
|
||||
$options = TemplatesHelper::getTemplateOptions($clientId);
|
||||
|
||||
// Merge into the parent options.
|
||||
return array_merge(parent::getOptions(), $options);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Helper;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template Helper class.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
abstract class TemplateHelper
|
||||
{
|
||||
/**
|
||||
* Checks if the file is an image
|
||||
*
|
||||
* @param string $fileName The filename
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function getTypeIcon($fileName)
|
||||
{
|
||||
// Get file extension
|
||||
return strtolower(substr($fileName, strrpos($fileName, '.') + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file can be uploaded
|
||||
*
|
||||
* @param array $file File information
|
||||
* @param string $err An error message to be returned
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function canUpload($file, $err = '')
|
||||
{
|
||||
$params = ComponentHelper::getParams('com_templates');
|
||||
|
||||
if (empty($file['name'])) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_UPLOAD_INPUT'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Media file names should never have executable extensions buried in them.
|
||||
$executable = [
|
||||
'exe', 'phtml','java', 'perl', 'py', 'asp','dll', 'go', 'jar',
|
||||
'ade', 'adp', 'bat', 'chm', 'cmd', 'com', 'cpl', 'hta', 'ins', 'isp',
|
||||
'jse', 'lib', 'mde', 'msc', 'msp', 'mst', 'pif', 'scr', 'sct', 'shb',
|
||||
'sys', 'vb', 'vbe', 'vbs', 'vxd', 'wsc', 'wsf', 'wsh',
|
||||
];
|
||||
$explodedFileName = explode('.', $file['name']);
|
||||
|
||||
if (\count($explodedFileName) > 2) {
|
||||
foreach ($executable as $extensionName) {
|
||||
if (\in_array($extensionName, $explodedFileName)) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_EXECUTABLE'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($file['name'] !== File::makeSafe($file['name']) || preg_match('/\s/', File::makeSafe($file['name']))) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_WARNFILENAME'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$format = strtolower(File::getExt($file['name']));
|
||||
|
||||
$imageTypes = explode(',', $params->get('image_formats', 'gif,bmp,jpg,jpeg,png,webp'));
|
||||
$sourceTypes = explode(',', $params->get('source_formats', 'txt,less,ini,xml,js,php,css,scss,sass,json'));
|
||||
$fontTypes = explode(',', $params->get('font_formats', 'woff,woff2,ttf,otf'));
|
||||
$archiveTypes = explode(',', $params->get('compressed_formats', 'zip'));
|
||||
|
||||
$allowable = array_merge($imageTypes, $sourceTypes, $fontTypes, $archiveTypes);
|
||||
|
||||
if ($format == '' || $format == false || (!\in_array($format, $allowable))) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_WARNFILETYPE'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\in_array($format, $archiveTypes)) {
|
||||
$zip = new \ZipArchive();
|
||||
|
||||
if ($zip->open($file['tmp_name']) === true) {
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$entry = $zip->getNameIndex($i);
|
||||
$endString = substr($entry, -1);
|
||||
|
||||
if ($endString != DIRECTORY_SEPARATOR) {
|
||||
$explodeArray = explode('.', $entry);
|
||||
$ext = end($explodeArray);
|
||||
|
||||
if (!\in_array($ext, $allowable)) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_FILE_UNSUPPORTED_ARCHIVE'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_FILE_ARCHIVE_OPEN_FAIL'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Max upload size set to 10 MB for Template Manager
|
||||
$maxSize = (int) ($params->get('upload_limit') * 1024 * 1024);
|
||||
|
||||
if ($maxSize > 0 && (int) $file['size'] > $maxSize) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_WARNFILETOOLARGE'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$xss_check = file_get_contents($file['tmp_name'], false, null, -1, 256);
|
||||
$html_tags = [
|
||||
'abbr', 'acronym', 'address', 'applet', 'area', 'audioscope', 'base', 'basefont', 'bdo', 'bgsound', 'big', 'blackface', 'blink', 'blockquote',
|
||||
'body', 'bq', 'br', 'button', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'comment', 'custom', 'dd', 'del', 'dfn', 'dir', 'div',
|
||||
'dl', 'dt', 'em', 'embed', 'fieldset', 'fn', 'font', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html',
|
||||
'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'keygen', 'kbd', 'label', 'layer', 'legend', 'li', 'limittext', 'link', 'listing',
|
||||
'map', 'marquee', 'menu', 'meta', 'multicol', 'nobr', 'noembed', 'noframes', 'noscript', 'nosmartquotes', 'object', 'ol', 'optgroup', 'option',
|
||||
'param', 'plaintext', 'pre', 'rt', 'ruby', 's', 'samp', 'script', 'select', 'server', 'shadow', 'sidebar', 'small', 'spacer', 'span', 'strike',
|
||||
'strong', 'style', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'tt', 'ul', 'var', 'wbr', 'xml',
|
||||
'xmp', '!DOCTYPE', '!--',
|
||||
];
|
||||
|
||||
foreach ($html_tags as $tag) {
|
||||
// A tag is '<tagname ', so we need to add < and a space or '<tagname>'
|
||||
if (stristr($xss_check, '<' . $tag . ' ') || stristr($xss_check, '<' . $tag . '>')) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_ERROR_WARNIEXSS'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Helper;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Installer\Installer;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Object\CMSObject;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Filesystem\Path;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Templates component helper.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class TemplatesHelper
|
||||
{
|
||||
/**
|
||||
* Get a list of filter options for the application clients.
|
||||
*
|
||||
* @return array An array of HtmlOption 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 filter options for the templates with styles.
|
||||
*
|
||||
* @param mixed $clientId The CMS client id (0:site | 1:administrator) or '*' for all.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getTemplateOptions($clientId = '*')
|
||||
{
|
||||
// Build the filter options.
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
$query->select($db->quoteName('element', 'value'))
|
||||
->select($db->quoteName('name', 'text'))
|
||||
->select($db->quoteName('extension_id', 'e_id'))
|
||||
->from($db->quoteName('#__extensions'))
|
||||
->where($db->quoteName('type') . ' = ' . $db->quote('template'))
|
||||
->where($db->quoteName('enabled') . ' = 1')
|
||||
->order($db->quoteName('client_id') . ' ASC')
|
||||
->order($db->quoteName('name') . ' ASC');
|
||||
|
||||
if ($clientId != '*') {
|
||||
$clientId = (int) $clientId;
|
||||
$query->where($db->quoteName('client_id') . ' = :clientid')
|
||||
->bind(':clientid', $clientId, ParameterType::INTEGER);
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
$options = $db->loadObjectList();
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $templateBaseDir
|
||||
* @param string $templateDir
|
||||
*
|
||||
* @return boolean|CMSObject
|
||||
*/
|
||||
public static function parseXMLTemplateFile($templateBaseDir, $templateDir)
|
||||
{
|
||||
$data = new CMSObject();
|
||||
|
||||
// Check of the xml file exists
|
||||
$filePath = Path::clean($templateBaseDir . '/templates/' . $templateDir . '/templateDetails.xml');
|
||||
|
||||
if (is_file($filePath)) {
|
||||
$xml = Installer::parseXMLInstallFile($filePath);
|
||||
|
||||
if ($xml['type'] != 'template') {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($xml as $key => $value) {
|
||||
$data->set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $clientId
|
||||
* @param string $templateDir
|
||||
*
|
||||
* @return boolean|array
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static function getPositions($clientId, $templateDir)
|
||||
{
|
||||
$positions = [];
|
||||
|
||||
$templateBaseDir = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE;
|
||||
$filePath = Path::clean($templateBaseDir . '/templates/' . $templateDir . '/templateDetails.xml');
|
||||
|
||||
if (is_file($filePath)) {
|
||||
// Read the file to see if it's a valid component XML file
|
||||
$xml = simplexml_load_file($filePath);
|
||||
|
||||
if (!$xml) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for a valid XML root tag.
|
||||
|
||||
// Extensions use 'extension' as the root tag. Languages use 'metafile' instead
|
||||
|
||||
if ($xml->getName() != 'extension' && $xml->getName() != 'metafile') {
|
||||
unset($xml);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$positions = (array) $xml->positions;
|
||||
|
||||
if (isset($positions['position'])) {
|
||||
$positions = (array) $positions['position'];
|
||||
} else {
|
||||
$positions = [];
|
||||
}
|
||||
}
|
||||
|
||||
return $positions;
|
||||
}
|
||||
}
|
||||
794
administrator/components/com_templates/src/Model/StyleModel.php
Normal file
794
administrator/components/com_templates/src/Model/StyleModel.php
Normal file
@ -0,0 +1,794 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||
use Joomla\CMS\MVC\Model\AdminModel;
|
||||
use Joomla\CMS\Object\CMSObject;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Filesystem\Path;
|
||||
use Joomla\Registry\Registry;
|
||||
use Joomla\String\StringHelper;
|
||||
use Joomla\Utilities\ArrayHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template style model.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class StyleModel extends AdminModel
|
||||
{
|
||||
/**
|
||||
* The help screen key for the module.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $helpKey = 'Templates:_Edit_Style';
|
||||
|
||||
/**
|
||||
* The help screen base URL for the module.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $helpURL;
|
||||
|
||||
/**
|
||||
* Item cache.
|
||||
*
|
||||
* @var array
|
||||
* @since 1.6
|
||||
*/
|
||||
private $_cache = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config An optional associative array of configuration settings.
|
||||
* @param ?MVCFactoryInterface $factory The factory.
|
||||
*
|
||||
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
|
||||
* @since 3.2
|
||||
*/
|
||||
public function __construct($config = [], ?MVCFactoryInterface $factory = null)
|
||||
{
|
||||
$config = array_merge(
|
||||
[
|
||||
'event_before_delete' => 'onExtensionBeforeDelete',
|
||||
'event_after_delete' => 'onExtensionAfterDelete',
|
||||
'event_before_save' => 'onExtensionBeforeSave',
|
||||
'event_after_save' => 'onExtensionAfterSave',
|
||||
'events_map' => ['delete' => 'extension', 'save' => 'extension'],
|
||||
],
|
||||
$config
|
||||
);
|
||||
|
||||
parent::__construct($config, $factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* @note Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function populateState()
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// Load the User state.
|
||||
$pk = $app->getInput()->getInt('id');
|
||||
$this->setState('style.id', $pk);
|
||||
|
||||
// Load the parameters.
|
||||
$params = ComponentHelper::getParams('com_templates');
|
||||
$this->setState('params', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to delete rows.
|
||||
*
|
||||
* @param array &$pks An array of item ids.
|
||||
*
|
||||
* @return boolean Returns true on success, false on failure.
|
||||
*
|
||||
* @since 1.6
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(&$pks)
|
||||
{
|
||||
$pks = (array) $pks;
|
||||
$user = $this->getCurrentUser();
|
||||
$table = $this->getTable();
|
||||
$context = $this->option . '.' . $this->name;
|
||||
|
||||
PluginHelper::importPlugin($this->events_map['delete']);
|
||||
|
||||
// Iterate the items to delete each one.
|
||||
foreach ($pks as $pk) {
|
||||
if ($table->load($pk)) {
|
||||
// Access checks.
|
||||
if (!$user->authorise('core.delete', 'com_templates')) {
|
||||
throw new \Exception(Text::_('JERROR_CORE_DELETE_NOT_PERMITTED'));
|
||||
}
|
||||
|
||||
// You should not delete a default style
|
||||
if ($table->home != '0') {
|
||||
Factory::getApplication()->enqueueMessage(Text::_('COM_TEMPLATES_STYLE_CANNOT_DELETE_DEFAULT_STYLE'), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trigger the before delete event.
|
||||
$result = Factory::getApplication()->triggerEvent($this->event_before_delete, [$context, $table]);
|
||||
|
||||
if (\in_array(false, $result, true) || !$table->delete($pk)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trigger the after delete event.
|
||||
Factory::getApplication()->triggerEvent($this->event_after_delete, [$context, $table]);
|
||||
} else {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean cache
|
||||
$this->cleanCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to duplicate styles.
|
||||
*
|
||||
* @param array &$pks An array of primary key IDs.
|
||||
*
|
||||
* @return boolean True if successful.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function duplicate(&$pks)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
// Access checks.
|
||||
if (!$user->authorise('core.create', 'com_templates')) {
|
||||
throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED'));
|
||||
}
|
||||
|
||||
$context = $this->option . '.' . $this->name;
|
||||
|
||||
// Include the plugins for the save events.
|
||||
PluginHelper::importPlugin($this->events_map['save']);
|
||||
|
||||
$table = $this->getTable();
|
||||
|
||||
foreach ($pks as $pk) {
|
||||
if ($table->load($pk, true)) {
|
||||
// Reset the id to create a new record.
|
||||
$table->id = 0;
|
||||
|
||||
// Reset the home (don't want dupes of that field).
|
||||
$table->home = 0;
|
||||
|
||||
// Alter the title.
|
||||
$m = null;
|
||||
$table->title = $this->generateNewTitle(null, null, $table->title);
|
||||
|
||||
if (!$table->check()) {
|
||||
throw new \Exception($table->getError());
|
||||
}
|
||||
|
||||
// Trigger the before save event.
|
||||
$result = Factory::getApplication()->triggerEvent($this->event_before_save, [$context, &$table, true]);
|
||||
|
||||
if (\in_array(false, $result, true) || !$table->store()) {
|
||||
throw new \Exception($table->getError());
|
||||
}
|
||||
|
||||
// Trigger the after save event.
|
||||
Factory::getApplication()->triggerEvent($this->event_after_save, [$context, &$table, true]);
|
||||
} else {
|
||||
throw new \Exception($table->getError());
|
||||
}
|
||||
}
|
||||
|
||||
// Clean cache
|
||||
$this->cleanCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to change the title.
|
||||
*
|
||||
* @param integer $categoryId The id of the category.
|
||||
* @param string $alias The alias.
|
||||
* @param string $title The title.
|
||||
*
|
||||
* @return string New title.
|
||||
*
|
||||
* @since 1.7.1
|
||||
*/
|
||||
protected function generateNewTitle($categoryId, $alias, $title)
|
||||
{
|
||||
// Alter the title
|
||||
$table = $this->getTable();
|
||||
|
||||
while ($table->load(['title' => $title])) {
|
||||
$title = StringHelper::increment($title);
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the record form.
|
||||
*
|
||||
* @param array $data An optional array of data for the form to interrogate.
|
||||
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
|
||||
*
|
||||
* @return Form A Form object on success, false on failure
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function getForm($data = [], $loadData = true)
|
||||
{
|
||||
// The folder and element vars are passed when saving the form.
|
||||
if (empty($data)) {
|
||||
$item = $this->getItem();
|
||||
$clientId = $item->client_id;
|
||||
$template = $item->template;
|
||||
} else {
|
||||
$clientId = ArrayHelper::getValue($data, 'client_id');
|
||||
$template = ArrayHelper::getValue($data, 'template');
|
||||
}
|
||||
|
||||
// Add the default fields directory
|
||||
$baseFolder = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE;
|
||||
Form::addFieldPath($baseFolder . '/templates/' . $template . '/field');
|
||||
|
||||
// These variables are used to add data from the plugin XML files.
|
||||
$this->setState('item.client_id', $clientId);
|
||||
$this->setState('item.template', $template);
|
||||
|
||||
// Get the form.
|
||||
$form = $this->loadForm('com_templates.style', 'style', ['control' => 'jform', 'load_data' => $loadData]);
|
||||
|
||||
if (empty($form)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Modify the form based on access controls.
|
||||
if (!$this->canEditState((object) $data)) {
|
||||
// Disable fields for display.
|
||||
$form->setFieldAttribute('home', 'disabled', 'true');
|
||||
|
||||
// Disable fields while saving.
|
||||
// The controller has already verified this is a record you can edit.
|
||||
$form->setFieldAttribute('home', 'filter', 'unset');
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the data that should be injected in the form.
|
||||
*
|
||||
* @return mixed The data for the form.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function loadFormData()
|
||||
{
|
||||
// Check the session for previously entered form data.
|
||||
$data = Factory::getApplication()->getUserState('com_templates.edit.style.data', []);
|
||||
|
||||
if (empty($data)) {
|
||||
$data = $this->getItem();
|
||||
}
|
||||
|
||||
$this->preprocessData('com_templates.style', $data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a single record.
|
||||
*
|
||||
* @param integer $pk The id of the primary key.
|
||||
*
|
||||
* @return mixed Object on success, false on failure.
|
||||
*/
|
||||
public function getItem($pk = null)
|
||||
{
|
||||
$pk = (!empty($pk)) ? $pk : (int) $this->getState('style.id');
|
||||
|
||||
if (!isset($this->_cache[$pk])) {
|
||||
// Get a row instance.
|
||||
$table = $this->getTable();
|
||||
|
||||
// Attempt to load the row.
|
||||
$return = $table->load($pk);
|
||||
|
||||
// Check for a table object error.
|
||||
if ($return === false && $table->getError()) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to the \Joomla\CMS\Object\CMSObject before adding other data.
|
||||
$properties = $table->getProperties(1);
|
||||
$this->_cache[$pk] = ArrayHelper::toObject($properties, CMSObject::class);
|
||||
|
||||
// Convert the params field to an array.
|
||||
$registry = new Registry($table->params);
|
||||
$this->_cache[$pk]->params = $registry->toArray();
|
||||
|
||||
// Get the template XML.
|
||||
$client = ApplicationHelper::getClientInfo($table->client_id);
|
||||
$path = Path::clean($client->path . '/templates/' . $table->template . '/templateDetails.xml');
|
||||
|
||||
if (file_exists($path)) {
|
||||
$this->_cache[$pk]->xml = simplexml_load_file($path);
|
||||
} else {
|
||||
$this->_cache[$pk]->xml = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_cache[$pk];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to allow derived classes to preprocess the form.
|
||||
*
|
||||
* @param Form $form A Form object.
|
||||
* @param mixed $data The data expected for the form.
|
||||
* @param string $group The name of the plugin group to import (defaults to "content").
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
* @throws \Exception if there is an error in the form event.
|
||||
*/
|
||||
protected function preprocessForm(Form $form, $data, $group = 'content')
|
||||
{
|
||||
$clientId = $this->getState('item.client_id');
|
||||
$template = $this->getState('item.template');
|
||||
$lang = Factory::getLanguage();
|
||||
$client = ApplicationHelper::getClientInfo($clientId);
|
||||
|
||||
if (!$form->loadFile('style_' . $client->name, true)) {
|
||||
throw new \Exception(Text::_('JERROR_LOADFILE_FAILED'));
|
||||
}
|
||||
|
||||
$formFile = Path::clean($client->path . '/templates/' . $template . '/templateDetails.xml');
|
||||
|
||||
// Load the core and/or local language file(s).
|
||||
// Default to using parent template language constants
|
||||
$lang->load('tpl_' . $data->parent, $client->path)
|
||||
|| $lang->load('tpl_' . $data->parent, $client->path . '/templates/' . $data->parent);
|
||||
|
||||
// Apply any, optional, overrides for child template language constants
|
||||
$lang->load('tpl_' . $template, $client->path)
|
||||
|| $lang->load('tpl_' . $template, $client->path . '/templates/' . $template);
|
||||
|
||||
if (file_exists($formFile)) {
|
||||
// Get the template form.
|
||||
if (!$form->loadFile($formFile, false, '//config')) {
|
||||
throw new \Exception(Text::_('JERROR_LOADFILE_FAILED'));
|
||||
}
|
||||
}
|
||||
|
||||
// Disable home field if it is default style
|
||||
|
||||
if (
|
||||
(\is_array($data) && \array_key_exists('home', $data) && $data['home'] == '1')
|
||||
|| (\is_object($data) && isset($data->home) && $data->home == '1')
|
||||
) {
|
||||
$form->setFieldAttribute('home', 'readonly', 'true');
|
||||
}
|
||||
|
||||
if ($client->name === 'site' && !Multilanguage::isEnabled()) {
|
||||
$form->setFieldAttribute('home', 'type', 'radio');
|
||||
$form->setFieldAttribute('home', 'layout', 'joomla.form.field.radio.switcher');
|
||||
}
|
||||
|
||||
// Attempt to load the xml file.
|
||||
if (!$xml = simplexml_load_file($formFile)) {
|
||||
throw new \Exception(Text::_('JERROR_LOADFILE_FAILED'));
|
||||
}
|
||||
|
||||
// Get the help data from the XML file if present.
|
||||
$help = $xml->xpath('/extension/help');
|
||||
|
||||
if (!empty($help)) {
|
||||
$helpKey = trim((string) $help[0]['key']);
|
||||
$helpURL = trim((string) $help[0]['url']);
|
||||
|
||||
$this->helpKey = $helpKey ?: $this->helpKey;
|
||||
$this->helpURL = $helpURL ?: $this->helpURL;
|
||||
}
|
||||
|
||||
// Trigger the default form events.
|
||||
parent::preprocessForm($form, $data, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to save the form data.
|
||||
*
|
||||
* @param array $data The form data.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*/
|
||||
public function save($data)
|
||||
{
|
||||
// Detect disabled extension
|
||||
$extension = Table::getInstance('Extension', 'Joomla\\CMS\\Table\\');
|
||||
|
||||
if ($extension->load(['enabled' => 0, 'type' => 'template', 'element' => $data['template'], 'client_id' => $data['client_id']])) {
|
||||
$this->setError(Text::_('COM_TEMPLATES_ERROR_SAVE_DISABLED_TEMPLATE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$app = Factory::getApplication();
|
||||
$table = $this->getTable();
|
||||
$pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('style.id');
|
||||
$isNew = true;
|
||||
|
||||
// Include the extension plugins for the save events.
|
||||
PluginHelper::importPlugin($this->events_map['save']);
|
||||
|
||||
// Load the row if saving an existing record.
|
||||
if ($pk > 0) {
|
||||
$table->load($pk);
|
||||
$isNew = false;
|
||||
}
|
||||
|
||||
if ($app->getInput()->get('task') == 'save2copy') {
|
||||
$data['title'] = $this->generateNewTitle(null, null, $data['title']);
|
||||
$data['home'] = 0;
|
||||
$data['assigned'] = '';
|
||||
}
|
||||
|
||||
// Bind the data.
|
||||
if (!$table->bind($data)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare the row for saving
|
||||
$this->prepareTable($table);
|
||||
|
||||
// Check the data.
|
||||
if (!$table->check()) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trigger the before save event.
|
||||
$result = Factory::getApplication()->triggerEvent($this->event_before_save, ['com_templates.style', &$table, $isNew]);
|
||||
|
||||
// Store the data.
|
||||
if (\in_array(false, $result, true) || !$table->store()) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
if ($user->authorise('core.edit', 'com_menus') && $table->client_id == 0) {
|
||||
$n = 0;
|
||||
$db = $this->getDatabase();
|
||||
$user = $this->getCurrentUser();
|
||||
$tableId = (int) $table->id;
|
||||
$userId = (int) $user->id;
|
||||
|
||||
if (!empty($data['assigned']) && \is_array($data['assigned'])) {
|
||||
$data['assigned'] = ArrayHelper::toInteger($data['assigned']);
|
||||
|
||||
// Update the mapping for menu items that this style IS assigned to.
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__menu'))
|
||||
->set($db->quoteName('template_style_id') . ' = :newtsid')
|
||||
->whereIn($db->quoteName('id'), $data['assigned'])
|
||||
->where($db->quoteName('template_style_id') . ' != :tsid')
|
||||
->where('(' . $db->quoteName('checked_out') . ' IS NULL OR ' . $db->quoteName('checked_out') . ' = :userid)')
|
||||
->bind(':userid', $userId, ParameterType::INTEGER)
|
||||
->bind(':newtsid', $tableId, ParameterType::INTEGER)
|
||||
->bind(':tsid', $tableId, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
$n += $db->getAffectedRows();
|
||||
}
|
||||
|
||||
// Remove style mappings for menu items this style is NOT assigned to.
|
||||
// If unassigned then all existing maps will be removed.
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__menu'))
|
||||
->set($db->quoteName('template_style_id') . ' = 0');
|
||||
|
||||
if (!empty($data['assigned'])) {
|
||||
$query->whereNotIn($db->quoteName('id'), $data['assigned']);
|
||||
}
|
||||
|
||||
$query->where($db->quoteName('template_style_id') . ' = :templatestyleid')
|
||||
->where('(' . $db->quoteName('checked_out') . ' IS NULL OR ' . $db->quoteName('checked_out') . ' = :userid)')
|
||||
->bind(':userid', $userId, ParameterType::INTEGER)
|
||||
->bind(':templatestyleid', $tableId, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
$n += $db->getAffectedRows();
|
||||
|
||||
if ($n > 0) {
|
||||
$app->enqueueMessage(Text::plural('COM_TEMPLATES_MENU_CHANGED', $n));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean the cache.
|
||||
$this->cleanCache();
|
||||
|
||||
// Trigger the after save event.
|
||||
Factory::getApplication()->triggerEvent($this->event_after_save, ['com_templates.style', &$table, $isNew]);
|
||||
|
||||
$this->setState('style.id', $table->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set a template style as home.
|
||||
*
|
||||
* @param integer $id The primary key ID for the style.
|
||||
*
|
||||
* @return boolean True if successful.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setHome($id = 0)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$db = $this->getDatabase();
|
||||
|
||||
// Access checks.
|
||||
if (!$user->authorise('core.edit.state', 'com_templates')) {
|
||||
throw new \Exception(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
|
||||
}
|
||||
|
||||
$style = $this->getTable();
|
||||
|
||||
if (!$style->load((int) $id)) {
|
||||
throw new \Exception(Text::_('COM_TEMPLATES_ERROR_STYLE_NOT_FOUND'));
|
||||
}
|
||||
|
||||
// Detect disabled extension
|
||||
$extension = Table::getInstance('Extension', 'Joomla\\CMS\\Table\\');
|
||||
|
||||
if ($extension->load(['enabled' => 0, 'type' => 'template', 'element' => $style->template, 'client_id' => $style->client_id])) {
|
||||
throw new \Exception(Text::_('COM_TEMPLATES_ERROR_SAVE_DISABLED_TEMPLATE'));
|
||||
}
|
||||
|
||||
$clientId = (int) $style->client_id;
|
||||
$id = (int) $id;
|
||||
|
||||
// Reset the home fields for the client_id.
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__template_styles'))
|
||||
->set($db->quoteName('home') . ' = ' . $db->quote('0'))
|
||||
->where($db->quoteName('client_id') . ' = :clientid')
|
||||
->where($db->quoteName('home') . ' = ' . $db->quote('1'))
|
||||
->bind(':clientid', $clientId, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
// Set the new home style.
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__template_styles'))
|
||||
->set($db->quoteName('home') . ' = ' . $db->quote('1'))
|
||||
->where($db->quoteName('id') . ' = :id')
|
||||
->bind(':id', $id, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
// Clean the cache.
|
||||
$this->cleanCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to unset a template style as default for a language.
|
||||
*
|
||||
* @param integer $id The primary key ID for the style.
|
||||
*
|
||||
* @return boolean True if successful.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function unsetHome($id = 0)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$db = $this->getDatabase();
|
||||
|
||||
// Access checks.
|
||||
if (!$user->authorise('core.edit.state', 'com_templates')) {
|
||||
throw new \Exception(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
|
||||
}
|
||||
|
||||
$id = (int) $id;
|
||||
|
||||
// Lookup the client_id.
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName(['client_id', 'home']))
|
||||
->from($db->quoteName('#__template_styles'))
|
||||
->where($db->quoteName('id') . ' = :id')
|
||||
->bind(':id', $id, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$style = $db->loadObject();
|
||||
|
||||
if (!is_numeric($style->client_id)) {
|
||||
throw new \Exception(Text::_('COM_TEMPLATES_ERROR_STYLE_NOT_FOUND'));
|
||||
}
|
||||
|
||||
if ($style->home == '1') {
|
||||
throw new \Exception(Text::_('COM_TEMPLATES_ERROR_CANNOT_UNSET_DEFAULT_STYLE'));
|
||||
}
|
||||
|
||||
// Set the new home style.
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__template_styles'))
|
||||
->set($db->quoteName('home') . ' = ' . $db->quote('0'))
|
||||
->where($db->quoteName('id') . ' = :id')
|
||||
->bind(':id', $id, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
// Clean the cache.
|
||||
$this->cleanCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the necessary data to load an item help screen.
|
||||
*
|
||||
* @return object An object with key, url, and local properties for loading the item help screen.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function getHelp()
|
||||
{
|
||||
return (object) ['key' => $this->helpKey, 'url' => $this->helpURL];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the back end template for the given style.
|
||||
*
|
||||
* @param int $styleId The style id
|
||||
*
|
||||
* @return \stdClass
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function getAdminTemplate(int $styleId): \stdClass
|
||||
{
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName(['s.template', 's.params', 's.inheritable', 's.parent']))
|
||||
->from($db->quoteName('#__template_styles', 's'))
|
||||
->join(
|
||||
'LEFT',
|
||||
$db->quoteName('#__extensions', 'e'),
|
||||
$db->quoteName('e.type') . ' = ' . $db->quote('template')
|
||||
. ' AND ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('s.template')
|
||||
. ' AND ' . $db->quoteName('e.client_id') . ' = ' . $db->quoteName('s.client_id')
|
||||
)
|
||||
->where(
|
||||
[
|
||||
$db->quoteName('s.client_id') . ' = 1',
|
||||
$db->quoteName('s.home') . ' = ' . $db->quote('1'),
|
||||
]
|
||||
);
|
||||
|
||||
if ($styleId) {
|
||||
$query->extendWhere(
|
||||
'OR',
|
||||
[
|
||||
$db->quoteName('s.client_id') . ' = 1',
|
||||
$db->quoteName('s.id') . ' = :style',
|
||||
$db->quoteName('e.enabled') . ' = 1',
|
||||
]
|
||||
)
|
||||
->bind(':style', $styleId, ParameterType::INTEGER);
|
||||
}
|
||||
|
||||
$query->order($db->quoteName('s.home'));
|
||||
$db->setQuery($query);
|
||||
|
||||
return $db->loadObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the front end templates.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function getSiteTemplates(): array
|
||||
{
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName(['id', 'home', 'template', 's.params', 'inheritable', 'parent']))
|
||||
->from($db->quoteName('#__template_styles', 's'))
|
||||
->where(
|
||||
[
|
||||
$db->quoteName('s.client_id') . ' = 0',
|
||||
$db->quoteName('e.enabled') . ' = 1',
|
||||
]
|
||||
)
|
||||
->join(
|
||||
'LEFT',
|
||||
$db->quoteName('#__extensions', 'e'),
|
||||
$db->quoteName('e.element') . ' = ' . $db->quoteName('s.template')
|
||||
. ' AND ' . $db->quoteName('e.type') . ' = ' . $db->quote('template')
|
||||
. ' AND ' . $db->quoteName('e.client_id') . ' = ' . $db->quoteName('s.client_id')
|
||||
);
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return $db->loadObjectList('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom clean cache method
|
||||
*
|
||||
* @param string $group The cache group
|
||||
* @param integer $clientId No longer used, will be removed without replacement
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function cleanCache($group = null, $clientId = 0)
|
||||
{
|
||||
parent::cleanCache('com_templates');
|
||||
parent::cleanCache('_system');
|
||||
}
|
||||
}
|
||||
254
administrator/components/com_templates/src/Model/StylesModel.php
Normal file
254
administrator/components/com_templates/src/Model/StylesModel.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Database\QueryInterface;
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Methods supporting a list of template style records.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class StylesModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config An optional associative array of configuration settings.
|
||||
* @param ?MVCFactoryInterface $factory The factory.
|
||||
*
|
||||
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
|
||||
* @since 3.2
|
||||
*/
|
||||
public function __construct($config = [], ?MVCFactoryInterface $factory = null)
|
||||
{
|
||||
if (empty($config['filter_fields'])) {
|
||||
$config['filter_fields'] = [
|
||||
'id', 'a.id',
|
||||
'title', 'a.title',
|
||||
'template', 'a.template',
|
||||
'home', 'a.home',
|
||||
'menuitem',
|
||||
];
|
||||
}
|
||||
|
||||
parent::__construct($config, $factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* Note. Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @param string $ordering An optional ordering field.
|
||||
* @param string $direction An optional direction (asc|desc).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function populateState($ordering = 'a.template', $direction = 'asc')
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
if (!$app->isClient('api')) {
|
||||
// Special case for the client id.
|
||||
$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);
|
||||
}
|
||||
|
||||
// Load the parameters.
|
||||
$params = ComponentHelper::getParams('com_templates');
|
||||
$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.template');
|
||||
$id .= ':' . $this->getState('filter.menuitem');
|
||||
|
||||
return parent::getStoreId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an SQL query to load the list data.
|
||||
*
|
||||
* @return QueryInterface
|
||||
*/
|
||||
protected function getListQuery()
|
||||
{
|
||||
$clientId = (int) $this->getState('client_id');
|
||||
|
||||
// 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',
|
||||
[
|
||||
$db->quoteName('a.id'),
|
||||
$db->quoteName('a.template'),
|
||||
$db->quoteName('a.title'),
|
||||
$db->quoteName('a.home'),
|
||||
$db->quoteName('a.client_id'),
|
||||
$db->quoteName('l.title', 'language_title'),
|
||||
$db->quoteName('l.image'),
|
||||
$db->quoteName('l.sef', 'language_sef'),
|
||||
]
|
||||
)
|
||||
)
|
||||
->select(
|
||||
[
|
||||
'COUNT(' . $db->quoteName('m.template_style_id') . ') AS assigned',
|
||||
$db->quoteName('extension_id', 'e_id'),
|
||||
]
|
||||
)
|
||||
->from($db->quoteName('#__template_styles', 'a'))
|
||||
->where($db->quoteName('a.client_id') . ' = :clientid')
|
||||
->bind(':clientid', $clientId, ParameterType::INTEGER);
|
||||
|
||||
// Join on menus.
|
||||
$query->join('LEFT', $db->quoteName('#__menu', 'm'), $db->quoteName('m.template_style_id') . ' = ' . $db->quoteName('a.id'))
|
||||
->group(
|
||||
[
|
||||
$db->quoteName('a.id'),
|
||||
$db->quoteName('a.template'),
|
||||
$db->quoteName('a.title'),
|
||||
$db->quoteName('a.home'),
|
||||
$db->quoteName('a.client_id'),
|
||||
$db->quoteName('l.title'),
|
||||
$db->quoteName('l.image'),
|
||||
$db->quoteName('l.sef'),
|
||||
$db->quoteName('e.extension_id'),
|
||||
]
|
||||
);
|
||||
|
||||
// Join over the language.
|
||||
$query->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.home'));
|
||||
|
||||
// Filter by extension enabled.
|
||||
$query->join(
|
||||
'LEFT',
|
||||
$db->quoteName('#__extensions', 'e'),
|
||||
$db->quoteName('e.element') . ' = ' . $db->quoteName('a.template')
|
||||
. ' AND ' . $db->quoteName('e.client_id') . ' = ' . $db->quoteName('a.client_id')
|
||||
)
|
||||
->where(
|
||||
[
|
||||
$db->quoteName('e.enabled') . ' = 1',
|
||||
$db->quoteName('e.type') . ' = ' . $db->quote('template'),
|
||||
]
|
||||
);
|
||||
|
||||
// Filter by template.
|
||||
if ($template = $this->getState('filter.template')) {
|
||||
$query->where($db->quoteName('a.template') . ' = :template')
|
||||
->bind(':template', $template);
|
||||
}
|
||||
|
||||
// Filter by menuitem.
|
||||
$menuItemId = $this->getState('filter.menuitem');
|
||||
|
||||
if ($clientId === 0 && is_numeric($menuItemId)) {
|
||||
// If user selected the templates styles that are not assigned to any page.
|
||||
if ((int) $menuItemId === -1) {
|
||||
// Only custom template styles overrides not assigned to any menu item.
|
||||
$query->where(
|
||||
[
|
||||
$db->quoteName('a.home') . ' = ' . $db->quote('0'),
|
||||
$db->quoteName('m.id') . ' IS NULL',
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// If user selected the templates styles assigned to particular pages.
|
||||
// Subquery to get the language of the selected menu item.
|
||||
$menuItemId = (int) $menuItemId;
|
||||
$menuItemLanguageSubQuery = $db->getQuery(true);
|
||||
$menuItemLanguageSubQuery->select($db->quoteName('language'))
|
||||
->from($db->quoteName('#__menu'))
|
||||
->where($db->quoteName('id') . ' = :menuitemid');
|
||||
$query->bind(':menuitemid', $menuItemId, ParameterType::INTEGER);
|
||||
|
||||
// Subquery to get the language of the selected menu item.
|
||||
$templateStylesMenuItemsSubQuery = $db->getQuery(true);
|
||||
$templateStylesMenuItemsSubQuery->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__menu'))
|
||||
->where($db->quoteName('template_style_id') . ' = ' . $db->quoteName('a.id'));
|
||||
|
||||
// Main query where clause.
|
||||
$query->where('(' .
|
||||
// Default template style (fallback template style to all menu items).
|
||||
$db->quoteName('a.home') . ' = ' . $db->quote('1') . ' OR ' .
|
||||
// Default template style for specific language (fallback template style to the selected menu item language).
|
||||
$db->quoteName('a.home') . ' IN (' . $menuItemLanguageSubQuery . ') OR ' .
|
||||
// Custom template styles override (only if assigned to the selected menu item).
|
||||
'(' . $db->quoteName('a.home') . ' = ' . $db->quote('0') . ' AND ' . $menuItemId . ' IN (' . $templateStylesMenuItemsSubQuery . '))' .
|
||||
')');
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by search in title.
|
||||
if ($search = $this->getState('filter.search')) {
|
||||
if (stripos($search, 'id:') === 0) {
|
||||
$ids = (int) substr($search, 3);
|
||||
$query->where($db->quoteName('a.id') . ' = :id');
|
||||
$query->bind(':id', $ids, ParameterType::INTEGER);
|
||||
} else {
|
||||
$search = '%' . StringHelper::strtolower($search) . '%';
|
||||
$query->extendWhere(
|
||||
'AND',
|
||||
[
|
||||
'LOWER(' . $db->quoteName('a.template') . ') LIKE :templatesearch',
|
||||
'LOWER(' . $db->quoteName('a.title') . ') LIKE :title',
|
||||
],
|
||||
'OR'
|
||||
)
|
||||
->bind(':templatesearch', $search)
|
||||
->bind(':title', $search);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the list ordering clause.
|
||||
$query->order($db->escape($this->getState('list.ordering', 'a.template')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
2106
administrator/components/com_templates/src/Model/TemplateModel.php
Normal file
2106
administrator/components/com_templates/src/Model/TemplateModel.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\Component\Templates\Administrator\Helper\TemplatesHelper;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Database\QueryInterface;
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Methods supporting a list of template extension records.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class TemplatesModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config An optional associative array of configuration settings.
|
||||
* @param ?MVCFactoryInterface $factory The factory.
|
||||
*
|
||||
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
|
||||
* @since 3.2
|
||||
*/
|
||||
public function __construct($config = [], ?MVCFactoryInterface $factory = null)
|
||||
{
|
||||
if (empty($config['filter_fields'])) {
|
||||
$config['filter_fields'] = [
|
||||
'id', 'a.id',
|
||||
'name', 'a.name',
|
||||
'folder', 'a.folder',
|
||||
'element', 'a.element',
|
||||
'checked_out', 'a.checked_out',
|
||||
'checked_out_time', 'a.checked_out_time',
|
||||
'state', 'a.state',
|
||||
'enabled', 'a.enabled',
|
||||
'ordering', 'a.ordering',
|
||||
];
|
||||
}
|
||||
|
||||
parent::__construct($config, $factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parent getItems to add extra XML metadata.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$items = parent::getItems();
|
||||
|
||||
foreach ($items as &$item) {
|
||||
$client = ApplicationHelper::getClientInfo($item->client_id);
|
||||
$item->xmldata = TemplatesHelper::parseXMLTemplateFile($client->path, $item->element);
|
||||
$num = $this->updated($item->extension_id);
|
||||
|
||||
if ($num) {
|
||||
$item->updated = $num;
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if template extension have any updated override.
|
||||
*
|
||||
* @param integer $exid Extension id of template.
|
||||
*
|
||||
* @return boolean False if records not found/else integer.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function updated($exid)
|
||||
{
|
||||
$db = $this->getDatabase();
|
||||
|
||||
// Select the required fields from the table
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName('template'))
|
||||
->from($db->quoteName('#__template_overrides'))
|
||||
->where($db->quoteName('extension_id') . ' = :extensionid')
|
||||
->where($db->quoteName('state') . ' = 0')
|
||||
->bind(':extensionid', $exid, ParameterType::INTEGER);
|
||||
|
||||
// Reset the query.
|
||||
$db->setQuery($query);
|
||||
|
||||
// Load the results as a list of stdClass objects.
|
||||
$num = \count($db->loadObjectList());
|
||||
|
||||
if ($num > 0) {
|
||||
return $num;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an SQL query to load the list data.
|
||||
*
|
||||
* @return QueryInterface
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
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, a.client_id'
|
||||
)
|
||||
);
|
||||
$clientId = (int) $this->getState('client_id');
|
||||
$query->from($db->quoteName('#__extensions', 'a'))
|
||||
->where($db->quoteName('a.client_id') . ' = :clientid')
|
||||
->where($db->quoteName('a.enabled') . ' = 1')
|
||||
->where($db->quoteName('a.type') . ' = ' . $db->quote('template'))
|
||||
->bind(':clientid', $clientId, ParameterType::INTEGER);
|
||||
|
||||
// Filter by search in title.
|
||||
if ($search = $this->getState('filter.search')) {
|
||||
if (stripos($search, 'id:') === 0) {
|
||||
$ids = (int) substr($search, 3);
|
||||
$query->where($db->quoteName('a.id') . ' = :id');
|
||||
$query->bind(':id', $ids, ParameterType::INTEGER);
|
||||
} else {
|
||||
$search = '%' . StringHelper::strtolower($search) . '%';
|
||||
$query->extendWhere(
|
||||
'AND',
|
||||
[
|
||||
'LOWER(' . $db->quoteName('a.element') . ') LIKE :element',
|
||||
'LOWER(' . $db->quoteName('a.name') . ') LIKE :name',
|
||||
],
|
||||
'OR'
|
||||
)
|
||||
->bind(':element', $search)
|
||||
->bind(':name', $search);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the list ordering clause.
|
||||
$query->order($db->escape($this->getState('list.ordering', 'a.element')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a store id based on model configuration state.
|
||||
*
|
||||
* This is necessary because the model is used by the component and
|
||||
* different modules that might need different sets of data or different
|
||||
* ordering requirements.
|
||||
*
|
||||
* @param string $id A prefix for the store id.
|
||||
*
|
||||
* @return string A store id.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function getStoreId($id = '')
|
||||
{
|
||||
// Compile the store id.
|
||||
$id .= ':' . $this->getState('client_id');
|
||||
$id .= ':' . $this->getState('filter.search');
|
||||
|
||||
return parent::getStoreId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.element', $direction = 'asc')
|
||||
{
|
||||
// Special case for the client id.
|
||||
$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);
|
||||
|
||||
// Load the parameters.
|
||||
$params = ComponentHelper::getParams('com_templates');
|
||||
$this->setState('params', $params);
|
||||
|
||||
// List state information.
|
||||
parent::populateState($ordering, $direction);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Service\HTML;
|
||||
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Component\Templates\Administrator\Helper\TemplatesHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Html helper class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class Templates
|
||||
{
|
||||
/**
|
||||
* Display the thumb for the template.
|
||||
*
|
||||
* @param string|object $template The name of the template or the template object.
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
* The argument $template must be an object only
|
||||
* @param integer $clientId No longer used, will be removed without replacement
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
*
|
||||
* @return string The html string
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function thumb($template, $clientId = 0)
|
||||
{
|
||||
if (\is_string($template)) {
|
||||
return HTMLHelper::_('image', 'template_thumbnail.png', Text::_('COM_TEMPLATES_PREVIEW'), [], true, -1);
|
||||
}
|
||||
|
||||
$client = ApplicationHelper::getClientInfo($template->client_id);
|
||||
|
||||
if (!isset($template->xmldata)) {
|
||||
$template->xmldata = TemplatesHelper::parseXMLTemplateFile($client->id === 0 ? JPATH_ROOT : JPATH_ROOT . '/administrator', $template->name);
|
||||
}
|
||||
|
||||
if ((isset($template->xmldata->inheritable) && (bool) $template->xmldata->inheritable) || isset($template->xmldata->parent)) {
|
||||
if (isset($template->xmldata->parent) && (string) $template->xmldata->parent !== '' && file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . (string) $template->xmldata->parent . '/images/template_thumbnail.png')) {
|
||||
if (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_preview.png')) {
|
||||
$html = HTMLHelper::_('image', 'media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png', Text::_('COM_TEMPLATES_PREVIEW'));
|
||||
$html = '<button type="button" data-bs-target="#' . $template->element . '-Modal" class="thumbnail" data-bs-toggle="modal" title="' . Text::_('COM_TEMPLATES_CLICK_TO_ENLARGE') . '">' . $html . '</button>';
|
||||
} elseif ((file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . (string) $template->xmldata->parent . '/images/template_preview.png'))) {
|
||||
$html = HTMLHelper::_('image', 'media/templates/' . $client->name . '/' . (string) $template->xmldata->parent . '/images/template_thumbnail.png', Text::_('COM_TEMPLATES_PREVIEW'));
|
||||
$html = '<button type="button" data-bs-target="#' . $template->element . '-Modal" class="thumbnail" data-bs-toggle="modal" title="' . Text::_('COM_TEMPLATES_CLICK_TO_ENLARGE') . '">' . $html . '</button>';
|
||||
} else {
|
||||
$html = HTMLHelper::_('image', 'template_thumb.svg', Text::_('COM_TEMPLATES_PREVIEW'), ['style' => 'width:200px; height:120px;']);
|
||||
}
|
||||
} elseif (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png')) {
|
||||
$html = HTMLHelper::_('image', 'media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png', Text::_('COM_TEMPLATES_PREVIEW'));
|
||||
|
||||
if (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_preview.png')) {
|
||||
$html = '<button type="button" data-bs-target="#' . $template->element . '-Modal" class="thumbnail" data-bs-toggle="modal" title="' . Text::_('COM_TEMPLATES_CLICK_TO_ENLARGE') . '">' . $html . '</button>';
|
||||
}
|
||||
} else {
|
||||
$html = HTMLHelper::_('image', 'template_thumb.svg', Text::_('COM_TEMPLATES_PREVIEW'), ['style' => 'width:200px; height:120px;']);
|
||||
}
|
||||
} elseif (file_exists($client->path . '/templates/' . $template->element . '/template_thumbnail.png')) {
|
||||
$html = HTMLHelper::_('image', (($template->client_id == 0) ? Uri::root(true) : Uri::root(true) . '/administrator/') . '/templates/' . $template->element . '/template_thumbnail.png', Text::_('COM_TEMPLATES_PREVIEW'), [], false, -1);
|
||||
|
||||
if (file_exists($client->path . '/templates/' . $template->element . '/template_preview.png')) {
|
||||
$html = '<button type="button" data-bs-target="#' . $template->element . '-Modal" class="thumbnail" data-bs-toggle="modal" title="' . Text::_('COM_TEMPLATES_CLICK_TO_ENLARGE') . '">' . $html . '</button>';
|
||||
}
|
||||
} else {
|
||||
$html = HTMLHelper::_('image', 'template_thumb.svg', Text::_('COM_TEMPLATES_PREVIEW'), ['style' => 'width:200px; height:120px;']);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the html for the modal linked to thumb.
|
||||
*
|
||||
* @param string|object $template The name of the template or the template object.
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
* The argument $template must be an object only
|
||||
* @param integer $clientId No longer used, will be removed without replacement
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
*
|
||||
* @return string The html string
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function thumbModal($template, $clientId = 0)
|
||||
{
|
||||
if (\is_string($template)) {
|
||||
return HTMLHelper::_('image', 'template_thumbnail.png', Text::_('COM_TEMPLATES_PREVIEW'), [], true, -1);
|
||||
}
|
||||
|
||||
$html = '';
|
||||
$thumb = '';
|
||||
$preview = '';
|
||||
$client = ApplicationHelper::getClientInfo($template->client_id);
|
||||
|
||||
if (!isset($template->xmldata)) {
|
||||
$template->xmldata = TemplatesHelper::parseXMLTemplateFile($client->id === 0 ? JPATH_ROOT : JPATH_ROOT . '/administrator', $template->name);
|
||||
}
|
||||
|
||||
if ((isset($template->xmldata->inheritable) && (bool) $template->xmldata->inheritable) || isset($template->xmldata->parent)) {
|
||||
if (isset($template->xmldata->parent) && (string) $template->xmldata->parent !== '') {
|
||||
if (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png')) {
|
||||
$thumb = ($template->client_id == 0 ? Uri::root(true) : Uri::root(true) . 'administrator') . 'media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png';
|
||||
|
||||
if (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_preview.png')) {
|
||||
$preview = ($template->client_id == 0 ? Uri::root(true) : Uri::root(true) . '/administrator') . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_preview.png';
|
||||
}
|
||||
} else {
|
||||
$thumb = ($template->client_id == 0 ? Uri::root(true) : Uri::root(true) . 'administrator') . 'media/templates/' . $client->name . '/' . (string) $template->xmldata->parent . '/images/template_thumbnail.png';
|
||||
|
||||
if (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . (string) $template->xmldata->parent . '/images/template_preview.png')) {
|
||||
$preview = ($template->client_id == 0 ? Uri::root(true) : Uri::root(true) . '/administrator') . '/media/templates/' . $client->name . '/' . (string) $template->xmldata->parent . '/images/template_preview.png';
|
||||
}
|
||||
}
|
||||
} elseif (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png')) {
|
||||
$thumb = ($template->client_id == 0 ? Uri::root(true) : Uri::root(true) . '/administrator') . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_thumbnail.png';
|
||||
|
||||
if (file_exists(JPATH_ROOT . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_preview.png')) {
|
||||
$preview = Uri::root(true) . '/media/templates/' . $client->name . '/' . $template->element . '/images/template_preview.png';
|
||||
}
|
||||
}
|
||||
} elseif (file_exists($client->path . '/templates/' . $template->element . '/template_thumbnail.png')) {
|
||||
$thumb = (($template->client_id == 0) ? Uri::root(true) : Uri::root(true) . 'administrator') . '/templates/' . $template->element . '/template_thumbnail.png';
|
||||
|
||||
if (file_exists($client->path . '/templates/' . $template->element . '/template_preview.png')) {
|
||||
$preview = (($template->client_id == 0) ? Uri::root(true) : Uri::root(true) . '/administrator') . '/templates/' . $template->element . '/template_preview.png';
|
||||
}
|
||||
}
|
||||
|
||||
if ($thumb !== '' && $preview !== '') {
|
||||
$footer = '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">'
|
||||
. Text::_('JTOOLBAR_CLOSE') . '</button>';
|
||||
|
||||
$html .= HTMLHelper::_(
|
||||
'bootstrap.renderModal',
|
||||
$template->element . '-Modal',
|
||||
[
|
||||
'title' => Text::sprintf('COM_TEMPLATES_SCREENSHOT', ucfirst($template->name)),
|
||||
'height' => '500px',
|
||||
'width' => '800px',
|
||||
'footer' => $footer,
|
||||
],
|
||||
'<div><img src="' . $preview . '" class="mw-100" alt="' . $template->name . '"></div>'
|
||||
);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
159
administrator/components/com_templates/src/Table/StyleTable.php
Normal file
159
administrator/components/com_templates/src/Table/StyleTable.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\Table;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Database\DatabaseDriver;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Template style table class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class StyleTable extends Table
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DatabaseDriver $db Database connector object
|
||||
* @param ?DispatcherInterface $dispatcher Event dispatcher for this table
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function __construct(DatabaseDriver $db, ?DispatcherInterface $dispatcher = null)
|
||||
{
|
||||
parent::__construct('#__template_styles', 'id', $db, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded bind function to pre-process the params.
|
||||
*
|
||||
* @param array $array Named array
|
||||
* @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
|
||||
*
|
||||
* @return null|string null if operation was satisfactory, otherwise returns an error
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function bind($array, $ignore = '')
|
||||
{
|
||||
if (isset($array['params']) && \is_array($array['params'])) {
|
||||
$registry = new Registry($array['params']);
|
||||
$array['params'] = (string) $registry;
|
||||
}
|
||||
|
||||
// Verify that the default style is not unset
|
||||
if ($array['home'] == '0' && $this->home == '1') {
|
||||
$this->setError(Text::_('COM_TEMPLATES_ERROR_CANNOT_UNSET_DEFAULT_STYLE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::bind($array, $ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded check method to ensure data integrity.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
try {
|
||||
parent::check();
|
||||
} catch (\Exception $e) {
|
||||
$this->setError($e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->title)) {
|
||||
$this->setError(Text::_('COM_TEMPLATES_ERROR_STYLE_REQUIRES_TITLE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded store method to ensure unicity of default style.
|
||||
*
|
||||
* @param boolean $updateNulls True to update fields even if they are null.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function store($updateNulls = false)
|
||||
{
|
||||
if ($this->home != '0') {
|
||||
$clientId = (int) $this->client_id;
|
||||
$query = $this->_db->getQuery(true)
|
||||
->update($this->_db->quoteName('#__template_styles'))
|
||||
->set($this->_db->quoteName('home') . ' = ' . $this->_db->quote('0'))
|
||||
->where($this->_db->quoteName('client_id') . ' = :clientid')
|
||||
->where($this->_db->quoteName('home') . ' = :home')
|
||||
->bind(':clientid', $clientId, ParameterType::INTEGER)
|
||||
->bind(':home', $this->home);
|
||||
$this->_db->setQuery($query);
|
||||
$this->_db->execute();
|
||||
}
|
||||
|
||||
return parent::store($updateNulls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded store method to unsure existence of a default style for a template.
|
||||
*
|
||||
* @param mixed $pk An optional primary key value to delete. If not set the instance property value is used.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function delete($pk = null)
|
||||
{
|
||||
$k = $this->_tbl_key;
|
||||
$pk = \is_null($pk) ? $this->$k : $pk;
|
||||
|
||||
if (!\is_null($pk)) {
|
||||
$clientId = (int) $this->client_id;
|
||||
$query = $this->_db->getQuery(true)
|
||||
->select($this->_db->quoteName('id'))
|
||||
->from($this->_db->quoteName('#__template_styles'))
|
||||
->where($this->_db->quoteName('client_id') . ' = :clientid')
|
||||
->where($this->_db->quoteName('template') . ' = :template')
|
||||
->bind(':template', $this->template)
|
||||
->bind(':clientid', $clientId, ParameterType::INTEGER);
|
||||
$this->_db->setQuery($query);
|
||||
$results = $this->_db->loadColumn();
|
||||
|
||||
if (\count($results) == 1 && $results[0] == $pk) {
|
||||
$this->setError(Text::_('COM_TEMPLATES_ERROR_CANNOT_DELETE_LAST_STYLE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::delete($pk);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\View\Style;
|
||||
|
||||
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 template style.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The item
|
||||
*
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $item;
|
||||
|
||||
/**
|
||||
* The form object
|
||||
*
|
||||
* @var \Joomla\CMS\Form\Form
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Array of fieldsets not to display
|
||||
*
|
||||
* @var string[]
|
||||
*
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public $ignore_fieldsets = [];
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @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->item = $this->get('Item');
|
||||
$this->state = $this->get('State');
|
||||
$this->form = $this->get('Form');
|
||||
$this->canDo = ContentHelper::getActions('com_templates');
|
||||
|
||||
// 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);
|
||||
|
||||
$isNew = ($this->item->id == 0);
|
||||
$canDo = $this->canDo;
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
ToolbarHelper::title(
|
||||
$isNew ? Text::_('COM_TEMPLATES_MANAGER_ADD_STYLE')
|
||||
: Text::_('COM_TEMPLATES_MANAGER_EDIT_STYLE'),
|
||||
'paint-brush thememanager'
|
||||
);
|
||||
|
||||
// If not checked out, can save the item.
|
||||
if ($canDo->get('core.edit')) {
|
||||
$toolbar->apply('style.apply');
|
||||
}
|
||||
|
||||
$saveGroup = $toolbar->dropdownButton('save-group');
|
||||
|
||||
$saveGroup->configure(
|
||||
function (Toolbar $childBar) use ($canDo, $isNew) {
|
||||
// If not checked out, can save the item.
|
||||
if ($canDo->get('core.edit')) {
|
||||
$childBar->save('style.save');
|
||||
}
|
||||
|
||||
// If an existing item, can save to a copy.
|
||||
if (!$isNew && $canDo->get('core.create')) {
|
||||
$childBar->save2copy('style.save2copy');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (empty($this->item->id)) {
|
||||
$toolbar->cancel('style.cancel', 'JTOOLBAR_CANCEL');
|
||||
} else {
|
||||
$toolbar->cancel('style.cancel');
|
||||
}
|
||||
|
||||
$toolbar->divider();
|
||||
|
||||
// Get the help information for the template 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->help($help->key, false, $url);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Templates\Administrator\View\Style;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* View to edit a template style.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class JsonView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The item
|
||||
*
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $item;
|
||||
|
||||
/**
|
||||
* The form object
|
||||
*
|
||||
* @var \Joomla\CMS\Form\Form
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return mixed A string if successful, otherwise an Error object.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
try {
|
||||
$this->item = $this->get('Item');
|
||||
} catch (\Exception $e) {
|
||||
$app = Factory::getApplication();
|
||||
$app->enqueueMessage($e->getMessage(), 'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$paramsList = $this->item->getProperties();
|
||||
|
||||
unset($paramsList['xml']);
|
||||
|
||||
$paramsList = json_encode($paramsList);
|
||||
|
||||
return $paramsList;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\View\Styles;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
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\ToolbarHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* View class for a list of template styles.
|
||||
*
|
||||
* @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 the parameter enabled to show template positions in the frontend?
|
||||
*
|
||||
* @var boolean
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public $preview;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @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->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->preview = ComponentHelper::getParams('com_templates')->get('template_positions_display');
|
||||
|
||||
// Remove the menu item filter for administrator styles.
|
||||
if ((int) $this->state->get('client_id') !== 0) {
|
||||
unset($this->activeFilters['menuitem']);
|
||||
$this->filterForm->removeField('menuitem', 'filter');
|
||||
}
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
$canDo = ContentHelper::getActions('com_templates');
|
||||
$clientId = (int) $this->get('State')->get('client_id');
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
// Add a shortcut to the templates list view.
|
||||
$toolbar->linkButton('templates', 'COM_TEMPLATES_MANAGER_TEMPLATES')
|
||||
->url('index.php?option=com_templates&view=templates&client_id=' . $clientId)
|
||||
->icon('icon-code thememanager');
|
||||
|
||||
// Set the title.
|
||||
if ($clientId === 1) {
|
||||
ToolbarHelper::title(Text::_('COM_TEMPLATES_MANAGER_STYLES_ADMIN'), 'paint-brush thememanager');
|
||||
} else {
|
||||
ToolbarHelper::title(Text::_('COM_TEMPLATES_MANAGER_STYLES_SITE'), 'paint-brush thememanager');
|
||||
}
|
||||
|
||||
if ($canDo->get('core.edit.state')) {
|
||||
$toolbar->makeDefault('styles.setDefault', 'COM_TEMPLATES_TOOLBAR_SET_HOME');
|
||||
$toolbar->divider();
|
||||
}
|
||||
|
||||
if ($canDo->get('core.create')) {
|
||||
$toolbar->standardButton('duplicate', 'JTOOLBAR_DUPLICATE', 'styles.duplicate')
|
||||
->listCheck(true)
|
||||
->icon('icon-copy');
|
||||
$toolbar->divider();
|
||||
}
|
||||
|
||||
if ($canDo->get('core.delete')) {
|
||||
$toolbar->delete('styles.delete')
|
||||
->message('JGLOBAL_CONFIRM_DELETE')
|
||||
->listCheck(true);
|
||||
$toolbar->divider();
|
||||
}
|
||||
|
||||
if ($canDo->get('core.admin') || $canDo->get('core.options')) {
|
||||
$toolbar->preferences('com_templates');
|
||||
$toolbar->divider();
|
||||
}
|
||||
|
||||
$toolbar->help('Templates:_Styles');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,418 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\View\Template;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filter\InputFilter;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Toolbar\Button\DropdownButton;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* View to edit a template.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The Model state
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The template details
|
||||
*
|
||||
* @var \stdClass|false
|
||||
*/
|
||||
protected $template;
|
||||
|
||||
/**
|
||||
* For loading the source form
|
||||
*
|
||||
* @var Form
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
/**
|
||||
* For loading source file contents
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* Extension id
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Encrypted file path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* List of available overrides
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $overridesList;
|
||||
|
||||
/**
|
||||
* Name of the present file
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fileName;
|
||||
|
||||
/**
|
||||
* Type of the file - image, source, font
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* For loading image information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* Template id for showing preview button
|
||||
*
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $preview;
|
||||
|
||||
/**
|
||||
* For loading font information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $font;
|
||||
|
||||
/**
|
||||
* A nested array containing list of files and folders
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* An array containing a list of compressed files
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $archive;
|
||||
|
||||
/**
|
||||
* The state of installer override plugin.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $pluginState;
|
||||
|
||||
/**
|
||||
* A nested array containing list of files and folders in the media folder
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $mediaFiles;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return void|boolean
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
$this->file = $app->getInput()->get('file', '');
|
||||
$this->fileName = InputFilter::getInstance()->clean(base64_decode($this->file), 'string');
|
||||
$explodeArray = explode('.', $this->fileName);
|
||||
$ext = end($explodeArray);
|
||||
$this->files = $this->get('Files');
|
||||
$this->mediaFiles = $this->get('MediaFiles');
|
||||
$this->state = $this->get('State');
|
||||
$this->template = $this->get('Template');
|
||||
$this->preview = $this->get('Preview');
|
||||
$this->pluginState = PluginHelper::isEnabled('installer', 'override');
|
||||
$this->updatedList = $this->get('UpdatedList');
|
||||
$this->styles = $this->get('AllTemplateStyles');
|
||||
$this->stylesHTML = '';
|
||||
|
||||
$params = ComponentHelper::getParams('com_templates');
|
||||
$imageTypes = explode(',', $params->get('image_formats', 'gif,bmp,jpg,jpeg,png,webp'));
|
||||
$sourceTypes = explode(',', $params->get('source_formats', 'txt,less,ini,xml,js,php,css,scss,sass,json'));
|
||||
$fontTypes = explode(',', $params->get('font_formats', 'woff,woff2,ttf,otf'));
|
||||
$archiveTypes = explode(',', $params->get('compressed_formats', 'zip'));
|
||||
|
||||
if (\in_array($ext, $sourceTypes)) {
|
||||
$this->form = $this->get('Form');
|
||||
$this->form->setFieldAttribute('source', 'syntax', $ext);
|
||||
$this->source = $this->get('Source');
|
||||
$this->type = 'file';
|
||||
} elseif (\in_array($ext, $imageTypes)) {
|
||||
try {
|
||||
$this->image = $this->get('Image');
|
||||
$this->type = 'image';
|
||||
} catch (\RuntimeException $exception) {
|
||||
$app->enqueueMessage(Text::_('COM_TEMPLATES_GD_EXTENSION_NOT_AVAILABLE'));
|
||||
$this->type = 'home';
|
||||
}
|
||||
} elseif (\in_array($ext, $fontTypes)) {
|
||||
$this->font = $this->get('Font');
|
||||
$this->type = 'font';
|
||||
} elseif (\in_array($ext, $archiveTypes)) {
|
||||
$this->archive = $this->get('Archive');
|
||||
$this->type = 'archive';
|
||||
} else {
|
||||
$this->type = 'home';
|
||||
}
|
||||
|
||||
$this->overridesList = $this->get('OverridesList');
|
||||
$this->id = $this->state->get('extension.id');
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
$app->enqueueMessage(implode("\n", $errors));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
if (!$this->getCurrentUser()->authorise('core.admin')) {
|
||||
$this->setLayout('readonly');
|
||||
}
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @since 1.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
$user = $this->getCurrentUser();
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
$app->getInput()->set('hidemainmenu', true);
|
||||
|
||||
// User is global SuperUser
|
||||
$isSuperUser = $user->authorise('core.admin');
|
||||
|
||||
ToolbarHelper::title(Text::sprintf('COM_TEMPLATES_MANAGER_VIEW_TEMPLATE', ucfirst($this->template->name)), 'icon-code thememanager');
|
||||
|
||||
// Add a Template preview button
|
||||
if ($this->type === 'home') {
|
||||
$client = (int) $this->preview->client_id === 1 ? 'administrator/' : '';
|
||||
$toolbar->linkButton('preview', 'COM_TEMPLATES_BUTTON_PREVIEW')
|
||||
->url(Uri::root() . $client . 'index.php?tp=1&templateStyle=' . $this->preview->id)
|
||||
->icon('icon-image')
|
||||
->attributes(['target' => '_new']);
|
||||
}
|
||||
|
||||
// Only show file edit buttons for global SuperUser
|
||||
if ($isSuperUser) {
|
||||
switch ($this->type) {
|
||||
case 'file':
|
||||
$toolbar->apply('template.apply');
|
||||
$toolbar->save('template.save');
|
||||
$toolbar->cancel('template.close', 'COM_TEMPLATES_BUTTON_CLOSE_FILE');
|
||||
break;
|
||||
|
||||
case 'image':
|
||||
// Add a Crop and Resize button
|
||||
$toolbar->standardButton('crop', 'COM_TEMPLATES_BUTTON_CROP', 'template.cropImage')
|
||||
->listCheck(false)
|
||||
->icon('icon-crop');
|
||||
ToolbarHelper::modal('resizeModal', 'icon-expand', 'COM_TEMPLATES_BUTTON_RESIZE');
|
||||
$toolbar->cancel('template.close', 'COM_TEMPLATES_BUTTON_CLOSE_FILE');
|
||||
break;
|
||||
|
||||
case 'archive':
|
||||
// Add an extract button
|
||||
$toolbar->standardButton('extract', 'COM_TEMPLATES_BUTTON_EXTRACT_ARCHIVE', 'template.extractArchive')
|
||||
->listCheck(false)
|
||||
->icon('icon-chevron-down');
|
||||
break;
|
||||
|
||||
case 'home':
|
||||
// Add a copy/child template button
|
||||
if (isset($this->template->xmldata->inheritable) && (string) $this->template->xmldata->inheritable === '1') {
|
||||
ToolbarHelper::modal('childModal', 'icon-copy', 'COM_TEMPLATES_BUTTON_TEMPLATE_CHILD');
|
||||
} elseif (empty($this->template->xmldata->parent) && empty($this->template->xmldata->namespace)) {
|
||||
// We can't copy parent templates nor namespaced templates
|
||||
ToolbarHelper::modal('copyModal', 'icon-copy', 'COM_TEMPLATES_BUTTON_COPY_TEMPLATE');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only show file manage buttons for global SuperUser
|
||||
if ($isSuperUser) {
|
||||
if ($this->type === 'home') {
|
||||
// Add Manage folders button
|
||||
ToolbarHelper::modal('folderModal', 'icon-folder icon white', 'COM_TEMPLATES_BUTTON_FOLDERS');
|
||||
|
||||
// Add a new file button
|
||||
ToolbarHelper::modal('fileModal', 'icon-file', 'COM_TEMPLATES_BUTTON_FILE');
|
||||
} else {
|
||||
// Add a Rename file Button
|
||||
ToolbarHelper::modal('renameModal', 'icon-sync', 'COM_TEMPLATES_BUTTON_RENAME_FILE');
|
||||
|
||||
// Add a Delete file Button
|
||||
ToolbarHelper::modal('deleteModal', 'icon-trash', 'COM_TEMPLATES_BUTTON_DELETE_FILE', 'btn-danger');
|
||||
}
|
||||
}
|
||||
|
||||
if (\count($this->updatedList) !== 0 && $this->pluginState && $this->type === 'home') {
|
||||
/** @var DropdownButton $dropdown */
|
||||
$dropdown = $toolbar->dropdownButton('override-group', 'COM_TEMPLATES_BUTTON_CHECK')
|
||||
->toggleSplit(false)
|
||||
->icon('icon-ellipsis-h')
|
||||
->buttonClass('btn btn-action')
|
||||
->form('updateForm')
|
||||
->listCheck(true);
|
||||
|
||||
$childBar = $dropdown->getChildToolbar();
|
||||
|
||||
$childBar->publish('template.publish')
|
||||
->text('COM_TEMPLATES_BUTTON_CHECK_LIST_ENTRY')
|
||||
->form('updateForm')
|
||||
->listCheck(true);
|
||||
$childBar->unpublish('template.unpublish')
|
||||
->text('COM_TEMPLATES_BUTTON_UNCHECK_LIST_ENTRY')
|
||||
->form('updateForm')
|
||||
->listCheck(true);
|
||||
$childBar->unpublish('template.deleteOverrideHistory')
|
||||
->text('COM_TEMPLATES_BUTTON_DELETE_LIST_ENTRY')
|
||||
->form('updateForm')
|
||||
->listCheck(true);
|
||||
}
|
||||
|
||||
if (!\in_array($this->type, ['image', 'file'])) {
|
||||
$toolbar->cancel('template.cancel');
|
||||
}
|
||||
|
||||
$toolbar->divider();
|
||||
$toolbar->help('Templates:_Customise');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for creating the collapsible tree.
|
||||
*
|
||||
* @param array $array The value of the present node for recursion
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @note Uses recursion
|
||||
* @since 3.2
|
||||
*/
|
||||
protected function directoryTree($array)
|
||||
{
|
||||
$temp = $this->files;
|
||||
$this->files = $array;
|
||||
$txt = $this->loadTemplate('tree');
|
||||
$this->files = $temp;
|
||||
|
||||
return $txt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for listing the folder tree in modals.
|
||||
*
|
||||
* @param array $array The value of the present node for recursion
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @note Uses recursion
|
||||
* @since 3.2
|
||||
*/
|
||||
protected function folderTree($array)
|
||||
{
|
||||
$temp = $this->files;
|
||||
$this->files = $array;
|
||||
$txt = $this->loadTemplate('folders');
|
||||
$this->files = $temp;
|
||||
|
||||
return $txt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for creating the collapsible tree.
|
||||
*
|
||||
* @param array $array The value of the present node for recursion
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @note Uses recursion
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function mediaTree($array)
|
||||
{
|
||||
$temp = $this->mediaFiles;
|
||||
$this->mediaFiles = $array;
|
||||
$txt = $this->loadTemplate('tree_media');
|
||||
$this->mediaFiles = $temp;
|
||||
|
||||
return $txt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for listing the folder tree in modals.
|
||||
*
|
||||
* @param array $array The value of the present node for recursion
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @note Uses recursion
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function mediaFolderTree($array)
|
||||
{
|
||||
$temp = $this->mediaFiles;
|
||||
$this->mediaFiles = $array;
|
||||
$txt = $this->loadTemplate('media_folders');
|
||||
$this->mediaFiles = $temp;
|
||||
|
||||
return $txt;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_templates
|
||||
*
|
||||
* @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\Templates\Administrator\View\Templates;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
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\Plugin\PluginHelper;
|
||||
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 templates.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The list of templates
|
||||
*
|
||||
* @var array
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* The pagination object
|
||||
*
|
||||
* @var object
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $pagination;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var object
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.2
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* 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 the parameter enabled to show template positions in the frontend?
|
||||
*
|
||||
* @var boolean
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public $preview;
|
||||
|
||||
/**
|
||||
* The state of installer override plugin.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $pluginState;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @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->preview = ComponentHelper::getParams('com_templates')->get('template_positions_display');
|
||||
$this->file = base64_encode('home');
|
||||
$this->pluginState = PluginHelper::isEnabled('installer', 'override');
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
$canDo = ContentHelper::getActions('com_templates');
|
||||
$clientId = (int) $this->get('State')->get('client_id');
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
// Add a shortcut to the styles list view.
|
||||
$toolbar->linkButton('', 'COM_TEMPLATES_MANAGER_STYLES_BUTTON')
|
||||
->url('index.php?option=com_templates&view=styles&client_id=' . $clientId)
|
||||
->icon('icon-brush thememanager');
|
||||
|
||||
// Set the title.
|
||||
if ($clientId === 1) {
|
||||
ToolbarHelper::title(Text::_('COM_TEMPLATES_MANAGER_TEMPLATES_ADMIN'), 'icon-code thememanager');
|
||||
} else {
|
||||
ToolbarHelper::title(Text::_('COM_TEMPLATES_MANAGER_TEMPLATES_SITE'), 'icon-code thememanager');
|
||||
}
|
||||
|
||||
if ($canDo->get('core.admin') || $canDo->get('core.options')) {
|
||||
$toolbar->preferences('com_templates');
|
||||
$toolbar->divider();
|
||||
}
|
||||
|
||||
$toolbar->help('Templates:_Templates');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user