<?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 обычно построена следующим образом:
- Ищем наиболее подходящий для задачи xtype. Для поиска можно воспользоваться документацией. Она на английском, но по названию объектов можно хотя бы сориентироваться. Например, если нам нужно отобразить какое-то окошко, идём в раздел Ext.Window и видим, что нужный нам xtype — это window: https://ilyaut.ru/cloud/1WpUHf.png
- Решаем, внутри какого объекта отобразить наш новый объект, вставляем его внутрь соответствующего свойства items
- Переопределяем те свойства и методы объекта, в которых мы хотим изменить поведение.
Давайте, уберём из контроллера метод getTemplateFile и отобразим заголовок с помощью ExtJS. Файл home.tpl тоже можно удалить, он нам больше не понадобится — всю HTML-структуру будет создавать ExtJS.
MODX создаёт DIV с id='modx-panel-holder' на странице компонента. Вот в нём мы и будем создавать всю внутреннюю структуру. Добавить объект в этот div можно с помощью команды MODx.add(). Загрузку нашего компонента будем производить по окончании загрузки страницы. Воспользуемся аналогом записи $(document).ready():
Ext.onReady(function() { // Когда страница загрузилась MODx.add({ // Вставляем на страницу объект xtype: 'panel', // Тип объекта - Панель items: [{ // Внутри панели будет другой объект html: '<h2>Things</h2>', // который представляет из себя HTML-блок } ] }); });
Обновляем страницу компонента и видим, что ничего не изменилось)) Но это на первый взгляд. Посмотрите в инспекторе кода — ExtJS вставил заголовок внутрь дива modx-panel-holder, но не напрямую, а сгенерировал целый набор вложенных дивов. Так он работает.
Преимущество ExtJS в том, что мы можем избавиться от дублирования кода и, в то же время, использовать его повторно, если нам это нужно. Для этого определим новый ExtJS-компонент — тогда мы сможем обращаться к нему из любого места и даже переопределять некоторые его свойства:
Things = function (config) { // Создаём объект Things config = config || {}; // Определяем настройки объекта Ext.applyIf(config, { // Указываем состав объекта components: [{ xtype: 'panel', 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.add({ xtype: 'things', // Командуем загрузить наш новый объект }); });
Как же нам теперь переопределить свойства нашего объекта? Нужно всего лишь передать их внутри config. У нашего объекта есть только свойство components. Давайте его и переопределим, ради эксперимента:
// ... Ext.onReady(function() { MODx.add({ xtype: 'things', components: [{ // Указываем новый состав объекта xtype: 'panel', 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.add, // поэтому нужно создать экземпляр нашего класса // чтобы можно было обращатсья к его свойствам Things = new Things(); // Создаём внутри компонента главную панель // (через точку в JS обозначется вложенность массива, то есть мы создаём // объект Home внутри panel, который, в свою очередь, находится в Things) Things.panel.Home = function (config) { config = config || {}; Ext.apply(config, { // xtype можно не указывать, так как внутри MODx.Panel xtype уже указан // А вот если вы захотите xtype изменить, его можно указать здесь 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.add({ // На странице выводим сразу нашу панель 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, { 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/
Примеры кода у нас начали разбухать, поэтому я буду пропускать некоторые строки, будьте внимательны, чтобы не затереть нужное.
В следующей статье «оживим» наш интерфейс — рассмотрим отправку запросов и обработку ответа.
Работа проделана колоссальная. Спасибо Вам за нее.
Но повторить ваш урок успешно не получается.
Если бы вы
Выложили файлики
home.js и index.class.php
для скачивания.
Было бы очень окей.
Где-то закралась ошибочка, и не получается это урок
компонентстраничку в админке с нуля. Тут надо отдать должное, вы все хорошо расписали и все прошло как по маслу. Но я пытаюсь сделать, чтобы весь Ext.JS загружался в div, указанный в файле .tpl и в теории (а так же подобию других дополнений) это не должно было быть сложным. Я создал div с id=«test»Далее в файле c extjs
thing-panel-home — зарегистрированная панелька рабочая.
ну и в контроллере
Но, вместо того, чтобы подгружаться в div все добавляется после него. Я пришел к выводу, что extjs грузится раньше, чем div и поэтому не находит его и просто загружает. Хотя, по моей теории, должна быть ошибка.
Я разделил все на 3 js файла, вначале подгружаю тот, где
и сама панелька
Потом гриды и файл инициализации ранее. tpl вообще загружаю в конце контроллера. И я не знаю что делать. что уже только не перебирал. В див не грузится, только после него. Все работает, все функционирует. Я даже панель упрастил. Классы переименовывал. Будто что-то надо добавить, но что — не понимаю. Кто-нибудь, может подсказать, что случилось.
Вот контроллер мой
Почему это очень удобно (если вдруг кто из новичков прочтет), иначе tpl файл будет выглядеть как position:absolute, а вся панелька будет «скроллиться» под него. Тут или полностью отказаться от шаблона и просто делать слои в extjs или еще потратить бессонные ночи :-) Я уже думал делал класс в классе, точнее в этом контроллере все рендерить, а потом require_once файл с вызовом панели.
Благодаря вашим урокам, я, кстати, еще в одни дебри полез :-) но на это можете не отвечать. получаю в handler, через get запросом данные и с помощью Ext.getCmp('id_поля').setValue(); присваиваю дальше. Одно из таких значений — путь к картинке. Что тоже работает и хорошо, т.е. кнопка отработала нажатие в texfield появился адрес к jpg. И вот решаю теперь задачу по кнопке preview рядом с этим полем, открыть условный window.PrevImg, который отрендерит картинку. Ну а на полном серьезе, вы рассмотрели здесь основные вещи при создании CMP, без различных вспомогательных дополнений, что катализирует на творчество и подтягивание знаний. А уж ExtJs — это просто жесть. Даже их страница docs по версии 3.4.0 — дремучая вещь.
можно было и без переменной обойтись.
прошу прощения, что к теме renderTo вообще не относится, не мог сам себе не ответить, на тот курсив, чтобы не отвлекать на лишнее.
Использую modx3 и заготовку modExtra3.
Что хочу сделать:
1. Отображать список «предметов» на странице компонента, (тут все ок из коробки), запретил только добавление, поскольку надо связывать «предмет» с ресурсом.
2. На вкладке ресурса добавлять «предметы» и сохранять их с указанием id ресурса в бд.
Проблема — не получается добавить вкладку компонента на страницу редактирования ресурса, можете показать как это правильно сделать в моем случае?