Как сделать элемент для Zoo/JBZoo? — Дополнительные возможности

10.0/10 оценка (4 голосов)

Используем Ajax в элементе

Часто бывают задачи, где Ajax просто необходим. К счастью, добавить динамичность в наш элемент не составит большого труда.

Нам необходимо будет выполнить несколько действий:

  1. Зарегистрировать экшен в конструкторе элемента, иначе он не выполнится.

  2. Создать метод с именем аналогичным названию экшена и добавить принимаемые аргументы.

  public function __construct()
    {
        parent::__construct();
        $this->registerCallback('myFirstAjax');
    }

Добавляем метод в наш элемент.

 // Нам нужно знать количество передаваемых параметров, чтобы их принять.
    public function myFirstAjax($param1, $param2, $param3)
    {
        // Получаем текст по умолчанию из настроек элемента.
        $default = $this->config->get('ajax', 'default text');
                return $this->app->jbajax->send(array(
                'default'    => $default,
                'param1'  => $param1,
                'param2'  => $param2,
                'param3'  => $param3,
            )
        );
    }

Сформировать правильную ссылку для POST запроса на элемент нам поможет хелпер JBAjax и его метод element.

$url = $this->app->jbrouter->element($this->identifier, $this->getItem()->id, 'myFirstAjax');

Если мы хотим добавить дополнительные параметры, нам нужно подготовить массив args перед отправкой запроса. К примеру, это можно сделать в js.

<script type="text/javascript">
    jQuery(document).ready(function () {
        jQuery('.css селектор').on('click', function(){
           // Наш массив дополнительных параметров
            var data = new Array('1',  '2', '3');
            jQuery.ajax({
                type: 'POST',
                data: 'args=' + data,
                url: '<?php echo $url; ?>',
                success: function(html){
                    console.log(html.param1);
                    console.log(html.param2);
                    console.log(html.param3);
                    console.log(html.default);
                }
            });
        });
    });
</script>

Или с помощью php в метод send передать четвертым аргументом массив.

$data = array('1', '2', '3');
$url    = $this->app->jbrouter->element($this->identifier, $this->getItem()->id, 'myFirstAjax', $data);

Отдать ответ в виде JSON можно с помощью метода send в хелпере JBAjax. Все, что нам нужно — указать ключ и его значение, как мы это сделали в примере выше. Дальше нам остается в js скрипте принять результат и обработать его.

Импорт/Экспорт в пользовательском элементе

Элемент создан. Можем его использовать при подаче материалов, а также делать его повторяемым. Но как же быть с импортом, если нам надо наполнить свой сайт товарами?

К счастью, это так же предусмотрено разработчиками JBZoo. Файл элемента необходимо разместить в папке:

/media/zoo/applications/jbuniversal/framework/elements/user/.

Название файла соответствует имени элемента.

Создаем файл jbint.php

Название класса должно содержать префикс JBCSVItemUser и постфикс (имя нашего элемента) JBInt. Наследуется от класса JBCSVItem.

В нашем классе должны быть переопределены 2 метода:

  • toCSV — метод, используемый при экспорте.
  • fromCSV — метод, используемый при импорте.

У родительского класса определены две константы:

  • JBCSVItem::SEP_ROWS — для разделения повторяемых полей.
  • JBCSVItem::SEP_CELL — для разделения разных данных внутри одного элемента.
class JBCSVItemUserJBlist extends JBCSVItem 
{
    public function toCSV()
    {
        $result = array();
        $params = $this->app->jbuser->getParam('export-items', array());
        if (!empty($this->_value)) {
            foreach($this->_value as $jbint) {
                $result[] = $jbint['number'];
            }
        }
        // Объединять повторяемые поля?
        if ((int)$params->merge_repeatable) {
            return implode(JBCSVItem::SEP_ROWS, $result);
        } else {
            return $result;
        }
    }
   
     public function fromCSV()
    {
        $data = ($position == 1) ? array() : $this->_element->data();
        if (strpos($value, JBCSVItem::SEP_ROWS)) {
            foreach (explode(JBCSVItem::SEP_ROWS, $value) as $val) {
                $values[] = array(
                    'number'  => $val,
                );
            }
            $data = $values;
        } else {
            $data[] = array('number' => $value);
        }
        $this->_element->bindData($data);
        return $this->_item;
    }
}

Фильтр

Чтобы у нашего элемента появились настройки для фильтра, нам необходимо создать xml файл и наполнить его.

По примеру создания настроек в фильтре для нового элемента, мы создадим и новый шаблон с названием number. Он будет иметь уникальный тип инпута — number. Также будет возможность поиска по диапазону.

Добавление шаблона для нового элемента в фильтр состоит из двух этапов:

  1. Создание xml файла с названием нашего элемента.

  2. Написание класса шаблона.

XML файл с именем нашего элемента надо создать по пути:

/media/zoo/applications/jbuniversal/config/mod_jbzoo_search/jbint.xml.

Имя нашего файла-шаблона соответствует имени опции в параметре — jbzoo_filter_render.

Добавим в параметр новый шаблон

 <param name="jbzoo_filter_render"
               type="list"
               label="JBZOO_ELEMENT_TEMPLATE"
               description="JBZOO_ELEMENT_TEMPLATE_DESC"
               default="_auto_"
                >
            <option value="_auto_">JBZOO_ELEMENT_TEMPLATE_AUTO</option>
            <option value="text">JBZOO_ELEMENT_TEMPLATE_TEXT</option>
            <option value="text-range">JBZOO_ELEMENT_TEMPLATE_TEXT_RANGE</option>
            <option value="checkbox">JBZOO_ELEMENT_TEMPLATE_CHECKBOX</option>
            <option value="jqueryui">JBZOO_ELEMENT_TEMPLATE_JQUERYUI</option>
            <option value="radio">JBZOO_ELEMENT_TEMPLATE_RADIO</option>
            <option value="select">JBZOO_ELEMENT_TEMPLATE_SELECT</option>
            <option value="select-chosen">JBZOO_ELEMENT_TEMPLATE_SELECT_CHOSEN</option>
            <option value="slider">JBZOO_ELEMENT_TEMPLATE_SLIDER</option>
	<!-- Имя нового шаблона -->
            <option value="number">JBZOO_ELEMENT_TEMPLATE_NUMBER_RANGE</option>
	<!--  Имя нового шаблона -->
            <option value="hidden">JBZOO_ELEMENT_TEMPLATE_HIDDEN</option>
        </param>

Теперь от нас будет требоваться создать файл шаблона

/media/zoo/applications/jbuniversal/framework/render/filter/element.<АЛИАС_ОПЦИИ>.php.

Название класса должно начинаться с JBFilterElement и заканчиваться алиасом выбранной опции, наследоваться от класса JBFilterElement.

  • html — выводим наш класс.
  • _getName — изменяем имя input'ов, у нас их будет два.
  • _getAttrs — получаем атрибуты. Проверяем, стоит ли опция автодополнения, если стоит — подключаем скрипты.
  • _number — скелет нашего шаблона. В примере используется метод прямо с нашего класса. В практике JBZoo используется хелпер JBHtml.
class JBFilterElementNumber extends JBFilterElement 
{
    /**
     * Render HTML
     * @return string|null
     */
    public function html()
    {
        $html = array();
        $values = array('', '');
        if (isset($this->_value['range'])) {
            if (!is_array($this->_value['range'])) {
                $values = explode('/', $this->_value['range']);
            } else if (is_array($this->_value['range'])) {
                $values = $this->_value['range'];
            }
        }
        $html[] = '<label for="' . $this->_getId('1') . '">' . JText::_('JBZOO_FROM') . '</label>';
        $html[] = $this->_number(
            $this->_getName('0'),
            $values[0],
            $this->_attrs,
            $this->_getId('1')
        );
        $html[] = '<br />';
        $html[] = '<label for="' . $this->_getId('2') . '">' . JText::_('JBZOO_TO') . '</label>';
        $html[] = $this->_number(
            $this->_getName('1'),
            $values[1],
            $this->_attrs,
            $this->_getId('2')
        );
        return implode("\n\r", $html);
    }
    /**
     * Get name
     * @param $postFix
     * @return string
     */
    protected function _getName($postFix = null)
    {
        return parent::_getName('range') . '[' . $postFix . ']';
    }
    /**
     *  Generates an HTML input type[number].
     * @param $name
     * @param null $value
     * @param null $attribs
     * @param null $idtag
     * @return string
     */
    protected function _number($name, $value = null, $attribs = null, $idtag = null)
    {
        if ($idtag && is_array($attribs)) {
            $attribs['id'] = $idtag;
        }
        $attribs = $this->app->jbhtml->buildAttrs($attribs);
        if (strpos($attribs, 'jsAutocomplete') !== false) {
            $this->app->jbassets->jqueryui();
            $this->app->jbassets->initAutocomplete();
        }
        return '<input type="number" name="'.$name.'" value="'.$value.'" '. $attribs.' />' ;
    }
    /**
     * Get main attrs
     * @param array $attrs
     * @return array
     */
    protected function _getAttrs(array $attrs)
    {
        $attrs = parent::_getAttrs($attrs);
        $attrs['maxlength'] = '255';
        $attrs['size']      = '60';
        if ((int)$this->_params->get('jbzoo_filter_autocomplete', 0)) {
            $attrs['class'][]     = 'jsAutocomplete';
            $attrs['placeholder'] = $this->_getPlaceholder();
        }
        return $attrs;
    }
}

Если вы столкнулись с каким-нибудь препятствием или что-то у вас не выходит, загляните в соседние файлы, возможно там вы найдете ответ.

Системные события в Zoo/JBZoo

Для чего нужны события? С помощью событий мы можем глобально влиять на составные Zoo/JBZoo — элементы, категории, материалы.

Разберем несколько событий, которые могут быть вызваны для элемента.

  • afterDisplay — вызывается после вывода.

  • beforeDisplay — вызывается перед выводом.

  • download — событие, которое вызывается перед загрузкой, пока что только для DownloadElement.

  • afterSubmissionDisplay — аналог afterDisplay только при подаче материала.

  • beforeSubmissionDisplay — аналог beforeDisplay только при подаче материала.

  • beforeEdit — событие происходит до редактирования.

Рассмотрим пример. Обернем все элементы в div с классом event. Тут нам поможет событие afterDisplay — в нем можно получить содержимое элемента.

 /**
     * On after element display
     * @param $event
     */
    public static function afterDisplay($event)
    {
        $params         = $event->getParameters();
        $params['html'] = '<div class="event">'.$params['html'].'</div>';
        $event->setReturnValue($params);
    }

Все события по элементу можно посмотреть в классе JBEventElement

/media/zoo/applications/jbuniversal/framework/events/jbevent.element.php.

API, Создание элемента

У меня остались вопросы, где я могу их задать?

Вы можете обратиться на наш специальный форум техподдержки JBZoo. Если у вас нет активного аккаунта со знаком «плюс» в тарифном плане, то вы можете задать свой вопрос в одном из этих разделов или на любой из наших контактов. Форум специально предназначен для JBZoo, приоритет и скорость ответа там выше.