diff --git a/administrator/components/com_categories/layouts/joomla/form/field/modal-select/extra-buttons.php b/administrator/components/com_categories/layouts/joomla/form/field/modal-select/extra-buttons.php new file mode 100644 index 0000000000000..b1efa7927384d --- /dev/null +++ b/administrator/components/com_categories/layouts/joomla/form/field/modal-select/extra-buttons.php @@ -0,0 +1,83 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +defined('_JEXEC') or die; + +use Joomla\CMS\Factory; +use Joomla\CMS\Language\Text; + +extract($displayData); + +/** + * Layout variables + * ----------------- + * @var string $autocomplete Autocomplete attribute for the field. + * @var boolean $autofocus Is autofocus enabled? + * @var string $class Classes for the input. + * @var string $description Description of the field. + * @var boolean $disabled Is this field disabled? + * @var string $group Group the field belongs to. section in form XML. + * @var boolean $hidden Is this field hidden in the form? + * @var string $hint Placeholder for the field. + * @var string $id DOM id of the field. + * @var string $label Label of the field. + * @var string $labelclass Classes to apply to the label. + * @var boolean $multiple Does this field support multiple values? + * @var string $name Name of the input field. + * @var string $onchange Onchange attribute for the field. + * @var string $onclick Onclick attribute for the field. + * @var string $pattern Pattern (Reg Ex) of value of the form field. + * @var boolean $readonly Is this field read only? + * @var boolean $repeat Allows extensions to duplicate elements. + * @var boolean $required Is this field required? + * @var integer $size Size attribute of the input. + * @var boolean $spellcheck Spellcheck state for the form field. + * @var string $validate Validation rules to apply. + * @var string $value Value attribute of the field. + * @var string $dataAttribute Miscellaneous data attributes preprocessed for HTML output + * @var array $dataAttributes Miscellaneous data attribute for eg, data-* + * @var string $valueTitle + * @var array $canDo + * @var string[] $urls + * @var string[] $modalTitles + * @var string $language + */ + +// Do nothing when propagate is disabled +if (empty($canDo['propagate'])) { + return; +} + +// Scripts for backward compatibility +/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ +$wa = Factory::getApplication()->getDocument()->getWebAssetManager(); +$wa->useScript('field.modal-fields'); +$wa->addInlineScript( + 'window.jSelectCategory_' . $id . ' = function (id, title, object) { + window.processModalSelect("Category", "' . $id . '", id, title, "", object); +}', + ['name' => 'inline.select_category_' . $id], + ['type' => 'module'] +); +Text::script('JGLOBAL_ASSOCIATIONS_PROPAGATE_FAILED'); + +// Language propagate callback name +// Strip off language tag at the end +$tagLength = strlen($language); +$callbackFunctionStem = substr("jSelectCategory_" . $id, 0, -$tagLength); + +?> + + diff --git a/administrator/components/com_categories/src/Controller/CategoryController.php b/administrator/components/com_categories/src/Controller/CategoryController.php index e457e1ae9d950..6ffae68757181 100644 --- a/administrator/components/com_categories/src/Controller/CategoryController.php +++ b/administrator/components/com_categories/src/Controller/CategoryController.php @@ -14,6 +14,7 @@ use Joomla\CMS\MVC\Controller\FormController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\BaseDatabaseModel; +use Joomla\CMS\Router\Route; use Joomla\CMS\Versioning\VersionableControllerTrait; use Joomla\Input\Input; use Joomla\Registry\Registry; @@ -152,6 +153,15 @@ public function cancel($key = null) $newKey = $this->option . '.edit.category.' . substr($this->extension, 4) . '.data'; $this->app->setUserState($newKey, null); + // When editing in modal then redirect to modalreturn layout + if ($result && $this->input->get('layout') === 'modal') { + $id = $this->input->get('id'); + $return = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($id) + . '&layout=modalreturn&from-task=cancel'; + + $this->setRedirect(Route::_($return, false)); + } + return $result; } @@ -243,5 +253,14 @@ protected function postSaveHook(BaseDatabaseModel $model, $validData = []) $registry = new Registry($item->metadata); $item->metadata = (string) $registry; } + + // When editing in modal then redirect to modalreturn layout + if ($this->input->get('layout') === 'modal' && $this->task === 'save') { + $id = $item->id; + $return = 'index.php?option=' . $this->option . '&view=' . $this->view_item . $this->getRedirectToItemAppend($id) + . '&layout=modalreturn&from-task=save'; + + $this->setRedirect(Route::_($return, false)); + } } } diff --git a/administrator/components/com_categories/src/Field/Modal/CategoryField.php b/administrator/components/com_categories/src/Field/Modal/CategoryField.php index 7ff5e2d7d7b06..3783bb677d004 100644 --- a/administrator/components/com_categories/src/Field/Modal/CategoryField.php +++ b/administrator/components/com_categories/src/Field/Modal/CategoryField.php @@ -11,11 +11,12 @@ namespace Joomla\Component\Categories\Administrator\Field\Modal; use Joomla\CMS\Factory; -use Joomla\CMS\Form\FormField; -use Joomla\CMS\HTML\HTMLHelper; +use Joomla\CMS\Form\Field\ModalSelectField; use Joomla\CMS\Language\LanguageHelper; use Joomla\CMS\Language\Text; +use Joomla\CMS\Layout\FileLayout; use Joomla\CMS\Session\Session; +use Joomla\CMS\Uri\Uri; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects @@ -27,7 +28,7 @@ * * @since 3.1 */ -class CategoryField extends FormField +class CategoryField extends ModalSelectField { /** * The form field type. @@ -38,270 +39,151 @@ class CategoryField extends FormField protected $type = 'Modal_Category'; /** - * Method to get the field input markup. + * Method to attach a Form object to the field. * - * @return string The field input markup. + * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `` tag for the form field object. + * @param mixed $value The form field value to validate. + * @param string $group The field name group control value. * - * @since 1.6 + * @return boolean True on success. + * + * @see FormField::setup() + * @since __DEPLOY_VERSION__ */ - protected function getInput() + public function setup(\SimpleXMLElement $element, $value, $group = null) { - if ($this->element['extension']) { - $extension = (string) $this->element['extension']; - } else { - $extension = (string) Factory::getApplication()->getInput()->get('extension', 'com_content'); + // Check if the value consist with id:alias, extract the id only + if ($value && str_contains($value, ':')) { + [$id] = explode(':', $value, 2); + $value = (int) $id; } - $allowNew = ((string) $this->element['new'] == 'true'); - $allowEdit = ((string) $this->element['edit'] == 'true'); - $allowClear = ((string) $this->element['clear'] != 'false'); - $allowSelect = ((string) $this->element['select'] != 'false'); - $allowPropagate = ((string) $this->element['propagate'] == 'true'); - - $languages = LanguageHelper::getContentLanguages([0, 1], false); - - // Load language. - Factory::getLanguage()->load('com_categories', JPATH_ADMINISTRATOR); - - // The active category id field. - $value = (int) $this->value ?: ''; + $result = parent::setup($element, $value, $group); - // Create the modal id. - $modalId = 'Category_' . $this->id; - - /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ - $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); - - // Add the modal field script to the document head. - $wa->useScript('field.modal-fields'); + if (!$result) { + return $result; + } - // Script to proxy the select modal function to the modal-fields.js file. - if ($allowSelect) { - static $scriptSelect = null; + Factory::getApplication()->getLanguage()->load('com_categories', JPATH_ADMINISTRATOR); - if (\is_null($scriptSelect)) { - $scriptSelect = []; - } + $languages = LanguageHelper::getContentLanguages([0, 1], false); + $language = (string) $this->element['language']; + + // Prepare enabled actions + $this->canDo['propagate'] = ((string) $this->element['propagate'] == 'true') && \count($languages) > 2; + + // Prepare Urls + $linkItems = (new Uri())->setPath(Uri::base(true) . '/index.php'); + $linkItems->setQuery([ + 'option' => 'com_categories', + 'view' => 'categories', + 'layout' => 'modal', + 'tmpl' => 'component', + Session::getFormToken() => 1, + ]); + $linkItem = clone $linkItems; + $linkItem->setVar('view', 'category'); + $linkCheckin = (new Uri())->setPath(Uri::base(true) . '/index.php'); + $linkCheckin->setQuery([ + 'option' => 'com_categories', + 'task' => 'categories.checkin', + 'format' => 'json', + Session::getFormToken() => 1, + ]); + + if ($language) { + $linkItems->setVar('forcedLanguage', $language); + $linkItem->setVar('forcedLanguage', $language); + + $modalTitle = Text::_('COM_CATEGORIES_SELECT_A_CATEGORY') . ' — ' . $this->getTitle(); + + $this->dataAttributes['data-language'] = $language; + } else { + $modalTitle = Text::_('COM_CATEGORIES_SELECT_A_CATEGORY'); + } - if (!isset($scriptSelect[$this->id])) { - $wa->addInlineScript( - " - window.jSelectCategory_" . $this->id . " = function (id, title, object) { - window.processModalSelect('Category', '" . $this->id . "', id, title, '', object); - }", - [], - ['type' => 'module'] - ); + $urlSelect = $linkItems; + $urlEdit = clone $linkItem; + $urlEdit->setVar('task', 'category.edit'); + $urlNew = clone $linkItem; + $urlNew->setVar('task', 'category.add'); - Text::script('JGLOBAL_ASSOCIATIONS_PROPAGATE_FAILED'); + $this->urls['select'] = (string) $urlSelect; + $this->urls['new'] = (string) $urlNew; + $this->urls['edit'] = (string) $urlEdit; + $this->urls['checkin'] = (string) $linkCheckin; - $scriptSelect[$this->id] = true; - } - } + // Prepare titles + $this->modalTitles['select'] = $modalTitle; + $this->modalTitles['new'] = Text::_('COM_CATEGORIES_NEW_CATEGORY'); + $this->modalTitles['edit'] = Text::_('COM_CATEGORIES_EDIT_CATEGORY'); - // Setup variables for display. - $linkCategories = 'index.php?option=com_categories&view=categories&layout=modal&tmpl=component&' . Session::getFormToken() . '=1' - . '&extension=' . $extension; - $linkCategory = 'index.php?option=com_categories&view=category&layout=modal&tmpl=component&' . Session::getFormToken() . '=1' - . '&extension=' . $extension; - $modalTitle = Text::_('COM_CATEGORIES_SELECT_A_CATEGORY'); + $this->hint = $this->hint ?: Text::_('COM_CATEGORIES_SELECT_A_CATEGORY'); - if (isset($this->element['language'])) { - $linkCategories .= '&forcedLanguage=' . $this->element['language']; - $linkCategory .= '&forcedLanguage=' . $this->element['language']; - $modalTitle .= ' — ' . $this->element['label']; - } + return $result; + } - $urlSelect = $linkCategories . '&function=jSelectCategory_' . $this->id; - $urlEdit = $linkCategory . '&task=category.edit&id=\' + document.getElementById("' . $this->id . '_id").value + \''; - $urlNew = $linkCategory . '&task=category.add'; + /** + * Method to retrieve the title of selected item. + * + * @return string + * + * @since __DEPLOY_VERSION__ + */ + protected function getValueTitle() + { + $value = (int) $this->value ?: ''; + $title = ''; if ($value) { - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->select($db->quoteName('title')) - ->from($db->quoteName('#__categories')) - ->where($db->quoteName('id') . ' = :value') - ->bind(':value', $value, ParameterType::INTEGER); - $db->setQuery($query); - try { + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->select($db->quoteName('title')) + ->from($db->quoteName('#__categories')) + ->where($db->quoteName('id') . ' = :value') + ->bind(':value', $value, ParameterType::INTEGER); + $db->setQuery($query); + $title = $db->loadResult(); - } catch (\RuntimeException $e) { + } catch (\Throwable $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); } } - $title = empty($title) ? Text::_('COM_CATEGORIES_SELECT_A_CATEGORY') : htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); - - // The current category display field. - $html = ''; - - if ($allowSelect || $allowNew || $allowEdit || $allowClear) { - $html .= ''; - } - - $html .= ''; - - // Select category button. - if ($allowSelect) { - $html .= '' - . ' ' . Text::_('JSELECT') - . ''; - } - - // New category button. - if ($allowNew) { - $html .= '' - . ' ' . Text::_('JACTION_CREATE') - . ''; - } - - // Edit category button. - if ($allowEdit) { - $html .= '' - . ' ' . Text::_('JACTION_EDIT') - . ''; - } - - // Clear category button. - if ($allowClear) { - $html .= '' - . ' ' . Text::_('JCLEAR') - . ''; - } - - // Propagate category button - if ($allowPropagate && \count($languages) > 2) { - // Strip off language tag at the end - $tagLength = (int) \strlen($this->element['language']); - $callbackFunctionStem = substr("jSelectCategory_" . $this->id, 0, -$tagLength); - - $html .= '' - . ' ' . Text::_('JGLOBAL_ASSOCIATIONS_PROPAGATE_BUTTON') - . ''; - } - - if ($allowSelect || $allowNew || $allowEdit || $allowClear) { - $html .= ''; - } - - // Select category modal. - if ($allowSelect) { - $html .= HTMLHelper::_( - 'bootstrap.renderModal', - 'ModalSelect' . $modalId, - [ - 'title' => $modalTitle, - 'url' => $urlSelect, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => 70, - 'modalWidth' => 80, - 'footer' => '', - ] - ); - } - - // New category modal. - if ($allowNew) { - $html .= HTMLHelper::_( - 'bootstrap.renderModal', - 'ModalNew' . $modalId, - [ - 'title' => Text::_('COM_CATEGORIES_NEW_CATEGORY'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'url' => $urlNew, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => 70, - 'modalWidth' => 80, - 'footer' => '' - . '' - . '', - ] - ); - } - - // Edit category modal. - if ($allowEdit) { - $html .= HTMLHelper::_( - 'bootstrap.renderModal', - 'ModalEdit' . $modalId, - [ - 'title' => Text::_('COM_CATEGORIES_EDIT_CATEGORY'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'url' => $urlEdit, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => 70, - 'modalWidth' => 80, - 'footer' => '' - . '' - . '', - ] - ); - } - - // Note: class='required' for client side validation - $class = $this->required ? ' class="required modal-value"' : ''; + return $title ?: $value; + } - $html .= ''; + /** + * Method to get the data to be passed to the layout for rendering. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + $data['language'] = (string) $this->element['language']; - return $html; + return $data; } /** - * Method to get the field label markup. + * Get the renderer + * + * @param string $layoutId Id to load * - * @return string The field label markup. + * @return FileLayout * - * @since 3.7.0 + * @since __DEPLOY_VERSION__ */ - protected function getLabel() + protected function getRenderer($layoutId = 'default') { - return str_replace($this->id, $this->id . '_name', parent::getLabel()); + $layout = parent::getRenderer($layoutId); + $layout->setComponent('com_categories'); + $layout->setClient(1); + + return $layout; } } diff --git a/administrator/components/com_categories/src/View/Category/HtmlView.php b/administrator/components/com_categories/src/View/Category/HtmlView.php index a1290cc23dc42..03c068c84be87 100644 --- a/administrator/components/com_categories/src/View/Category/HtmlView.php +++ b/administrator/components/com_categories/src/View/Category/HtmlView.php @@ -92,6 +92,12 @@ public function display($tpl = null) $this->canDo = ContentHelper::getActions($this->state->get('category.component'), $section . 'category', $this->item->id); $this->assoc = $this->get('Assoc'); + if ($this->getLayout() === 'modalreturn') { + parent::display($tpl); + + return; + } + // Check for errors. if (\count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); @@ -119,6 +125,8 @@ public function display($tpl = null) if ($this->getLayout() !== 'modal') { $this->addToolbar(); + } else { + $this->addModalToolbar(); } parent::display($tpl); @@ -292,4 +300,61 @@ function (Toolbar $childBar) use ($checkedOut, $canDo, $itemEditable) { $toolbar->help($ref_key, $componentParams->exists('helpURL'), $url, $component); } + + /** + * Add the modal toolbar. + * + * @return void + * + * @since __DEPLOY_VERSION__ + * + * @throws \Exception + */ + protected function addModalToolbar() + { + $extension = Factory::getApplication()->getInput()->get('extension'); + $user = $this->getCurrentUser(); + $userId = $user->id; + $isNew = ($this->item->id == 0); + $toolbar = Toolbar::getInstance(); + + // Avoid nonsense situation. + if ($extension == 'com_categories') { + return; + } + + // The extension can be in the form com_foo.section + $parts = explode('.', $extension); + $component = $parts[0]; + + // Need to load the menu language file as mod_menu hasn't been loaded yet. + $lang = $this->getLanguage(); + $lang->load($component, JPATH_BASE) + || $lang->load($component, JPATH_ADMINISTRATOR . '/components/' . $component); + + // Build the actions for new and existing records. + $canDo = $this->canDo; + + // Load specific css component + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = $this->getDocument()->getWebAssetManager(); + $wa->getRegistry()->addExtensionRegistryFile($component); + + if ($wa->assetExists('style', $component . '.admin-categories')) { + $wa->useStyle($component . '.admin-categories'); + } else { + $wa->registerAndUseStyle($component . '.admin-categories', $component . '/administrator/categories.css'); + } + + $canCreate = $isNew; + $canEdit = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_user_id == $userId); + + // For new records, check the create permission. + if ($canCreate || $canEdit) { + $toolbar->apply('category.apply'); + $toolbar->save('category.save'); + } + + $toolbar->cancel('category.cancel'); + } } diff --git a/administrator/components/com_categories/tmpl/categories/modal.php b/administrator/components/com_categories/tmpl/categories/modal.php index 7554482925ad0..93df45fdd3027 100644 --- a/administrator/components/com_categories/tmpl/categories/modal.php +++ b/administrator/components/com_categories/tmpl/categories/modal.php @@ -27,9 +27,11 @@ /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); -$wa->useScript('core'); +$wa->useScript('core') + ->useScript('modal-content-select'); $extension = $this->escape($this->state->get('filter.extension')); +// @todo: Use of Function is deprecated and should be removed in 6.0. It stays only for backward compatibility. $function = $app->getInput()->getCmd('function', 'jSelectCategory'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); @@ -81,18 +83,19 @@ ]; ?> items as $i => $item) : ?> - language && Multilanguage::isEnabled()) { - $tag = strlen($item->language); + language && Multilanguage::isEnabled()) { + $tag = \strlen($item->language); if ($tag == 5) { $lang = substr($item->language, 0, 2); } elseif ($tag == 6) { $lang = substr($item->language, 0, 3); - } else { - $lang = ''; } - } elseif (!Multilanguage::isEnabled()) { - $lang = ''; } + + $link = RouteHelper::getCategoryRoute($item->id, $item->language); + $itemHtml = '' . $item->title . ''; ?> @@ -101,8 +104,15 @@ + id . '"' + . ' data-title="' . $this->escape($item->title) . '"' + . ' data-uri="' . $this->escape($link) . '"' + . ' data-language="' . $this->escape($lang) . '"' + . ' data-html="' . $this->escape($itemHtml) . '"'; + ?> $item->level]); ?> - + onclick="if (window.parent && !window.parent.JoomlaExpectingPostMessage) window.parent.escape($function); ?>('id; ?>', 'escape(addslashes($item->title)); ?>', null, 'escape(RouteHelper::getCategoryRoute($item->id, $item->language)); ?>', 'escape($lang); ?>', null);"> escape($item->title); ?>
note)) : ?> diff --git a/administrator/components/com_categories/tmpl/category/modal.php b/administrator/components/com_categories/tmpl/category/modal.php index 87526bec61712..58b14d2999546 100644 --- a/administrator/components/com_categories/tmpl/category/modal.php +++ b/administrator/components/com_categories/tmpl/category/modal.php @@ -10,6 +10,9 @@ defined('_JEXEC') or die; ?> +
+ document->getToolbar('toolbar')->render(); ?> +
setLayout('edit'); ?> loadTemplate(); ?> diff --git a/administrator/components/com_categories/tmpl/category/modalreturn.php b/administrator/components/com_categories/tmpl/category/modalreturn.php new file mode 100644 index 0000000000000..744ed66171977 --- /dev/null +++ b/administrator/components/com_categories/tmpl/category/modalreturn.php @@ -0,0 +1,44 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +defined('_JEXEC') or die; + +use Joomla\Component\Content\Site\Helper\RouteHelper; + +$icon = 'icon-check'; +$title = $this->item ? $this->item->title : ''; +$content = $this->item ? $this->item->alias : ''; +$data = ['contentType' => $this->state->get('category.component') . '.category']; + +if ($this->item) { + $data['id'] = $this->item->id; + $data['title'] = $this->item->title; + $data['uri'] = RouteHelper::getCategoryRoute($this->item->id, $this->item->language); +} + +// Add Content select script +/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ +$wa = $this->document->getWebAssetManager(); +$wa->useScript('modal-content-select'); + +// The data for Content select script +$this->document->addScriptOptions('content-select-on-load', $data, false); + +?> + +
+ +

+
+

+ +

+
+