File manager - Edit - /home/opticamezl/www/newok/com_guidedtours.tar
Back
config.xml 0000644 00000000476 15172634556 0006560 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <config> <fieldset name="permissions" label="JCONFIG_PERMISSIONS_LABEL" > <field name="rules" type="rules" label="JCONFIG_PERMISSIONS_LABEL" validate="rules" filter="rules" component="com_guidedtours" section="component" /> </fieldset> </config> services/provider.php 0000644 00000003531 15172634556 0010752 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface; use Joomla\CMS\Extension\ComponentInterface; use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory; use Joomla\CMS\Extension\Service\Provider\MVCFactory; use Joomla\CMS\HTML\Registry; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\Component\Guidedtours\Administrator\Extension\GuidedtoursComponent; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * The Guidedtours service provider. * * @since 4.3.0 */ return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.3.0 */ public function register(Container $container) { $container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Guidedtours')); $container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Guidedtours')); $container->set( ComponentInterface::class, function (Container $container) { $component = new GuidedtoursComponent($container->get(ComponentDispatcherFactoryInterface::class)); $component->setRegistry($container->get(Registry::class)); $component->setMVCFactory($container->get(MVCFactoryInterface::class)); return $component; } ); } }; guidedtours.xml 0000644 00000001772 15172634556 0007651 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <extension type="component" method="upgrade"> <name>com_guidedtours</name> <author>Joomla! Project</author> <creationDate>2023-02</creationDate> <copyright>(C) 2023 Open Source Matters, Inc.</copyright> <license>GNU General Public License version 2 or later; see LICENSE.txt</license> <authorEmail>admin@joomla.org</authorEmail> <authorUrl>www.joomla.org</authorUrl> <version>4.3.0</version> <description>COM_GUIDEDTOURS_XML_DESCRIPTION</description> <namespace path="src">Joomla\Component\Guidedtours</namespace> <administration> <filename>access.xml</filename> <filename>config.xml</filename> <filename>guidedtours.xml</filename> <folder>forms</folder> <folder>services</folder> <folder>src</folder> <folder>tmpl</folder> <languages folder="administrator"> <language tag="en-GB">language/en-GB/com_guidedtours.ini</language> <language tag="en-GB">language/en-GB/com_guidedtours.sys.ini</language> </languages> </administration> </extension> access.xml 0000644 00000001074 15172634556 0006547 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <access component="com_guidedtours"> <section name="component"> <action name="core.admin" title="JACTION_ADMIN" /> <action name="core.options" title="JACTION_OPTIONS" /> <action name="core.manage" title="JACTION_MANAGE" /> <action name="core.create" title="JACTION_CREATE" /> <action name="core.delete" title="JACTION_DELETE" /> <action name="core.edit" title="JACTION_EDIT" /> <action name="core.edit.state" title="JACTION_EDITSTATE" /> <action name="core.edit.own" title="JACTION_EDITOWN" /> </section> </access> forms/tour.xml 0000644 00000005171 15172634556 0007427 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form addfieldprefix="Joomla\Component\Guidedtours\Administrator\Field"> <config> <inlinehelp button="show"/> </config> <field name="id" type="text" label="JGLOBAL_FIELD_ID_LABEL" class="readonly" readonly="true" default="0" /> <field name="title" type="text" label="COM_GUIDEDTOURS_TITLE" required="true" /> <field name="title_translation" type="text" label="JGLOBAL_TITLE" readonly="true" /> <field name="description" type="editor" label="JGLOBAL_DESCRIPTION" filter="JComponentHelper::filterText" buttons="true" hide="readmore,pagebreak,module,menu,fields,contact,article" /> <field name="description_translation" type="editor" label="JGLOBAL_DESCRIPTION" filter="JComponentHelper::filterText" buttons="false" readonly="true" /> <field name="published" type="list" label="JSTATUS" default="1" class="form-select-color-state" validate="options" > <option value="1">JPUBLISHED</option> <option value="0">JUNPUBLISHED</option> <option value="2">JARCHIVED</option> <option value="-2">JTRASHED</option> </field> <field name="checked_out" type="hidden" filter="unset" /> <field name="checked_out_time" type="hidden" filter="unset" /> <field name="access" type="accesslevel" label="JFIELD_ACCESS_LABEL" filter="UINT" validate="options" /> <field name="created_by" type="user" label="JGLOBAL_FIELD_CREATED_BY_LABEL" validate="UserId" /> <field name="created" type="calendar" label="JGLOBAL_CREATED_DATE" translateformat="true" showtime="true" filter="user_utc" /> <field name="modified_by" type="user" label="JGLOBAL_FIELD_MODIFIED_BY_LABEL" class="readonly" readonly="true" filter="unset" validate="UserId" /> <field name="modified" type="calendar" label="JGLOBAL_FIELD_MODIFIED_LABEL" class="readonly" readonly="true" translateformat="true" showtime="true" filter="user_utc" /> <field name="language" type="contentlanguage" label="JFIELD_LANGUAGE_LABEL" default="*" > <option value="*">JALL</option> </field> <field name="note" type="text" label="COM_GUIDEDTOURS_FIELD_NOTE_LABEL" maxlength="255" /> <field name="url" type="url" label="COM_GUIDEDTOURS_URL_LABEL" description="COM_GUIDEDTOURS_URL_DESC" required="true" /> <field name="extensions" type="components" label="COM_GUIDEDTOURS_EXTENSIONS_LABEL" description="COM_GUIDEDTOURS_EXTENSIONS_DESC" required="true" multiple="multiple" layout="joomla.form.field.list-fancy-select" default="*" > <option value="*">JALL</option> </field> </form> forms/step.xml 0000644 00000007562 15172634556 0007417 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form addfieldprefix="Joomla\Component\Guidedtours\Administrator\Field"> <config> <inlinehelp button="show"/> </config> <field name="id" type="text" label="JGLOBAL_FIELD_ID_LABEL" default="0" class="readonly" readonly="true" /> <field name="position" type="list" label="COM_GUIDEDTOURS_STEP_POSITION_LABEL" description="COM_GUIDEDTOURS_STEP_POSITION_DESC" default="center" validate="options" > <option value="bottom">JGLOBAL_BOTTOM</option> <option value="center">JGLOBAL_CENTER</option> <option value="left">JGLOBAL_LEFT</option> <option value="right">JGLOBAL_RIGHT</option> <option value="top">JGLOBAL_TOP</option> </field> <field name="target" type="text" label="COM_GUIDEDTOURS_STEP_TARGET_LABEL" description="COM_GUIDEDTOURS_STEP_TARGET_DESC" /> <field name="tour_id" type="hidden" class="readonly" readonly="true" /> <field name="title" type="text" label="COM_GUIDEDTOURS_STEP_TITLE" required="true" /> <field name="title_translation" type="text" label="JGLOBAL_TITLE" readonly="true" /> <field name="description" type="editor" label="JGLOBAL_DESCRIPTION" filter="JComponentHelper::filterText" buttons="true" hide="readmore,pagebreak,module,menu,fields,contact,article" /> <field name="description_translation" type="editor" label="JGLOBAL_DESCRIPTION" filter="JComponentHelper::filterText" buttons="false" readonly="true" /> <field name="published" type="list" label="JSTATUS" default="1" class="form-select-color-state" validate="options" > <option value="1">JPUBLISHED</option> <option value="0">JUNPUBLISHED</option> <option value="2">JARCHIVED</option> <option value="-2">JTRASHED</option> </field> <field name="type" type="list" label="COM_GUIDEDTOURS_STEP_TYPE_LABEL" description="COM_GUIDEDTOURS_STEP_TYPE_DESC" default="0" validate="options" > <option value="0">COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_NEXT</option> <option value="1">COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_REDIRECT</option> <option value="2">COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_INTERACTIVE</option> </field> <field name="url" type="url" label="COM_GUIDEDTOURS_TYPE_REDIRECT_URL_LABEL" description="COM_GUIDEDTOURS_TYPE_REDIRECT_URL_DESC" showon="type:1" filter="string" /> <field name="interactive_type" type="list" label="COM_GUIDEDTOURS_TYPE_INTERACTIVE_STEP_LABEL" description="COM_GUIDEDTOURS_TYPE_INTERACTIVE_STEP_DESC" showon="type:2" filter="string" validate="options" > <option value="1">COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_FORM_SUBMIT</option> <option value="2">COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_TEXT_FIELD</option> <option value="4">COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_BUTTON</option> <option value="3">COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_OTHER</option> </field> <field name="checked_out" type="hidden" filter="unset" /> <field name="checked_out_time" type="hidden" filter="unset" /> <field name="created_by" type="user" label="JGLOBAL_FIELD_CREATED_BY_LABEL" validate="UserId" /> <field name="created" type="calendar" label="JGLOBAL_CREATED_DATE" translateformat="true" showtime="true" filter="user_utc" /> <field name="modified_by" type="user" label="JGLOBAL_FIELD_MODIFIED_BY_LABEL" class="readonly" readonly="true" filter="unset" validate="UserId" /> <field name="modified" type="calendar" label="JGLOBAL_FIELD_MODIFIED_LABEL" class="readonly" readonly="true" translateformat="true" showtime="true" filter="user_utc" /> <field name="language" type="contentlanguage" label="JFIELD_LANGUAGE_LABEL" default="*" > <option value="*">JALL</option> </field> <field name="note" type="text" label="COM_GUIDEDTOURS_FIELD_NOTE_LABEL" maxlength="255" /> </form> forms/filter_steps.xml 0000644 00000002554 15172634556 0011143 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fields name="filter"> <field name="search" type="text" label="COM_GUIDEDTOURS_STEP_FILTER_SEARCH_LABEL" description="COM_GUIDEDTOURS_STEP_FILTER_SEARCH_DESC" inputmode="search" hint="JSEARCH_FILTER" /> <field name="published" type="status" label="JOPTION_SELECT_PUBLISHED" class="js-select-submit-on-change" > <option value="">JOPTION_SELECT_PUBLISHED</option> </field> </fields> <fields name="list"> <field name="fullordering" type="list" label="JGLOBAL_SORT_BY" class="js-select-submit-on-change" default="a.ordering ASC" validate="options" > <option value="">JGLOBAL_SORT_BY</option> <option value="a.ordering ASC">JGRID_HEADING_ORDERING_ASC</option> <option value="a.ordering DESC">JGRID_HEADING_ORDERING_DESC</option> <option value="a.published ASC">JSTATUS_ASC</option> <option value="a.published DESC">JSTATUS_DESC</option> <option value="a.type ASC">COM_GUIDEDTOURS_ORDER_TYPE_ASC</option> <option value="a.type DESC">COM_GUIDEDTOURS_ORDER_TYPE_DESC</option> <option value="a.id ASC">JGRID_HEADING_ID_ASC</option> <option value="a.id DESC">JGRID_HEADING_ID_DESC</option> </field> <field name="limit" type="limitbox" label="JGLOBAL_LIST_LIMIT" default="25" class="js-select-submit-on-change" /> </fields> </form> forms/filter_tours.xml 0000644 00000003670 15172634556 0011161 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fields name="filter"> <field name="search" type="text" label="COM_GUIDEDTOURS_FILTER_SEARCH_LABEL" description="COM_GUIDEDTOURS_FILTER_SEARCH_DESC" inputmode="search" hint="JSEARCH_FILTER" /> <field name="published" type="status" label="JOPTION_SELECT_PUBLISHED" class="js-select-submit-on-change" > <option value="">JOPTION_SELECT_PUBLISHED</option> </field> <field name="access" type="accesslevel" label="JGRID_HEADING_ACCESS" class="js-select-submit-on-change" > <option value="">JOPTION_SELECT_ACCESS</option> </field> <field name="language" type="contentlanguage" label="JGRID_HEADING_LANGUAGE" class="js-select-submit-on-change" > <option value="">JOPTION_SELECT_LANGUAGE</option> <option value="*">JALL</option> </field> </fields> <fields name="list"> <field name="fullordering" type="list" label="JGLOBAL_SORT_BY" class="js-select-submit-on-change" default="a.ordering ASC" validate="options" > <option value="">JGLOBAL_SORT_BY</option> <option value="a.ordering ASC">JGRID_HEADING_ORDERING_ASC</option> <option value="a.ordering DESC">JGRID_HEADING_ORDERING_DESC</option> <option value="a.published ASC">JSTATUS_ASC</option> <option value="a.published DESC">JSTATUS_DESC</option> <option value="a.access ASC">JGRID_HEADING_ACCESS_ASC</option> <option value="a.access DESC">JGRID_HEADING_ACCESS_DESC</option> <option value="a.language ASC" requires="multilanguage">JGRID_HEADING_LANGUAGE_ASC</option> <option value="a.language DESC" requires="multilanguage">JGRID_HEADING_LANGUAGE_DESC</option> <option value="a.id ASC">JGRID_HEADING_ID_ASC</option> <option value="a.id DESC">JGRID_HEADING_ID_DESC</option> </field> <field name="limit" type="limitbox" label="JGLOBAL_LIST_LIMIT" default="25" class="js-select-submit-on-change" /> </fields> </form> src/View/Steps/HtmlView.php 0000644 00000012777 15172634556 0011647 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\View\Steps; 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\Router\Route; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View class for a list of guidedtour_steps. * * @since 4.3.0 */ 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\CMS\Object\CMSObject */ protected $state; /** * Form object for search filters * * @var \Joomla\CMS\Form\Form */ public $filterForm; /** * The active search filters * * @var array */ public $activeFilters; /** * Is this view an Empty State * * @var boolean * * @since 4.3.0 */ private $isEmptyState = false; /** * Display the view. * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void */ public function display($tpl = null) { $this->items = $this->get('Items'); $this->pagination = $this->get('Pagination'); $this->state = $this->get('State'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) { $this->setLayout('emptystate'); } // Check for errors. if (\count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } if ($this->state->get('filter.tour_id', -1) < 0) { throw new GenericDataException(implode("\n", $errors), 500); } // Unset the tour_id field from activeFilters as we don't filter by tour here. unset($this->activeFilters['tour_id']); $this->addToolbar(); parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.3.0 */ protected function addToolbar() { // Get the toolbar object instance $toolbar = Toolbar::getInstance('toolbar'); $canDo = ContentHelper::getActions('com_guidedtours'); $app = Factory::getApplication(); $user = $app->getIdentity(); /** @var \Joomla\Component\Guidedtours\Administrator\Model\TourModel $tourModel */ $tourModel = $app->bootComponent('com_guidedtours') ->getMVCFactory()->createModel('Tour', 'Administrator', ['ignore_request' => true]); $tour = $tourModel->getItem($this->state->get('filter.tour_id', -1)); $title = !empty($tour->title) ? $tour->title : ''; ToolbarHelper::title(Text::sprintf('COM_GUIDEDTOURS_STEPS_LIST', Text::_($title)), 'map-signs'); $arrow = $this->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'; ToolbarHelper::link( Route::_('index.php?option=com_guidedtours&view=tours'), 'JTOOLBAR_BACK', $arrow ); if ($canDo->get('core.create')) { $toolbar->addNew('step.add'); } if (!$this->isEmptyState && $canDo->get('core.edit.state')) { $dropdown = $toolbar->dropdownButton('status-group') ->text('JTOOLBAR_CHANGE_STATUS') ->toggleSplit(false) ->icon('icon-ellipsis-h') ->buttonClass('btn btn-action') ->listCheck(true); $childBar = $dropdown->getChildToolbar(); $childBar->publish('steps.publish')->listCheck(true); $childBar->unpublish('steps.unpublish')->listCheck(true); $childBar->archive('steps.archive')->listCheck(true); $childBar->checkin('steps.checkin')->listCheck(true); if ($this->state->get('filter.published') != -2) { $childBar->trash('steps.trash')->listCheck(true); } } if (!$this->isEmptyState && $this->state->get('filter.published') == -2 && $canDo->get('core.delete')) { $toolbar->delete('steps.delete') ->text('JTOOLBAR_EMPTY_TRASH') ->message('JGLOBAL_CONFIRM_DELETE') ->listCheck(true); } if ($user->authorise('core.admin', 'com_guidedtours') || $user->authorise('core.options', 'com_guidedtours')) { $toolbar->preferences('com_guidedtours'); } ToolbarHelper::help('Guided_Tours:_Steps'); } /** * Returns an array of fields the table can be sorted by * * @return array Array containing the field name to sort by as the key and display text as value * * @since 4.3.0 */ protected function getSortFields() { return [ 'a.id' => Text::_('JGRID_HEADING_ID'), ]; } } src/View/Tour/HtmlView.php 0000644 00000010452 15172634556 0011466 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\View\Tour; 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 an tour. * * @since 4.3.0 */ class HtmlView extends BaseHtmlView { /** * The \JForm object * * @var \Joomla\CMS\Form\Form */ protected $form; /** * The active item * * @var object */ protected $item; /** * The model state * * @var object */ protected $state; /** * The actions the user is authorised to perform * * @var \Joomla\CMS\Object\CMSObject */ protected $canDo; /** * 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 * * @throws \Exception * @since 4.3.0 */ public function display($tpl = null) { $this->form = $this->get('Form'); $this->item = $this->get('Item'); $this->state = $this->get('State'); 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 * * @throws \Exception * @since 4.3.0 */ protected function addToolbar() { Factory::getApplication()->getInput()->set('hidemainmenu', true); $user = Factory::getApplication()->getIdentity(); $userId = $user->id; $isNew = empty($this->item->id); $canDo = ContentHelper::getActions('com_guidedtours'); ToolbarHelper::title(Text::_($isNew ? 'COM_GUIDEDTOURS_MANAGER_TOUR_NEW' : 'COM_GUIDEDTOURS_MANAGER_TOUR_EDIT'), 'map-signs'); $toolbarButtons = []; if ($isNew) { // For new records, check the create permission. if ($canDo->get('core.create')) { ToolbarHelper::apply('tour.apply'); $toolbarButtons = [['save', 'tour.save'], ['save2new', 'tour.save2new']]; } ToolbarHelper::saveGroup( $toolbarButtons, 'btn-success' ); ToolbarHelper::cancel( 'tour.cancel' ); } else { // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId); if ($itemEditable) { ToolbarHelper::apply('tour.apply'); $toolbarButtons = [['save', 'tour.save']]; // We can save this record, but check the create permission to see if we can return to make a new one. if ($canDo->get('core.create')) { $toolbarButtons[] = ['save2new', 'tour.save2new']; $toolbarButtons[] = ['save2copy', 'tour.save2copy']; } ToolbarHelper::saveGroup( $toolbarButtons, 'btn-success' ); ToolbarHelper::cancel( 'tour.cancel', 'JTOOLBAR_CLOSE' ); } } ToolbarHelper::divider(); $inlinehelp = (string) $this->form->getXml()->config->inlinehelp['button'] == 'show' ?: false; $targetClass = (string) $this->form->getXml()->config->inlinehelp['targetclass'] ?: 'hide-aware-inline-help'; if ($inlinehelp) { ToolbarHelper::inlinehelp($targetClass); } ToolbarHelper::help('Guided_Tours:_New_or_Edit_Tour'); } } src/View/Step/HtmlView.php 0000644 00000010370 15172634556 0011447 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\View\Step; 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\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View to edit an Step * * @since 4.3.0 */ class HtmlView extends BaseHtmlView { /** * The \JForm object * * @var \Joomla\CMS\Form\Form */ protected $form; /** * The active item * * @var object */ protected $item; /** * The model state * * @var object */ protected $state; /** * The actions the user is authorised to perform * * @var \Joomla\CMS\Object\CMSObject */ protected $canDo; /** * 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 * * @throws \Exception * @since 4.3.0 */ public function display($tpl = null) { $this->form = $this->get('Form'); $this->item = $this->get('Item'); $this->state = $this->get('State'); 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 * * @throws \Exception * @since 4.3.0 */ protected function addToolbar() { Factory::getApplication()->getInput()->set('hidemainmenu', true); $user = $this->getCurrentUser(); $userId = $user->id; $isNew = empty($this->item->id); $canDo = ContentHelper::getActions('com_guidedtours'); ToolbarHelper::title(Text::_($isNew ? 'COM_GUIDEDTOURS_MANAGER_STEP_NEW' : 'COM_GUIDEDTOURS_MANAGER_STEP_EDIT'), 'map-signs'); $toolbarButtons = []; if ($isNew) { // For new records, check the create permission. if ($canDo->get('core.create')) { ToolbarHelper::apply('step.apply'); $toolbarButtons = [['save', 'step.save'], ['save2new', 'step.save2new']]; } ToolbarHelper::saveGroup( $toolbarButtons, 'btn-success' ); ToolbarHelper::cancel( 'step.cancel' ); } else { // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId); if ($itemEditable) { ToolbarHelper::apply('step.apply'); $toolbarButtons = [['save', 'step.save']]; // We can save this record, but check the create permission to see if we can return to make a new one. if ($canDo->get('core.create')) { $toolbarButtons[] = ['save2new', 'step.save2new']; $toolbarButtons[] = ['save2copy', 'step.save2copy']; } ToolbarHelper::saveGroup( $toolbarButtons, 'btn-success' ); ToolbarHelper::cancel( 'step.cancel', 'JTOOLBAR_CLOSE' ); } } ToolbarHelper::divider(); $inlinehelp = (string) $this->form->getXml()->config->inlinehelp['button'] == 'show' ?: false; $targetClass = (string) $this->form->getXml()->config->inlinehelp['targetclass'] ?: 'hide-aware-inline-help'; if ($inlinehelp) { ToolbarHelper::inlinehelp($targetClass); } ToolbarHelper::help('Guided_Tours:_New_or_Edit_Step'); } } src/View/Tours/HtmlView.php 0000644 00000011335 15172634556 0011652 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\View\Tours; use Joomla\CMS\Factory; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View class for a list of guidedtours. * * @since 4.3.0 */ 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\CMS\Object\CMSObject */ protected $state; /** * Form object for search filters * * @var \Joomla\CMS\Form\Form */ public $filterForm; /** * The active search filters * * @var array */ public $activeFilters; /** * Is this view an Empty State * * @var boolean * * @since 4.3.0 */ private $isEmptyState = false; /** * Display the view. * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void */ public function display($tpl = null) { $this->items = $this->get('Items'); $this->pagination = $this->get('Pagination'); $this->state = $this->get('State'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) { $this->setLayout('emptystate'); } // Check for errors. if (\count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $this->addToolbar(); // We do not need to filter by language when multilingual is disabled if (!Multilanguage::isEnabled()) { unset($this->activeFilters['language']); $this->filterForm->removeField('language', 'filter'); } parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.3.0 */ protected function addToolbar() { // Get the toolbar object instance $toolbar = Toolbar::getInstance('toolbar'); ToolbarHelper::title(Text::_('COM_GUIDEDTOURS_TOURS_LIST'), 'map-signs'); $canDo = ContentHelper::getActions('com_guidedtours'); $user = Factory::getApplication()->getIdentity(); if ($canDo->get('core.create')) { $toolbar->addNew('tour.add'); } if (!$this->isEmptyState && $canDo->get('core.edit.state')) { $dropdown = $toolbar->dropdownButton('status-group') ->text('JTOOLBAR_CHANGE_STATUS') ->toggleSplit(false) ->icon('icon-ellipsis-h') ->buttonClass('btn btn-action') ->listCheck(true); $childBar = $dropdown->getChildToolbar(); $childBar->publish('tours.publish')->listCheck(true); $childBar->unpublish('tours.unpublish')->listCheck(true); $childBar->archive('tours.archive')->listCheck(true); $childBar->checkin('tours.checkin')->listCheck(true); if ($this->state->get('filter.published') != -2) { $childBar->trash('tours.trash')->listCheck(true); } if ($canDo->get('core.create')) { $childBar->standardButton('copy') ->text('JTOOLBAR_DUPLICATE') ->task('tours.duplicate') ->listCheck(true); } } if (!$this->isEmptyState && $this->state->get('filter.published') == -2 && $canDo->get('core.delete')) { $toolbar->delete('tours.delete') ->text('JTOOLBAR_EMPTY_TRASH') ->message('JGLOBAL_CONFIRM_DELETE') ->listCheck(true); } if ($user->authorise('core.admin', 'com_guidedtours') || $user->authorise('core.options', 'com_guidedtours')) { $toolbar->preferences('com_guidedtours'); } ToolbarHelper::help('Guided_Tours'); } } src/Controller/TourController.php 0000644 00000001102 15172634556 0013174 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Controller; use Joomla\CMS\MVC\Controller\FormController; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Controller for a single Tour * * @since 4.3.0 */ class TourController extends FormController { } src/Controller/DisplayController.php 0000644 00000004536 15172634556 0013666 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Controller; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\BaseController; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Router\Route; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Component Controller * * @since 4.3.0 */ class DisplayController extends BaseController { /** * The default view. * * @var string * @since 4.3.0 */ protected $default_view = 'tours'; /** * Method to display a view. * * @param boolean $cachable If true, the view output will be cached * @param array $urlparams An array of safe URL parameters and their variable types, for valid values see {@link \JFilterInput::clean()}. * * @return static |boolean This object to support chaining. False on failure. * * @since 4.3.0 */ public function display($cachable = false, $urlparams = []) { $view = $this->input->get('view', $this->default_view); $layout = $this->input->get('layout', 'default'); $id = $this->input->getInt('id'); // Show messages about the disabled plugin if ($view === 'tours' && !PluginHelper::isEnabled('system', 'guidedtours')) { $this->app->enqueueMessage(Text::_('COM_GUIDEDTOURS_PLUGIN_DISABLED'), 'error'); } if ($view === 'tour' && $layout === 'edit' && !$this->checkEditId('com_guidedtours.edit.tour', $id)) { $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 'error'); $this->setRedirect(Route::_('index.php?option=com_guidedtours&view=tours', false)); return false; } if ($view === 'step' && $layout === 'edit' && !$this->checkEditId('com_guidedtours.edit.step', $id)) { $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 'error'); $this->setRedirect(Route::_('index.php?option=com_guidedtours&view=steps', false)); return false; } return parent::display(); } } src/Controller/StepController.php 0000644 00000001102 15172634556 0013156 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Controller; use Joomla\CMS\MVC\Controller\FormController; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Controller for a single step * * @since 4.3.0 */ class StepController extends FormController { } src/Controller/StepsController.php 0000644 00000002077 15172634556 0013355 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Controller; use Joomla\CMS\MVC\Controller\AdminController; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Component Controller * * @since 4.3.0 */ class StepsController extends AdminController { /** * Proxy for getModel. * * @param string $name The model name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config The array of possible config values. Optional. * * @return \Joomla\CMS\MVC\Model\BaseDatabaseModel * * @since 4.3.0 */ public function getModel($name = 'Step', $prefix = 'Administrator', $config = ['ignore_request' => true]) { return parent::getModel($name, $prefix, $config); } } src/Controller/ToursController.php 0000644 00000003555 15172634556 0013375 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Controller; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\AdminController; use Joomla\CMS\Router\Route; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Guidedtours list controller class. * * @since 4.3.0 */ class ToursController extends AdminController { /** * Proxy for getModel. * * @param string $name The model name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config The array of possible config values. Optional. * * @return \Joomla\CMS\MVC\Model\BaseDatabaseModel * * @since 4.3.0 */ public function getModel($name = 'Tour', $prefix = 'Administrator', $config = ['ignore_request' => true]) { return parent::getModel($name, $prefix, $config); } public function duplicate() { $this->checkToken(); $pks = (array) $this->input->post->get('cid', [], 'int'); $pks = array_filter($pks); try { if (empty($pks)) { throw new \Exception(Text::_('COM_GUIDEDTOURS_ERROR_NO_GUIDEDTOURS_SELECTED')); } $model = $this->getModel(); $model->duplicate($pks); $this->setMessage(Text::plural('COM_GUIDEDTOURS_TOURS_DUPLICATED', count($pks))); } catch (\Exception $e) { $this->app->enqueueMessage($e->getMessage(), 'warning'); } $this->setRedirect(Route::_('index.php?option=com_guidedtours&view=tours' . $this->getRedirectToListAppend(), false)); } } src/Model/StepsModel.php 0000644 00000016521 15172634556 0011206 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\ListModel; use Joomla\Database\DatabaseQuery; use Joomla\Database\ParameterType; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Methods supporting a list of steps records. * * @since 4.3.0 */ class StepsModel extends ListModel { /** * Constructor. * * @param array $config An optional associative array of configuration settings. * * @since 4.3.0 * @see \Joomla\CMS\MVC\Controller\BaseController */ public function __construct($config = []) { if (empty($config['filter_fields'])) { $config['filter_fields'] = [ 'id', 'a.id', 'tour_id', 'a.tour_id', 'title', 'a.title', 'type', 'a.type', 'description', 'a.description', 'published', 'a.published', 'ordering', 'a.ordering', 'created_by', 'a.created_by', 'modified', 'a.modified', 'modified_by', 'a.modified_by', 'note', 'a.note', ]; } parent::__construct($config); } /** * Provide a query to be used to evaluate if this is an Empty State, can be overridden in the model to provide granular control. * * @return DatabaseQuery * * @since 4.3.0 */ protected function getEmptyStateQuery() { $query = parent::getEmptyStateQuery(); $tourId = $this->getState('filter.tour_id'); if ($tourId) { $tourId = (int) $tourId; $query->where($this->getDatabase()->quoteName('a.tour_id') . ' = :tour_id') ->bind(':tour_id', $tourId, ParameterType::INTEGER); } return $query; } /** * Method to auto-populate the model state. * * Note. Calling getState in this method will result in recursion. * * @param string $ordering An optional ordering field. * @param string $direction An optional direction (asc|desc). * * @return void * * @since 4.3.0 */ protected function populateState($ordering = 'a.ordering', $direction = 'ASC') { $app = Factory::getApplication(); $tourId = $app->getUserStateFromRequest($this->context . '.filter.tour_id', 'tour_id', 0, 'int'); if (empty($tourId)) { $tourId = $app->getUserState('com_guidedtours.tour_id'); } $this->setState('filter.tour_id', $tourId); // Keep the tour_id for adding new visits $app->setUserState('com_guidedtours.tour_id', $tourId); // 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. * * @since 4.3.0 */ protected function getStoreId($id = '') { // Compile the store id. $id .= ':' . $this->getState('filter.tour_id'); $id .= ':' . $this->getState('filter.search'); $id .= ':' . $this->getState('filter.published'); return parent::getStoreId($id); } /** * Build an SQL query to load the list data. * * @return \Joomla\Database\DatabaseQuery * * @since 4.3.0 */ 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.*' ) ); $query->from($db->quoteName('#__guidedtour_steps', 'a')); // Join with user table $query->select( [ $db->quoteName('uc.name', 'editor'), ] ) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')); $tourId = $this->getState('filter.tour_id'); if (is_numeric($tourId)) { $tourId = (int) $tourId; $query->where($db->quoteName('a.tour_id') . ' = :tour_id') ->bind(':tour_id', $tourId, ParameterType::INTEGER); } elseif (is_array($tourId)) { $tourId = ArrayHelper::toInteger($tourId); $query->whereIn($db->quoteName('a.tour_id'), $tourId); } // Published state $published = (string) $this->getState('filter.published'); if (is_numeric($published)) { $query->where($db->quoteName('a.published') . ' = :published'); $query->bind(':published', $published, ParameterType::INTEGER); } elseif ($published === '') { $query->where('(' . $db->quoteName('a.published') . ' = 0 OR ' . $db->quoteName('a.published') . ' = 1)'); } // Filter by search in title. $search = $this->getState('filter.search'); if (!empty($search)) { if (stripos($search, 'id:') === 0) { $search = (int) substr($search, 3); $query->where($db->quoteName('a.id') . ' = :search') ->bind(':search', $search, ParameterType::INTEGER); } elseif (stripos($search, 'description:') === 0) { $search = '%' . substr($search, 12) . '%'; $query->where('(' . $db->quoteName('a.description') . ' LIKE :search1)') ->bind([':search1'], $search); } else { $search = '%' . str_replace(' ', '%', trim($search)) . '%'; $query->where( '(' . $db->quoteName('a.title') . ' LIKE :search1' . ' OR ' . $db->quoteName('a.description') . ' LIKE :search2' . ' OR ' . $db->quoteName('a.note') . ' LIKE :search3)' ) ->bind([':search1', ':search2', ':search3'], $search); } } // Add the list ordering clause. $orderCol = $this->state->get('list.ordering', 'a.ordering'); $orderDirn = $this->state->get('list.direction', 'ASC'); $query->order($db->escape($orderCol) . ' ' . $db->escape($orderDirn)); return $query; } /** * Method to get an array of data items. * * @return mixed An array of data items on success, false on failure. * * @since 4.3.0 */ public function getItems() { $items = parent::getItems(); Factory::getLanguage()->load('com_guidedtours.sys', JPATH_ADMINISTRATOR); foreach ($items as $item) { $item->title = Text::_($item->title); $item->description = Text::_($item->description); } return $items; } } src/Model/TourModel.php 0000644 00000035023 15172634556 0011037 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\CMS\Object\CMSObject; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\ParameterType; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for tour * * @since 4.3.0 */ class TourModel extends AdminModel { /** * The prefix to use with controller messages. * * @var string * @since 4.3.0 */ protected $text_prefix = 'COM_GUIDEDTOURS'; /** * Type alias for content type * * @var string * @since 4.3.0 */ public $typeAlias = 'com_guidedtours.tour'; /** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success. * * @since 4.3.0 */ public function save($data) { $input = Factory::getApplication()->getInput(); // Language keys must include GUIDEDTOUR to prevent save issues if (strpos($data['description'], 'GUIDEDTOUR') !== false) { $data['description'] = strip_tags($data['description']); } if ($input->get('task') == 'save2copy') { $origTable = clone $this->getTable(); $origTable->load($input->getInt('id')); $data['published'] = 0; } // Set step language to parent tour language on save. $id = $data['id']; $lang = $data['language']; $this->setStepsLanguage($id, $lang); return parent::save($data); } /** * Prepare and sanitise the table prior to saving. * * @param \Joomla\CMS\Table\Table $table The Table object * * @return void * * @since 4.3.0 */ protected function prepareTable($table) { $date = Factory::getDate()->toSql(); $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); if (empty($table->id)) { // Set the values $table->created = $date; // Set ordering to the last item if not set if (empty($table->ordering)) { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('MAX(ordering)') ->from($db->quoteName('#__guidedtours')); $db->setQuery($query); $max = $db->loadResult(); $table->ordering = $max + 1; } } else { // Set the values $table->modified = $date; $table->modified_by = $this->getCurrentUser()->id; } } /** * Abstract method for getting the form from the model. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return \JForm|boolean A JForm object on success, false on failure * * @since 4.3.0 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm( 'com_guidedtours.tour', 'tour', [ 'control' => 'jform', 'load_data' => $loadData, ] ); if (empty($form)) { return false; } $id = $data['id'] ?? $form->getValue('id'); $item = $this->getItem($id); // Modify the form based on access controls. if (!$this->canEditState((object) $item)) { $form->setFieldAttribute('published', 'disabled', 'true'); $form->setFieldAttribute('published', 'required', 'false'); $form->setFieldAttribute('published', 'filter', 'unset'); } $currentDate = Factory::getDate()->toSql(); $form->setFieldAttribute('created', 'default', $currentDate); $form->setFieldAttribute('modified', 'default', $currentDate); return $form; } /** * Method to get the data that should be injected in the form. * * @return mixed The data for the form. * * @since 4.3.0 */ protected function loadFormData() { // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState( 'com_guidedtours.edit.tour.data', [] ); if (empty($data)) { $data = $this->getItem(); } return $data; } /** * Method to get a single record. * * @param integer $pk The id of the primary key. * * @return CMSObject|boolean Object on success, false on failure. * * @since 4.3.0 */ public function getItem($pk = null) { Factory::getLanguage()->load('com_guidedtours.sys', JPATH_ADMINISTRATOR); $result = parent::getItem($pk); if (!empty($result->id)) { $result->title_translation = Text::_($result->title); $result->description_translation = Text::_($result->description); } return $result; } /** * Delete all steps if a tour is deleted * * @param object $pks The primary key related to the tours. * * @return boolean * * @since 4.3.0 */ public function delete(&$pks) { $pks = ArrayHelper::toInteger((array) $pks); $table = $this->getTable(); // Include the plugins for the delete events. PluginHelper::importPlugin($this->events_map['delete']); // Iterate the items to delete each one. foreach ($pks as $i => $pk) { if ($table->load($pk)) { if ($this->canDelete($table)) { $context = $this->option . '.' . $this->name; // Trigger the before delete event. $result = Factory::getApplication()->triggerEvent($this->event_before_delete, [$context, $table]); if (\in_array(false, $result, true)) { $this->setError($table->getError()); return false; } $tourId = $table->id; if (!$table->delete($pk)) { $this->setError($table->getError()); return false; } // Delete of the tour has been successful, now delete the steps $db = $this->getDatabase(); $query = $db->getQuery(true) ->delete($db->quoteName('#__guidedtour_steps')) ->where($db->quoteName('tour_id') . '=' . $tourId); $db->setQuery($query); $db->execute(); // Trigger the after event. Factory::getApplication()->triggerEvent($this->event_after_delete, [$context, $table]); } else { // Prune items that you can't change. unset($pks[$i]); $error = $this->getError(); if ($error) { Log::add($error, Log::WARNING, 'jerror'); return false; } else { Log::add(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), Log::WARNING, 'jerror'); return false; } } } else { $this->setError($table->getError()); return false; } } // Clear the component's cache $this->cleanCache(); return true; } /** * Duplicate all steps if a tour is duplicated * * @param object $pks The primary key related to the tours. * * @return boolean * * @since 4.3.0 */ public function duplicate(&$pks) { $user = $this->getCurrentUser(); $db = $this->getDatabase(); // Access checks. if (!$user->authorise('core.create', 'com_guidedtours')) { throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); } $table = $this->getTable(); $date = Factory::getDate()->toSql(); foreach ($pks as $pk) { if ($table->load($pk, true)) { // Reset the id to create a new record. $table->id = 0; $table->published = 0; if (!$table->check() || !$table->store()) { throw new \Exception($table->getError()); } $pk = (int) $pk; $query = $db->getQuery(true) ->select( $db->quoteName( [ 'title', 'description', 'ordering', 'position', 'target', 'type', 'interactive_type', 'url', 'created', 'modified', 'checked_out_time', 'checked_out', 'language', 'note', ] ) ) ->from($db->quoteName('#__guidedtour_steps')) ->where($db->quoteName('tour_id') . ' = :id') ->bind(':id', $pk, ParameterType::INTEGER); $db->setQuery($query); $rows = $db->loadObjectList(); if ($rows) { $query = $db->getQuery(true) ->insert($db->quoteName('#__guidedtour_steps')) ->columns( [ $db->quoteName('tour_id'), $db->quoteName('title'), $db->quoteName('description'), $db->quoteName('ordering'), $db->quoteName('position'), $db->quoteName('target'), $db->quoteName('type'), $db->quoteName('interactive_type'), $db->quoteName('url'), $db->quoteName('created'), $db->quoteName('created_by'), $db->quoteName('modified'), $db->quoteName('modified_by'), $db->quoteName('language'), $db->quoteName('note'), ] ); foreach ($rows as $step) { $dataTypes = [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER, ParameterType::STRING, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ]; $query->values( implode( ',', $query->bindArray( [ $table->id, $step->title, $step->description, $step->ordering, $step->position, $step->target, $step->type, $step->interactive_type, $step->url, $date, $user->id, $date, $user->id, $step->language, $step->note, ], $dataTypes ) ) ); } $db->setQuery($query); try { $db->execute(); } catch (\RuntimeException $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); return false; } } } else { throw new \Exception($table->getError()); } } // Clear tours cache $this->cleanCache(); return true; } /** * Sets a tour's steps language * * @param int $id Id of a tour * @param string $language The language to apply to the steps belong the tour * * @return boolean * * @since 4.3.0 */ protected function setStepsLanguage(int $id, string $language = '*'): bool { if ($id <= 0) { return false; } $db = $this->getDatabase(); $query = $db->getQuery(true) ->update($db->quoteName('#__guidedtour_steps')) ->set($db->quoteName('language') . ' = :language') ->where($db->quoteName('tour_id') . ' = :tourId') ->bind(':language', $language) ->bind(':tourId', $id, ParameterType::INTEGER); return $db->setQuery($query) ->execute(); } } src/Model/ToursModel.php 0000644 00000020701 15172634556 0011217 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\ListModel; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for Tours * * @since 4.3.0 */ class ToursModel extends ListModel { /** * Constructor. * * @param array $config An optional associative array of configuration settings. * * @see JController * @since 4.3.0 */ public function __construct($config = []) { if (empty($config['filter_fields'])) { $config['filter_fields'] = [ 'id', 'a.id', 'title', 'a.title', 'access', 'a.access', 'access_level', 'description', 'a.description', 'published', 'a.published', 'language', 'a.language', 'ordering', 'a.ordering', 'extensions', 'a.extensions', 'created_by', 'a.created_by', 'modified', 'a.modified', 'modified_by', 'a.modified_by', 'note', 'a.note', ]; } parent::__construct($config); } /** * Method to auto-populate the model state. * * This method should only be called once per instantiation and is designed * to be called on the first call to the getState() method unless the model * configuration flag to ignore the request is set. * * 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 4.3.0 */ protected function populateState($ordering = 'a.ordering', $direction = 'ASC') { $app = Factory::getApplication(); $extension = $app->getUserStateFromRequest($this->context . '.filter.extension', 'extension', null, 'cmd'); $this->setState('filter.extension', $extension); parent::populateState($ordering, $direction); } /** * Get the filter form * * @param array $data data * @param boolean $loadData load current data * * @return \JForm|false the JForm object or false * * @since 4.3.0 */ public function getFilterForm($data = [], $loadData = true) { $form = parent::getFilterForm($data, $loadData); if ($form) { $form->setValue('extension', null, $this->getState('filter.extension')); } return $form; } /** * Method to get the data that should be injected in the form. * * @return string The query to database. * * @since 4.3.0 */ public 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.*' ) ); $subQuery = $db->getQuery(true) ->select('COUNT(' . $db->quoteName('s.id') . ')') ->from($db->quoteName('#__guidedtour_steps', 's')) ->where( [ $db->quoteName('s.tour_id') . ' = ' . $db->quoteName('a.id'), $db->quoteName('s.published') . ' = 1', ] ); $query->select('(' . $subQuery . ') AS ' . $db->quoteName('steps_count')) ->from($db->quoteName('#__guidedtours', 'a')); // Join with user table $query->select( [ $db->quoteName('uc.name', 'editor'), ] ) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')); // Join with language table $query->select( [ $db->quoteName('l.title', 'language_title'), $db->quoteName('l.image', 'language_image'), ] ) ->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')); // Join access table $query->select( [ $db->quoteName('ag.title', 'access_level'), ] ) ->join('LEFT', $db->quoteName('#__viewlevels', 'ag'), $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access')); // Filter by extension if ($extension = $this->getState('filter.extension')) { $extension = '%' . $extension . '%'; $all = '%*%'; $query->where( '(' . $db->quoteName('a.extensions') . ' LIKE :all OR ' . $db->quoteName('a.extensions') . ' LIKE :extensions)' ) ->bind([':all'], $all) ->bind([':extensions'], $extension); } $status = (string) $this->getState('filter.published'); // Filter by status if (is_numeric($status)) { $status = (int) $status; $query->where($db->quoteName('a.published') . ' = :published') ->bind(':published', $status, ParameterType::INTEGER); } elseif ($status === '') { $query->where($db->quoteName('a.published') . ' IN (0, 1)'); } // Filter by access level. $access = $this->getState('filter.access'); if (is_numeric($access)) { $access = (int) $access; $query->where($db->quoteName('a.access') . ' = :access') ->bind(':access', $access, ParameterType::INTEGER); } elseif (is_array($access)) { $access = ArrayHelper::toInteger($access); $query->whereIn($db->quoteName('a.access'), $access); } // Filter on the language, or all. if ($language = $this->getState('filter.language')) { $language = (array) $language; $query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING); } // Filter by search in title. $search = $this->getState('filter.search'); if (!empty($search)) { if (stripos($search, 'id:') === 0) { $search = (int) substr($search, 3); $query->where($db->quoteName('a.id') . ' = :search') ->bind(':search', $search, ParameterType::INTEGER); } elseif (stripos($search, 'description:') === 0) { $search = '%' . substr($search, 12) . '%'; $query->where('(' . $db->quoteName('a.description') . ' LIKE :search1)') ->bind([':search1'], $search); } else { $search = '%' . str_replace(' ', '%', trim($search)) . '%'; $query->where( '(' . $db->quoteName('a.title') . ' LIKE :search1' . ' OR ' . $db->quoteName('a.description') . ' LIKE :search2' . ' OR ' . $db->quoteName('a.note') . ' LIKE :search3)' ) ->bind([':search1', ':search2', ':search3'], $search); } } // Add the list ordering clause. $orderCol = $this->state->get('list.ordering', 'a.ordering'); $orderDirn = strtoupper($this->state->get('list.direction', 'ASC')); $query->order($db->escape($orderCol) . ' ' . ($orderDirn === 'DESC' ? 'DESC' : 'ASC')); return $query; } /** * Method to get an array of data items. * * @return mixed An array of data items on success, false on failure. * * @since 4.3.0 */ public function getItems() { $items = parent::getItems(); Factory::getLanguage()->load('com_guidedtours.sys', JPATH_ADMINISTRATOR); foreach ($items as $item) { $item->title = Text::_($item->title); $item->description = Text::_($item->description); $item->extensions = (new Registry($item->extensions))->toArray(); } return $items; } } src/Model/StepModel.php 0000644 00000016557 15172634556 0011034 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\CMS\Object\CMSObject; use Joomla\CMS\Table\Table; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Item Model for a single tour. * * @since 4.3.0 */ class StepModel extends AdminModel { /** * The prefix to use with controller messages. * * @var string * @since 4.3.0 */ protected $text_prefix = 'COM_GUIDEDTOURS'; /** * Type alias for content type * * @var string * @since 4.3.0 */ public $typeAlias = 'com_guidedtours.step'; /** * Method to test whether a record can be deleted. * * @param object $record A record object. * * @return boolean True if allowed to delete the record. Defaults to the permission for the component. * * @since 4.3.0 */ protected function canDelete($record) { if (empty($record->id) || $record->published != -2) { return false; } return parent::canDelete($record); } /** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success. * * @since 4.3.0 */ public function save($data) { $table = $this->getTable(); $input = Factory::getApplication()->getInput(); $tour = $this->getTable('Tour'); $tour->load($data['tour_id']); // Language keys must include GUIDEDTOUR to prevent save issues if (strpos($data['description'], 'GUIDEDTOUR') !== false) { $data['description'] = strip_tags($data['description']); } // Make sure we use the correct extension when editing an existing tour $key = $table->getKeyName(); $pk = isset($data[$key]) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); if ($pk > 0) { $table->load($pk); if ((int) $table->tour_id) { $data['tour_id'] = (int) $table->tour_id; } } if ($input->get('task') == 'save2copy') { $origTable = clone $this->getTable(); $origTable->load($input->getInt('id')); $data['published'] = 0; } return parent::save($data); } /** * Prepare and sanitise the table prior to saving. * * @param \Joomla\CMS\Table\Table $table The Table object * * @return void * * @since 4.3.0 */ protected function prepareTable($table) { $date = Factory::getDate()->toSql(); $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); if (empty($table->id)) { // Set the values $table->created = $date; // Set ordering to the last item if not set if (empty($table->ordering)) { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('MAX(ordering)') ->from($db->quoteName('#__guidedtour_steps')); $db->setQuery($query); $max = $db->loadResult(); $table->ordering = $max + 1; } } else { // Set the values $table->modified = $date; $table->modified_by = $this->getCurrentUser()->id; } } /** * Method to get a table object, load it if necessary. * * @param string $type The table name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config Configuration array for model. Optional. * * @return Table A Table object * * @since 4.3.0 * @throws \Exception */ public function getTable($type = 'Step', $prefix = 'Administrator', $config = []) { return parent::getTable($type, $prefix, $config); } /** * Abstract method for getting the form from the model. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return \JForm|boolean A JForm object on success, false on failure * * @since 4.3.0 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm( 'com_guidedtours.step', 'step', [ 'control' => 'jform', 'load_data' => $loadData, ] ); if (empty($form)) { return false; } $id = $data['id'] ?? $form->getValue('id'); $item = $this->getItem($id); // Modify the form based on access controls. if (!$this->canEditState((object) $item)) { $form->setFieldAttribute('published', 'disabled', 'true'); $form->setFieldAttribute('published', 'required', 'false'); $form->setFieldAttribute('published', 'filter', 'unset'); } // Disables language field selection $form->setFieldAttribute('language', 'readonly', 'true'); return $form; } /** * Method to get the data that should be injected in the form. * * @return mixed The data for the form. * * @since 4.3.0 */ protected function loadFormData() { // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState( 'com_guidedtours.edit.step.data', [] ); if (empty($data)) { $data = $this->getItem(); } return $data; } /** * Method to get a single record. * * @param integer $pk The id of the primary key. * * @return CMSObject|boolean Object on success, false on failure. * * @since 4.3.0 */ public function getItem($pk = null) { Factory::getLanguage()->load('com_guidedtours.sys', JPATH_ADMINISTRATOR); if ($result = parent::getItem($pk)) { if (!empty($result->id)) { $result->title_translation = Text::_($result->title); $result->description_translation = Text::_($result->description); } else { $app = Factory::getApplication(); $tourId = $app->getUserState('com_guidedtours.tour_id'); /** @var \Joomla\Component\Guidedtours\Administrator\Model\TourModel $tourModel */ $tourModel = $app->bootComponent('com_guidedtours') ->getMVCFactory()->createModel('Tour', 'Administrator', ['ignore_request' => true]); $tour = $tourModel->getItem($tourId); $tourLanguage = !empty($tour->language) ? $tour->language : '*'; // Sets step language to parent tour language $result->language = $tourLanguage; // Set the step's tour id $result->tour_id = $tourId; } } return $result; } } src/Extension/GuidedtoursComponent.php 0000644 00000006140 15172634556 0014220 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Extension; use Joomla\CMS\Extension\BootableExtensionInterface; use Joomla\CMS\Extension\MVCComponent; use Joomla\CMS\HTML\HTMLRegistryAwareTrait; use Psr\Container\ContainerInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Component class for com_guidedtours * * @since 4.3.0 */ class GuidedtoursComponent extends MVCComponent implements BootableExtensionInterface { use HTMLRegistryAwareTrait; /** * The step type * * @since 4.3.0 */ public const STEP_TYPE_NAMES = [ self::STEP_NEXT => 'COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_NEXT', self::STEP_REDIRECT => 'COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_REDIRECT', self::STEP_INTERACTIVE => 'COM_GUIDEDTOURS_FIELD_VALUE_STEP_TYPE_INTERACTIVE', ]; /** * A regular step. * * @since 4.3.0 */ public const STEP_NEXT = 0; /** * A step that redirects to another page. * * @since 4.3.0 */ public const STEP_REDIRECT = 1; /** * A step that allows interactions from the user. * * @since 4.3.0 */ public const STEP_INTERACTIVE = 2; /** * The step interactive type names * * @since 4.3.0 */ public const STEP_INTERACTIVETYPE_NAMES = [ self::STEP_INTERACTIVETYPE_FORM_SUBMIT => 'COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_FORM_SUBMIT', self::STEP_INTERACTIVETYPE_TEXT => 'COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_TEXT_FIELD', self::STEP_INTERACTIVETYPE_BUTTON => 'COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_BUTTON', self::STEP_INTERACTIVETYPE_OTHER => 'COM_GUIDEDTOURS_FIELD_VALUE_INTERACTIVESTEP_TYPE_OTHER', ]; /** * An interactive step where a user clicks on a form button. * * @since 4.3.0 */ public const STEP_INTERACTIVETYPE_FORM_SUBMIT = 1; /** * An interactive step where a user enters text. * * @since 4.3.0 */ public const STEP_INTERACTIVETYPE_TEXT = 2; /** * An interactive step where a user clicks on a button. * * @since 4.3.0 */ public const STEP_INTERACTIVETYPE_BUTTON = 4; /** * An interactive step for other fields. * * @since 4.3.0 */ public const STEP_INTERACTIVETYPE_OTHER = 3; /** * 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.3.0 */ public function boot(ContainerInterface $container) { } } src/Table/TourTable.php 0000644 00000004553 15172634556 0011021 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Table; use Joomla\CMS\Factory; use Joomla\CMS\Table\Table; use Joomla\Database\DatabaseDriver; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Tours table class. * * @since 4.3.0 */ class TourTable extends Table { /** * Indicates that columns fully support the NULL value in the database * * @var boolean * @since 4.3.0 */ protected $_supportNullValue = true; /** * An array of key names to be json encoded in the bind function * * @var array * @since 4.3.0 */ protected $_jsonEncode = ['extensions']; /** * Constructor * * @param DatabaseDriver $db Database connector object * * @since 4.3.0 */ public function __construct(DatabaseDriver $db) { parent::__construct('#__guidedtours', 'id', $db); } /** * Stores a tour. * * @param boolean $updateNulls True to update extensions even if they are null. * * @return boolean True on success, false on failure. * * @since 4.3.0 */ public function store($updateNulls = true) { $date = Factory::getDate()->toSql(); $userId = Factory::getUser()->id; // Set created date if not set. if (!(int) $this->created) { $this->created = $date; } if ($this->id) { // Existing item $this->modified_by = $userId; $this->modified = $date; } else { // Field created_by field can be set by the user, so we don't touch it if it's set. if (empty($this->created_by)) { $this->created_by = $userId; } if (!(int) $this->modified) { $this->modified = $date; } if (empty($this->modified_by)) { $this->modified_by = $userId; } } if (empty($this->extensions)) { $this->extensions = ["*"]; } return parent::store($updateNulls); } } src/Table/StepTable.php 0000644 00000004131 15172634556 0010773 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Table; use Joomla\CMS\Factory; use Joomla\CMS\Table\Table; use Joomla\Database\DatabaseDriver; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Step table class. * * @since 4.3.0 */ class StepTable extends Table { /** * Indicates that columns fully support the NULL value in the database * * @var boolean * @since 4.3.0 */ protected $_supportNullValue = true; /** * Constructor * * @param DatabaseDriver $db Database connector object * * @since 4.3.0 */ public function __construct(DatabaseDriver $db) { parent::__construct('#__guidedtour_steps', 'id', $db); } /** * Stores a step. * * @param boolean $updateNulls True to update fields even if they are null. * * @return boolean True on success, false on failure. * * @since 4.3.0 */ public function store($updateNulls = true) { $date = Factory::getDate()->toSql(); $userId = Factory::getUser()->id; // Set created date if not set. if (!(int) $this->created) { $this->created = $date; } if ($this->id) { // Existing item $this->modified_by = $userId; $this->modified = $date; } else { // Field created_by field can be set by the user, so we don't touch it if it's set. if (empty($this->created_by)) { $this->created_by = $userId; } if (!(int) $this->modified) { $this->modified = $date; } if (empty($this->modified_by)) { $this->modified_by = $userId; } } return parent::store($updateNulls); } } tmpl/tours/emptystate.php 0000644 00000001532 15172634556 0011623 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\Layout\LayoutHelper; $displayData = [ 'textPrefix' => 'COM_GUIDEDTOURS_TOURS_LIST', 'formURL' => 'index.php?option=com_guidedtours&view=tours', 'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Help4.x:Guided_Tours', 'icon' => 'icon-map-signs', ]; $user = Factory::getApplication()->getIdentity(); if ($user->authorise('core.create', 'com_guidedtours')) { $displayData['createURL'] = 'index.php?option=com_guidedtours&task=tour.add'; } echo LayoutHelper::render('joomla.content.emptystate', $displayData); tmpl/tours/default.xml 0000644 00000000324 15172634556 0011057 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <metadata> <layout title="COM_GUIDEDTOURS_TOURS_VIEW_DEFAULT_TITLE"> <message> <![CDATA[COM_GUIDEDTOURS_TOURS_VIEW_DEFAULT_DESC]]> </message> </layout> </metadata> tmpl/tours/default.php 0000644 00000026360 15172634556 0011056 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\Helpers\StringHelper; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; use Joomla\Component\Guidedtours\Administrator\View\Tours\HtmlView; /** @var HtmlView $this */ /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect'); try { $app = Factory::getApplication(); } catch (Exception $e) { die('Failed to get app'); } $user = $app->getIdentity(); $userId = $user->get('id'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $saveOrder = $listOrder == 'a.ordering'; $section = null; $mode = false; $canEdit = $user->authorise('core.edit', 'com_guidedtours'); $canEditOwnTour = $user->authorise('core.edit.own', 'com_guidedtours'); $canEditStateTour = $user->authorise('core.edit.state', 'com_guidedtours'); $hasCheckinPermission = $user->authorise('core.manage', 'com_checkin'); if ($saveOrder && !empty($this->items)) { $saveOrderingUrl = 'index.php?option=com_guidedtours&task=tours.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } ?> <form action="<?php echo Route::_('index.php?option=com_guidedtours&view=tours'); ?>" method="post" name="adminForm" id="adminForm"> <div id="j-main-container" class="j-main-container"> <?php // Search tools bar echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?> <!-- If no tours --> <?php if (empty($this->items)) : ?> <!-- No tours --> <div class="alert alert-info"> <span class="icon-info-circle" aria-hidden="true"></span> <span class="visually-hidden"><?php echo Text::_('INFO'); ?></span> <?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?> </div> <?php endif; ?> <!-- If there are tours, we start with the table --> <?php if (!empty($this->items)) : ?> <!-- Tours table starts here --> <table class="table" id="toursList"> <caption class="visually-hidden"> <?php echo Text::_('COM_GUIDEDTOURS_GUIDEDTOURS_TABLE_CAPTION'); ?>, <span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>, <span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span> </caption> <!-- Tours table header --> <thead> <tr> <td class="w-1 text-center"> <?php echo HTMLHelper::_('grid.checkall'); ?> </td> <!-- Ordering?--> <th scope="col" class="w-3 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_( 'searchtools.sort', '', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-sort' ); ?> </th> <th scope="col" class="w-1 text-center"> <?php echo HTMLHelper::_( 'searchtools.sort', 'JSTATUS', 'a.published', $listDirn, $listOrder ); ?> </th> <th scope="col"> <?php echo Text::_('COM_GUIDEDTOURS_TITLE'); ?> </th> <th scope="col" class="d-none d-md-table-cell"> <?php echo Text::_('COM_GUIDEDTOURS_DESCRIPTION'); ?> </th> <th scope="col" class="w-10 text-center d-none d-md-table-cell"> <?php echo Text::_('COM_GUIDEDTOURS_STEPS'); ?> </th> <th scope="col" class="text-center w-10 d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ACCESS', 'a.access', $listDirn, $listOrder); ?> </th> <!-- Add language types if multi-language enabled --> <?php if (Multilanguage::isEnabled()) : ?> <th scope="col" class="text-center w-10 d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_LANGUAGE', 'a.language', $this->state->get('list.direction'), $this->state->get('list.ordering')); ?> </th> <?php endif; ?> <th scope="col" class="w-10 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_( 'searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder ); ?> </th> </tr> </thead> <!-- Table body begins --> <tbody <?php if ($saveOrder) : ?> class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>" data-nested="true" <?php endif; ?>> <?php foreach ($this->items as $i => $item) : $canEditOwn = $canEditOwnTour && $item->created_by == $userId; $canCheckin = $hasCheckinPermission || $item->checked_out == $userId || is_null($item->checked_out); $canChange = $canEditStateTour && $canCheckin; ?> <!-- Row begins --> <tr class="row<?php echo $i % 2; ?>" data-draggable-group="none"> <!-- Item Checkbox --> <td class="text-center"> <?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', $item->title); ?> </td> <!-- Draggable handle --> <td class="text-center d-none d-md-table-cell"> <?php $iconClass = ''; if (!$canChange) { $iconClass = ' inactive'; } elseif (!$saveOrder) { $iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED'); } ?> <span class="sortable-handler <?php echo $iconClass; ?>"> <span class="icon-ellipsis-v" aria-hidden="true"></span> </span> <?php if ($canChange && $saveOrder) : ?> <input type="text" class="hidden text-area-order" name="order[]" size="5" value="<?php echo $item->ordering; ?>"> <?php endif; ?> </td> <!-- Item State --> <td class="text-center"> <?php echo HTMLHelper::_( 'jgrid.published', $item->published, $i, 'tours.', $canChange ); ?> </td> <th scope="row" class="has-context"> <div> <?php if ($item->checked_out) : ?> <?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'tours.', $canCheckin); ?> <?php endif; ?> <?php if ($canEdit || $canEditOwn) : ?> <a href="<?php echo Route::_('index.php?option=com_guidedtours&task=tour.edit&id=' . $item->id); ?>" title="<?php echo Text::_('JACTION_EDIT'); ?> <?php echo $this->escape($item->title); ?>"> <?php echo $this->escape($item->title); ?> </a> <?php else : ?> <?php echo $this->escape($item->title); ?> <?php endif; ?> <?php if ($item->note) : ?> <div class="small break-word"> <?php echo Text::sprintf('JGLOBAL_LIST_NOTE', $this->escape($item->note)); ?> </div> <?php endif; ?> </div> </th> <td class="d-none d-md-table-cell"> <?php echo StringHelper::truncate($item->description, 200, true, false); ?> </td> <td class="text-center btns d-none d-md-table-cell itemnumber"> <a class="btn btn-info" href="index.php?option=com_guidedtours&view=steps&tour_id=<?php echo $item->id; ?>"> <?php echo $item->steps_count; ?> </a> </td> <!-- Adds access labels --> <td class="small text-center d-none d-md-table-cell"> <?php echo $this->escape($item->access_level); ?> </td> <?php if (Multilanguage::isEnabled()) : ?> <td class="text-center small d-none d-md-table-cell"> <?php echo LayoutHelper::render('joomla.content.language', $item); ?> </td> <?php endif; ?> <!-- Tour ID --> <td class="d-none d-md-table-cell text-center"> <?php echo (int) $item->id; ?> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php // Load the pagination. echo $this->pagination->getListFooter(); ?> <?php endif; ?> <input type="hidden" name="task" value=""> <input type="hidden" name="boxchecked" value="0"> <?php echo HTMLHelper::_('form.token'); ?> </div> </form> tmpl/steps/default.php 0000644 00000024206 15172634556 0011035 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\Helpers\StringHelper; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; use Joomla\Component\Guidedtours\Administrator\Extension\GuidedtoursComponent; use Joomla\Component\Guidedtours\Administrator\View\Steps\HtmlView; /** @var HtmlView $this */ /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect'); $user = Factory::getApplication()->getIdentity(); $userId = $user->get('id'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $saveOrder = $listOrder == 'a.ordering'; $section = null; $mode = false; $tourId = $this->state->get('filter.tour_id'); $canEdit = $user->authorise('core.edit', 'com_guidedtours'); $canEditOwnTour = $user->authorise('core.edit.own', 'com_guidedtours'); $canEditStateTour = $user->authorise('core.edit.state', 'com_guidedtours'); $hasCheckinPermission = $user->authorise('core.manage', 'com_checkin'); if ($saveOrder && !empty($this->items)) { $saveOrderingUrl = 'index.php?option=com_guidedtours&task=steps.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } ?> <form action="<?php echo Route::_('index.php?option=com_guidedtours&view=steps&tour_id=' . $tourId); ?>" method="post" name="adminForm" id="adminForm"> <div id="j-main-container" class="j-main-container"> <?php // Search tools bar echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?> <!-- If no steps --> <?php if (empty($this->items)) : ?> <!-- No steps --> <div class="alert alert-info"> <span class="icon-info-circle" aria-hidden="true"></span> <span class="visually-hidden"><?php echo Text::_('INFO'); ?></span> <?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?> </div> <?php endif; ?> <!-- If there are steps, we start with the table --> <?php if (!empty($this->items)) : ?> <!-- Steps table starts here --> <table class="table" id="stepsList"> <caption class="visually-hidden"> <?php echo Text::_('COM_GUIDEDTOURS_STEPS_TABLE_CAPTION'); ?>, <span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?></span>, <span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span> </caption> <!-- Steps table header --> <thead> <tr> <td class="w-1 text-center"> <?php echo HTMLHelper::_('grid.checkall'); ?> </td> <!-- Ordering?--> <th scope="col" class="w-3 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_( 'searchtools.sort', '', 'a.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-sort' ); ?> </th> <th scope="col" class="w-1 text-center"> <?php echo HTMLHelper::_( 'searchtools.sort', 'JSTATUS', 'a.published', $listDirn, $listOrder ); ?> </th> <th scope="col"> <?php echo Text::_('COM_GUIDEDTOURS_STEP_TITLE'); ?> </th> <th scope="col" class="d-none d-md-table-cell"> <?php echo Text::_('COM_GUIDEDTOURS_DESCRIPTION'); ?> </th> <th scope="col" class="d-none d-md-table-cell"> <?php echo HTMLHelper::_( 'searchtools.sort', 'COM_GUIDEDTOURS_STEP_TYPE', 'a.type', $listDirn, $listOrder ); ?> </th> <th scope="col" class="w-10 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_( 'searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder ); ?> </th> </tr> </thead> <!-- Table body begins --> <tbody <?php if ($saveOrder) : ?> class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>" data-nested="true" <?php endif; ?>> <?php foreach ($this->items as $i => $item) : $canEditOwn = $canEditOwnTour && $item->created_by == $userId; $canCheckin = $hasCheckinPermission || $item->checked_out == $userId || is_null($item->checked_out); $canChange = $canEditStateTour && $canCheckin; ?> <!-- Row begins --> <tr class="row<?php echo $i % 2; ?>" data-draggable-group="none"> <!-- Item Checkbox --> <td class="text-center"> <?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', $item->title); ?> </td> <!-- Draggable handle --> <td class="text-center d-none d-md-table-cell"> <?php $iconClass = ''; if (!$canChange) { $iconClass = ' inactive'; } elseif (!$saveOrder) { $iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED'); } ?> <span class="sortable-handler <?php echo $iconClass; ?>"> <span class="icon-ellipsis-v" aria-hidden="true"></span> </span> <?php if ($canChange && $saveOrder) : ?> <input type="text" class="hidden text-area-order" name="order[]" size="5" value="<?php echo $item->ordering; ?>"> <?php endif; ?> </td> <!-- Step State --> <td class="text-center"> <?php echo HTMLHelper::_( 'jgrid.published', $item->published, $i, 'steps.', $canChange ); ?> </td> <!-- Step name, edit link, and note --> <th scope="row"> <div> <?php if ($item->checked_out) : ?> <?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'steps.', $canCheckin); ?> <?php endif; ?> <?php if ($canEdit || $canEditOwn) : ?> <a href="<?php echo Route::_('index.php?option=com_guidedtours&task=step.edit&id=' . $item->id); ?> " title="<?php echo Text::_('JACTION_EDIT'); ?> <?php echo $this->escape($item->title); ?>"> <?php echo $this->escape($item->title); ?> </a> <?php else : ?> <?php echo $this->escape($item->title); ?> <?php endif; ?> <?php if ($item->note) : ?> <div class="small break-word"> <?php echo Text::sprintf('JGLOBAL_LIST_NOTE', $this->escape($item->note)); ?> </div> <?php endif; ?> </div> </th> <td class="d-none d-md-table-cell"> <?php echo StringHelper::truncate($item->description, 200, true, false); ?> </td> <!-- Step Type --> <td class="d-none d-md-table-cell"> <?php echo Text::_(GuidedtoursComponent::STEP_TYPE_NAMES[$item->type]) ?> </td> <!-- Step ID --> <td class="d-none d-md-table-cell text-center"> <?php echo (int) $item->id; ?> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php // Load the pagination echo $this->pagination->getListFooter(); ?> <?php endif; ?> <input type="hidden" name="task" value=""> <input type="hidden" name="boxchecked" value="0"> <?php echo HTMLHelper::_('form.token'); ?> </div> </form> tmpl/steps/emptystate.php 0000644 00000001534 15172634556 0011607 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\Layout\LayoutHelper; $displayData = [ 'textPrefix' => 'COM_GUIDEDTOURS_STEPS', 'formURL' => 'index.php?option=com_guidedtours&view=steps', 'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Help4.x:Guided_Tours:_Steps', 'icon' => 'icon-map-signs', ]; $user = Factory::getApplication()->getIdentity(); if ($user->authorise('core.create', 'com_guidedtours')) { $displayData['createURL'] = 'index.php?option=com_guidedtours&task=step.add'; } echo LayoutHelper::render('joomla.content.emptystate', $displayData); tmpl/tour/edit.php 0000644 00000007277 15172634556 0010202 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); $lang = $this->getLanguage()->getTag(); /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') ->useScript('form.validate'); ?> <form action="<?php echo Route::_('index.php?option=com_guidedtours&view=tour&layout=edit&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="guidedtours-form" class="form-validate"> <?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?> <?php if ($this->item->id != 0 && strpos($this->item->title, 'GUIDEDTOUR') !== false) : ?> <div class="row title-alias form-vertical mb-3"> <div class="col-12"> <?php $this->form->setFieldAttribute('title_translation', 'label', Text::sprintf('COM_GUIDEDTOURS_TITLE_TRANSLATION', $lang)); ?> <?php echo $this->form->renderField('title_translation'); ?> </div> </div> <?php endif; ?> <div class="main-card"> <?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'details', 'recall' => true, 'breakpoint' => 768]); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'details', empty($this->item->id) ? Text::_('COM_GUIDEDTOURS_NEW_TOUR') : Text::_('COM_GUIDEDTOURS_EDIT_TOUR')); ?> <div class="row"> <div class="col-lg-9"> <?php echo $this->form->renderField('url'); ?> <?php echo $this->form->renderField('description'); ?> <?php if ($this->item->id != 0 && strpos($this->item->description, 'GUIDEDTOUR') !== false) : ?> <?php $this->form->setFieldAttribute('description_translation', 'label', Text::sprintf('COM_GUIDEDTOURS_DESCRIPTION_TRANSLATION', $lang)); ?> <?php echo $this->form->renderField('description_translation'); ?> <?php endif; ?> </div> <div class="col-lg-3"> <?php // Set main fields. $this->fields = [ 'published', 'access', 'language', 'extensions', 'note', ]; echo LayoutHelper::render('joomla.edit.global', $this); ?> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'publishing', Text::_('JGLOBAL_FIELDSET_PUBLISHING')); ?> <div class="row"> <div class="col-12 col-lg-8"> <fieldset id="fieldset-publishingdata" class="options-form"> <legend><?php echo Text::_('JGLOBAL_FIELDSET_PUBLISHING'); ?></legend> <div> <?php $this->fields = []; echo LayoutHelper::render('joomla.edit.publishingdata', $this); ?> </div> </fieldset> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php echo HTMLHelper::_('uitab.endTabSet'); ?> </div> <input type="hidden" name="task" value=""> <?php echo HTMLHelper::_('form.token'); ?> </form> tmpl/step/edit.php 0000644 00000007707 15172634556 0010162 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\MVC\View\GenericDataException; /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') ->useScript('form.validate'); if (empty($this->item->tour_id)) { throw new GenericDataException("\nThe Tour id was not set!\n", 500); } $lang = $this->getLanguage()->getTag(); ?> <form action="<?php echo Route::_('index.php?option=com_guidedtours&view=step&layout=edit&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="guidedtour-dates-form" class="form-validate"> <?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?> <?php if ($this->item->id != 0 && strpos($this->item->title, 'GUIDEDTOUR') !== false) : ?> <div class="row title-alias form-vertical mb-3"> <div class="col-12"> <?php $this->form->setFieldAttribute('title_translation', 'label', Text::sprintf('COM_GUIDEDTOURS_STEP_TITLE_TRANSLATION', $lang)); ?> <?php echo $this->form->renderField('title_translation'); ?> </div> </div> <?php endif; ?> <div class="main-card"> <?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'details', 'recall' => true, 'breakpoint' => 768]); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'details', empty($this->item->id) ? Text::_('COM_GUIDEDTOURS_STEP_NEW_STEP') : Text::_('COM_GUIDEDTOURS_STEP_EDIT_STEP')); ?> <div class="row"> <div class="col-lg-9"> <?php echo $this->form->renderField('description'); ?> <?php if ($this->item->id != 0 && strpos($this->item->description, 'GUIDEDTOUR') !== false) : ?> <?php $this->form->setFieldAttribute('description_translation', 'label', Text::sprintf('COM_GUIDEDTOURS_STEP_DESCRIPTION_TRANSLATION', $lang)); ?> <?php echo $this->form->renderField('description_translation'); ?> <?php endif; ?> </div> <div class="col-lg-3"> <?php // Set main fields. $this->fields = [ 'published', 'language', 'position', 'target', 'type', 'url', 'interactive_type', 'note', ]; $this->hidden_fields = [ 'tour_id', ]; echo LayoutHelper::render('joomla.edit.global', $this); ?> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'publishing', Text::_('JGLOBAL_FIELDSET_PUBLISHING')); ?> <div class="row"> <div class="col-12 col-lg-8"> <fieldset id="fieldset-publishingdata" class="options-form"> <legend><?php echo Text::_('JGLOBAL_FIELDSET_PUBLISHING'); ?></legend> <div> <?php $this->fields = []; $this->hidden_fields = []; echo LayoutHelper::render('joomla.edit.publishingdata', $this); ?> </div> </fieldset> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php echo HTMLHelper::_('uitab.endTabSet'); ?> </div> <input type="hidden" name="task" value=""> <?php echo $this->form->getInput('tour_id'); ?> <?php echo HTMLHelper::_('form.token'); ?> </form>
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings