ExtJs для новичков. Админка загрузилась. ч.2

В первой части познакомились с методом Ext.getCmp() для работы с компонентами ExtJs. Он позволяет взаимодействовать с виджетами 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.

На этом со статьями по ExtJs всё. Судя по предыдущей заметке особого интереса эта тема не вызвала. Надеюсь, кому-нибудь это поможет в начинании.
Сергей Шлоков
02 ноября 2015, 15:06
modx.pro
25
4 797
+10
Поблагодарить автора Отправить деньги

Комментарии: 19

Павел Гвоздь
02 ноября 2015, 18:52
+1
Очень зря, Сергей. Не знаю, как кому, но мне было очень интересно!
    Илья Уткин
    02 ноября 2015, 19:19
    +2
    Да, интереса сейчас мало. Вот позже, когда у людей появится необходимость разобраться, они через Яндекс или Google найдут эти статьи, в комментариях начнутся и вопросы, и благодарности)

    Мне, например, интересно, я про этот ExtJS все еще как про магию думаю)
      Максим Кузнецов
      02 ноября 2015, 20:26
      0
      Аналогично..)

      Может, стоит дублировать такие статьи напрямую в docs.modx.pro?
        Сергей Шлоков
        02 ноября 2015, 22:36
        +7
        Честно говоря, мои статьи рассчитаны на новичков MODX. Но уж если такого уровня людям интересно, готов продолжить.
        П.С. Дело не в благодарностях. Просто я поддерживаю хорошую традицию, начатую Василием, делится опытом. Пусть этот опыт пока не большой, но все же может кому-то пригодится. А если это не интересно никому, то какой смысл тратить время.
        Мою степень знаний ExtJs можно отследить по моим дополнениям. Начинал с elementNote, а сейчас дошел до adminTools с панелью задач, чтобы можно было переключаться между окнами. Мне пока самому интересно. :)
          Илья Уткин
          02 ноября 2015, 23:08
          +3
            Виталий Батушев
            03 ноября 2015, 04:08
            0
            ДелитЬся опытом :)
            А в остальном просто замечательно, как и Илья, смотрю пока на ExtJS как чудо, хоть и не новичок в MODX. Продолжай обязательно!
              Сергей Шлоков
              04 ноября 2015, 11:19
              0
              как НА чудо :)
              Странно, что ни одного вопроса нет.
                Виталий Батушев
                04 ноября 2015, 12:09
                0
                Гы, 1:1 :)
                Вопросы будут, но позже. У меня основная работа теперь связана теперь немного с другим.
                  Николай
                  04 ноября 2015, 12:50
                  0
                  Странно, что ни одного вопроса нет.
                  Потому-что на изучение время нужно, а время надо выбрать, чтобы заняться вплотную, тем более тема довольно обширная. Вот тогда и вопросы появятся :)
            Андрей
            03 ноября 2015, 12:14
            0
            По ExtJs для Modx весьма мало материалов. Есть конечно офф документация sencha но интересна именно свзязка с Modx. Поэтому хотелось бы чтобы серия статей не умерла.
            Сергей Шлоков
            03 ноября 2015, 12:17
            +2
            Добавил упражнение 2.
              Андрей Копп
              09 ноября 2015, 00:19
              0
              Начну с вопроса) Как сделать свою вкладку около вкладок Ресурсы, Элементы, Файлы и в ней выводить в древовидной форме записи из таблицы компонента?)
                Сергей Шлоков
                09 ноября 2015, 09:44
                +3
                Все компоненты ExtJs выводятся в контейнерах. Основные контейнеры — это панели и окна. В данном случае, контейнер с вкладками Ресурсы, Элементы, Файлы — это tabPanel. Если посмотреть исходный код, то можно увидеть, что у этого контейнера есть id — 'modx-leftbar-tabpanel'. Получая компонент через метод Ext.getCmp(), можно использовать все его методы, в том числе и add(), который добавляет дочерние элементы — табы. Но можно воспользоваться альтернативным способом. В MODX есть метод addTab(), который также добавляет вкладку указанной панели.
                MODx.addTab('modx-leftbar-tabpanel',{
                	id: "id нового таба",
                	title: "Заголовок таба",
                	items: [{
                		xtype: "x-type элемента, который будет показан на вкладке (в данном случае это дерево)"
                		//, другие параметры 
                	}]
                })
                П.С. Начинать изучать ExtJs с дерева — не очень хорошая идея. Это сложный компонент. Лучше начинать разбираться с чего-то попроще.
                В ближайшее время выйдет статья, где поподробнее поговорим о компонентах ExtJs.
                  Павел Гвоздь
                  09 ноября 2015, 10:30
                  0
                  Жду статью, Сергей. Побольше бы информации об ExtJS, побольше. :)
                Андрей
                27 декабря 2017, 12:01
                0
                А как подключить к окну редактирования ресурса таб с функционалом своего компонента? Как только указываю не родной xtype выдает ошибку:
                TypeError: b[(intermediate value)] is not a constructor
                При этом в плагине подкобчил файлы:
                $modx->controller->addJavascript($modx->modCOM->config['jsUrl'] . 'mgr/modcom.js');
                        $modx->controller->addJavascript($modx->modCOM->config['jsUrl'] . 'mgr/widgets/items.grid.js');
                        $modx->controller->addLastJavascript($modx->modCOM->config['jsUrl'] . 'mgr/tab.js');
                        $modx->controller->addHtml('<script type="text/javascript">modCOM.config = ' . $modx->toJSON($modx->modCOM->config) . ';</script>');
                  Сергей Шлоков
                  27 декабря 2017, 15:47
                  0
                  Вот пример из AdminTools.
                    Андрей
                    27 декабря 2017, 17:52
                    0
                    Сергей, а можно суть подробнее рассказать. Сам таб я создаю, кнопки, поля и т.д. в нем также могу сделать, но все это получается оторванным от самого компонента и не функциональным. Если же я в плагине подключаю файл items.grid.js и задаю xtype modcom-grid-items (тот, что на странице компонента выводит табличку), то все перестает работать.
                    Может мне нужно сам компонент инициализировать как-то?
                  Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                  19