Наверх

Как работают дополнения MODX. Часть 2 — ExtJS Panel

Для того, чтобы добавить свои стили и скрипты на страницу дополнения, в классе modExtraManagerController есть метод loadCustomCssJs. Давайте, воспользуемся им, чтобы запустить наш первый ExtJS-скрипт.
<?php
class ThingsIndexManagerController extends modExtraManagerController {
    public function getPageTitle() {
        return 'Things';
    }
    public function getTemplateFile() {
        return dirname(__FILE__) . '/home.tpl';
    }
    public function loadCustomCssJs() {
        $this->addHtml("<script>
            Ext.onReady(function() {
                var title = 'Мой заголовок';
                var msg = 'Модель DOM готова...';
                Ext.MessageBox.alert(title,msg);
            });
        </script>");
    }
}

Пример кода я взял из статьи, найденной в Яндексе по запросу «Уроки ExtJS». Единственное — нам не надо подключать скрипты и стили самого ExtJS, так как за нас это уже сделал MODX.

Писать JavaScript внутри PHP — то ещё извращение, поэтому JS-скрипты лучше выносить в отдельные файлы и подключать с помощью addJavascript:
<?php
class ThingsIndexManagerController extends modExtraManagerController {
    public function getPageTitle() {
        return 'Things';
    }
    public function getTemplateFile() {
        return dirname(__FILE__) . '/home.tpl';
    }
    public function loadCustomCssJs() {
        $this->addJavascript('/things/home.js');
    }
}

Чтобы каждый раз не очищать кеш браузера, можно указать дополнительный параметр у файла. Не забудьте потом удалить его, когда закончите разработку:
$this->addJavascript('/things/home.js?time=' .time());

В ExtJS принят объектно-ориентированный подход. В JavaScript как такового ООП нет и каждый фреймворк реализует его по-своему. Если объяснить простыми словами, то всё в ExtJS является объектами: дерево ресурсов, панель редактирования ресурса, панель системных настроек. Даже любое поле или чекбокс — это объект. Каждый объект может находиться внутри другого объекта — для реализации вложенности у объектов ExtJS есть свойство items.

ExtJS items

Если у объекта есть родительский элемент, то объект будет размещён (или отрендерен) внутри этого родительского элемента. Но вы можете изменить это поведение, указав свойство renderTo — оно указывает, где отобразить конкретный объект. Обычно свойство renderTo указывается только у тех объектов, у которых нет родителя.

И ещё одно важное свойство — это xtype.

ExtJS xtype

В этом свойстве указывается тип объекта. По аналогии можно сказать, что xtype — это класс объекта. В зависимости от xtype у объекта могут быть дополнительные свойства, методы, может быть прописано какое-то поведение и даже набор дочерних объектов.

Вся работа с ExtJS обычно построена следующим образом:

  1. Ищем наиболее подходящий для задачи xtype. Для поиска можно воспользоваться документацией. Она на английском, но по названию объектов можно хотя бы сориентироваться. Например, если нам нужно отобразить какое-то окошко, идём в раздел Ext.Window и видим, что нужный нам xtype — это window: https://ilyaut.ru/cloud/1WpUHf.png

  2. Решаем, внутри какого объекта отобразить наш новый объект, вставляем его внутрь соответствующего свойства items

  3. Переопределяем те свойства и методы объекта, в которых мы хотим изменить поведение.

Давайте, уберём из контроллера метод getTemplateFile и отобразим заголовок с помощью ExtJS. Файл home.tpl тоже можно удалить, он нам больше не понадобится — всю HTML-структуру будет создавать ExtJS.

MODX создаёт DIV с id=«modx-panel-holder» на странице компонента. Вот в нём мы и будем создавать всю внутреннюю структуру. Вызов того или иного объекта осуществляется с помощью команды MODx.load(). Загрузку нашего компонента будем производить по окончании загрузки страницы. Воспользуемся аналогом записи $(document).ready():
Ext.onReady(function() { // Когда страница загрузилась
    MODx.load({ // Вставляем на страницу объект
        xtype: 'panel', // Тип объекта - Панель
        renderTo: 'modx-panel-holder', // Вставить объект надо в #modx-panel-holder
        items: [{ // Внутри панели будет другой объект
            html: '<h2>Things</h2>', // который представляет из себя HTML-блок
        } ]
    });
});

Обновляем страницу компонента и видим, что ничего не изменилось)) Но это на первый взгляд. Посмотрите в инспекторе кода — ExtJS вставил заголовок внутрь дива modx-panel-holder, но не напрямую, а сгенерировал целый набор вложенных дивов. Так он работает.

Преимущество ExtJS в том, что мы можем избавиться от дублирования кода и, в то же время, использовать его повторно, если нам это нужно. Для этого определим новый ExtJS-компонент — тогда мы сможем обращаться к нему из любого места и даже переопределять некоторые его свойства:
Things = function (config) { // Создаём объект Things
    config = config || {}; // Определяем настройки объекта
    Ext.applyIf(config, { // Указываем состав объекта
        components: [{
            xtype: 'panel',
            renderTo: 'modx-panel-holder',
            items: [{
                html: '<h2>Things</h2>',
            } ]
        } ]
    });
    Things.superclass.constructor.call(this, config); // Магия =)
};
Ext.extend(Things, MODx.Component); // Расширяем объект MODx.Component нашим объектом
Ext.reg('things', Things); // Регистрируем xtype для нашего объекта

Ext.onReady(function() {
    MODx.load({
        xtype: 'things', // Командуем загрузить наш новый объект
    });
});

Как же нам теперь переопределить свойства нашего объекта? Нужно всего лишь передать их внутри config. У нашего объекта есть только свойство components. Давайте его и переопределим, ради эксперимента:
// ...
Ext.onReady(function() {
    MODx.load({
        xtype: 'things',
        components: [{ // Указываем новый состав объекта
            xtype: 'panel',
            renderTo: 'modx-panel-holder',
            items: [{
                html: '<h2>Things override</h2>',
            } ]
        } ]
    });
});

Компонент — это, обычно, просто контейнер, который содержит в себе объекты, которые мы собираемся использовать. Поэтому часто можно увидеть, что сам компонент не содержит элементов. А уже его дочерние объекты являются разными сущностями — страницы, панели, таблицы, окна и прочее.

Для удобства доступа к тем или иным дочерним объектам, разделим их на группы:
// Создаём компонент - главный объект
var Things = function (config) {
    config = config || {};
    Things.superclass.constructor.call(this, config);
};
Ext.extend(Things, MODx.Component, { // Перечисляем группы, внутрь которых будем "складывать" объекты
    panel: {}, page: {}, window: {}, grid: {}, tree: {}, combo: {}, config: {}, view: {}, utils: {}
});
Ext.reg('things', Things);
// Мы не будем вставлять компонент на страницу с помощью MODx.load,
// поэтому нужно создать экземпляр нашего класса
// чтобы можно было обращатсья к его свойствам
Things = new Things();

// Создаём внутри компонента главную панель
// (через точку в JS обозначется вложенность массива, то есть мы создаём
// объект Home внутри panel, который, в свою очередь, находится в Things)
Things.panel.Home = function (config) {
    config = config || {};
    Ext.apply(config, {
        // xtype можно не указывать, так как внутри MODx.Panel xtype уже указан
        // А вот если вы захотите xtype изменить, его можно указать здесь
        renderTo: 'modx-panel-holder',
        items: [{
            html: '<h2>Things</h2>'
        } ]
    });
    Things.panel.Home.superclass.constructor.call(this, config); // Опять магия
};
Ext.extend(Things.panel.Home, MODx.Panel); // Наша панель расширяет объект MODX.Panel
Ext.reg('things-panel-home', Things.panel.Home); // Регистрируем новый xtype для панели

Ext.onReady(function() {
    MODx.load({ // На странице выводим сразу нашу панель
        xtype: 'things-panel-home'
    });
});

ExtJS TabPanel

Немного украсим нашу страничку и, заодно, посмотрим, как добавлять на неё элементы. Для начала добавим панели класс container, чтобы появились отступы от других элементов админки. А так же добавим блок с табами и описанием. У объекта табов xtype — tabpanel, но в MODX есть свой объект табов, который расширяет Ext.TabPanel. Этот объект добавляет CSS-классы, чтобы табы смотрелись более органично внутри админки. Кроме того, табы MODX могут быть ещё и вертикальными. Поэтому мы будем использовать более «навороченные» MODX-табы:
// ...
Things.panel.Home = function (config) {
    config = config || {};
    Ext.apply(config, {
        renderTo: 'modx-panel-holder',
        cls: 'container', // Добавляем отступы
        items: [{
            html: '<h2>Things</h2>'
        }, {
            xtype: 'modx-tabs', // Добавляем объект табов в нашу панель
            items: [{ // Перечисляем, какие именно табы нам нужны
                title: 'Things 1', // Заголовок первого таба
                items: [{ // А внутри таба HTML-блок с классом panel-desc
                    html: 'Things 1 description', 
                    cls: 'panel-desc',
                } ]
            }, {
                title: 'Things 2', // Заголовок второго таба
                items: [{ // Внутри таба ещё один HTML-блок с классом panel-desc
                    html: 'Things 2 description', 
                    cls: 'panel-desc',
                } ]
            } ]
        } ]
    });
    Things.panel.Home.superclass.constructor.call(this, config); // Чёртова магия =)
};
Ext.extend(Things.panel.Home, MODx.Panel);
Ext.reg('things-panel-home', Things.panel.Home);
// ...

Как вы поняли, кроме документации по ExtJS, нужно смотреть ещё и в исходный код MODX. В основном, все стандартные ExtJS-объекты в MODX лежат в папке /manager/assets/modext/widgets/

Примеры кода у нас начали разбухать, поэтому я буду пропускать некоторые строки, будьте внимательны, чтобы не затереть нужное.

В следующей статье «оживим» наш интерфейс — рассмотрим отправку запросов и обработку ответа.


0 комментариев

    Авторизация

    через сервис Loginza:

    Подписка или RSS

    Буду присылать новые статьи — никакого спама



    Шаблоны MODX

    1 2 Дальше »

    Объектная
    модель
    MODX