• Блог
  • Объекты ExtJs в админке, ч.2

В первой части мы познакомились с методом Ext.getCmp(), который позволяет взаимодействовать с виджетами ExtJs — панелями, таблицами, формами, окнами, запрашивать и обрабатывать данные с сервера и т.д. Но иногда требуется просто поработать с обычными HTML элементами. А для этого метод Ext.getCmp() совсем не подходит. Можно, конечно, пользоваться обычным javascript. Но уж очень хочется иметь такой же удобный инструмент как jQuery. И ExtJs предоставляет нам такой функционал. Для работы с элементами DOM у него есть несколько методов.

Ext.get(el) — метод-обертка, возвращающий объект класа Ext.Element (элемент ExtJs), который инкапсулирует в себе и сам DOM элемент и методы для работы с ним. Очень похоже на jQuery с его $('div.class'). В качестве параметра передаются или id узла DOM, или сам узел или элемент ExtJs.

// Получаем элемент ExtJs из div с id="title"
var title = Ext.get('title');
// Обновляем текст
title.update('Новый заголовок');

Ext.select(selector) — возвращает коллекцию элементов ExtJs. Этот метод позволяет использовать селекторы CSS.

// Получаем все див узлы с классом "text" и скрываем их
var divs= Ext.select('div.text');
divs.hide();

Ext.query(selector) — возвращает массив HTML элементов. Этот метод позволяет использовать селекторы CSS. В отличие от Ext.select(), этот метод не создает объекты-обертки ExtJs для найденных элементов.

Ext.getDom(el) — также как и Ext.query() возвращает чистый узел DOM, но всего один. Параметр — id узла DOM, узел DOM или объект Ext.Element.

Подробную информацию по этим и другим методам можно посмотреть в официальной документации.

Упражнение 1

Для понимания принципов работы этих методов давайте попробуем поработать с главным меню, которое не является виджетом (компонентом) ExtJs. Поэтому для него нельзя использовать Ext.getCmp(). Вот его HTML структура

<ul id="modx-topnav">
    <li id="modx-home-dashboard">
    <li id="modx-site-info">
    <li id="modx-manager-search-icon">
    <li id="limenu-site" class="top">
    <li id="limenu-media" class="top">
    <li id="limenu-components" class="top">
    <li id="limenu-manage" class="top">
</ul>
Давайте сделаем так, чтобы пункты меню открывались и закрывались только по клику.

Создадим файл clickmenu.js.

// DOM построен
Ext.onReady(function () {
    // Получаем все li элементы главного меню 
    var menuli = Ext.select('#modx-topnav > li');
    // Скрываем все подменю, чтобы они не открывались на hover
    Ext.select('ul.modx-subnav').hide();
    // Закрываем открытое подменю (если есть) при клике на любое место
    Ext.get(document.body).on('click', function(e){
        var li = Ext.select('#modx-topnav > li.active');
        if (li.elements.length) {
            li.removeClass('active');
            // Скрываем подменю (ul), являющееся дочерним элементом li элемента
            li.el.child('ul').hide();
        }
    });
    // Каждому элементу главного меню навешиваем обработчик события клика
    Ext.each(menuli.elements, function(d,i){
        // Получаем элемент ExtJs для d узла DOM
        var li = Ext.get(l);
        li.on('click',function(){
            // Закрываем открытое подменю
            var active = Ext.select('#modx-topnav > li.active');
            // Массив active.elements содержит элементы DOM из предыдущего запроса (если есть)
            if (active.elements.length > 0) {
                active.removeClass('active');
                // Скрываем подменю (ul), являющееся дочерним элементом li элемента
                active.el.child('ul').hide();
            }
            // Если мы кликнули на уже открытом меню, то просто закрываем его. Если на другое
            //или нет других открытых меню, то открываем кликнутый пункт меню и прописываем класс.
            if (active.elements.length == 0 || active.elements.length && active.el.id != li.id) {
                var ul = li.child('ul');
                if (ul) {
                    li.addClass('active');
                    li.child('ul').show();
                }
            }
        },this, {stopPropagation: true})
    });
});

Тут мы используем CSS класс «active» для обозначения открытого подменю.

#modx-navbar li.active  ul.modx-subnav {
    opacity: 1 !important;
    visibility: visible !important;
}

Подключаем js файл и стиль в плагине

switch ($modx->event->name) {
    case 'OnManagerPageBeforeRender':
    $modx->controller->addHtml('<style type="text/css">#modx-navbar li.active  ul.modx-subnav {opacity: 1 !important;visibility: visible !important;} </style>');
    $modx->controller->addJavascript('/inc/clickmenu.js');
    break;
}

перезагружаем админку и вуаля. Всего несколько строчек кода и наше меню работает как мы ему приказали — по клику.

В этом примере использовались методы для работы с элементами DOM. Немного похоже на jQuery, правда? Можно было бы сделать тоже самое на javascript. Но получилось бы сложнее. А в ExtJs мы видим уже знакомые по jQuery методы — addClass(), show(), hide(), on().

Упражнение 2

В предыдущем упражнении мы использовали метод Ext.select(), который выбирал все записи документа с указанными параметрами. Но этот метод select() есть у всех элементов ExtJs. Что это дает? Это позволяет задавать ограничения поиска. Так мы можем выбрать всех потомков определенного контейнера. Давайте используем эту возможность в примере — скроем описание пунктов меню «Приложения», чтобы укоротить меню. Частая задача, когда компонентов слишком много. У остальных пунктов меню описание оставим.

Как мы видим, этот пункт меню имеет id=«limenu-components». А описания лежат в теге span.

// Получаем объект пункта меню компонентов
var liComponents = Ext.get('limenu-components');
// И у него ищем потомков - элементы span с описанием. И скрываем их.
// По-умолчанию, у элементов за отображение отвечает свойство visibility. А в этом случае, хоть элемент и  скрыт, 
// но место, где он расположен, остается. Поэтому нам нужно скрывать элемент через display: none.
// Вариант 1. Устанавливаем всем элементам метод отображения DISPLAY, а затем скрываем методом hide().
liComponents.select('span.description').setVisibilityMode(Ext.Element.DISPLAY).hide();
// Вариант 2. Просто меняем стиль display
liComponents.select('span.description').setStyle({display: 'none'});

Задача выполнена.

Другие методы, описанные выше, также могут быть использованы в элементах ExtJs.

Итог

ExtJs предлагает 2 вида методов для работы. Один — это работа с компонентами на уровнях Controller и View с точки зрения стандарта MCV. Второй — для работы с узлами DOM.

0   4091

Комментарии ()

  1. Tim Yusupov 23 января 2017 # 0
    Сергей, приветствую!
    На сайте реализован импорт ресурсов из xml ссылок, которые прописаны в категориях, в общей сложности по всем категориям собирается порядка 100 тыс. При добавлении/ обновлении ссылок, чтобы не запускать целиком весь импорт, который может затянуться на несколько часов, а то и суток, придумали следующее:

    Что если добавить виджет в панель управления MODX, в котором будут перечислены категории со ссылками, и чекбоксы (чтобы отметить нужные категории) После того, как отмечу все необходимые категории, нажимаю – ИМПОРТ, и запускается консольный импорт ресурсов из xml только отмеченных категорий. Причем всё в цикле (как, например, при запуске индексации mSearch2 из админки).

    Пытался найти что-то похожее на просторах интернета, и не нашел. Может не так искал.

    Так вот вопрос, с высоты вашего опыта, что можете посоветовать почитать или может подскажете, куда копать, чтобы реализовать подобное (а может и что-то более удобное сможете подсказать)

    Спасибо!:)
    1. Сергей Шлоков 23 января 2017 # 0
      Привет!
      В данном вопросе я совсем не помощник. Ни одного виджета в жизни не сделал и ни одного импорта/экспорта. По циклическому выполнению скрипта видел в сообществе инфу. Так что можно поискать. Из последнего вот. И тот же вариант mSearch2.
      Так что сорри, помочь нечем.

    Вы должны авторизоваться, чтобы оставлять комментарии.

    Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.