.. _components: ================================================ Добавление и измененение компонентов в дизайнере ================================================ Описание доступных типов и свойств компонентов ============================================== Все компоненты, используемые в дизайнере описаны в файле model-types-config.js. Внутри него находится объект typesConfig, полями которого являются доступные типы. Рассмотрим на примере ExtFormPanel:: formPanel: { parent:'panel', isContainer:true, properties : { id : { defaultValue:'frm_formpanel', isInitProperty:true, isQuickEditable: true }, layout: { defaultValue:'form', isInitProperty:true, isQuickEditable: true }, title: { defaultValue:'', isInitProperty:true, isQuickEditable: true }, url: { defaultValue:'' }, fileUpload:{ defaultValue:false }, urlShortName:{ defaultValue:'', isQuickEditable:true } }, childTypesRestrictions:{ disallowed:['arrayStore','gridColumn','jsonStore','pagingToolbar'] }, toolboxData: { category:'Containers', text:'Form panel' }, treeIconCls:'designer-formpanel' } *parent:'panel'* - Ссылка на тип, который является предком текущего типа. Типы компонентов наследуют свойства друг друга(под свойствами в данном контексте подразумеваются объекты в properties, ограничения и другие объекты первого уровня вложенности не наследуются) Раз formPanel является наследником Panel она получит свойства layout, region, height, width и тд *isContainer:true* - В случае если поле указано и равно true, то в компонент можно добавлять дочерние компоненты. Нужно отметить что под добавление дочерних в данном случае подразумевается чисто абстрактное условие, регламентирующее возможность иметь дочерние компоненты во внутренней структуре данных используемых дизайнером, и никак не связана напрямую с объектной моделью ExtJs. Так ComboBox имеет isContainer:true тк в него можно добавить подчиненный DataStore. *properties: {}* - Вложенные свойства это те поля что доступны для редактирования пользователю. *defaultValue:'form'* - обязательное поле для каждого свойства типа. По типу(javascript типу) определеяется редактор. К примеру height и width у контенейров обязан быть числом, и поэтому defaultValue:0 и редактироваться будет NumberField'ом. *isInitProperty:true* - Необязательное поле. Если установлено то при создании нового экземпляра поле будет проинициализировано. Типичный пример тайтлы у всего что можно *isQuickEditable:true* - Необязательное поле. True - свойство появиться в редакторе быстрых свойств *propertyType:'enum'* - Необязательное поле. Если не указано, то Javascript тип свойства будет определен по значению defaultValue. В данный момент обрабатываюются значения 'enum' и 'object' Значения перечисления обрабатываютcя в файле property-editor.js Для значения 'object' - вводимый пользователем текст будет про'eval'ен, это нужно для вложенных объектов. Значения перечислений прописываются в model-types.js *isNotEditable:true* - Необязательное поле. Используется когда нужно проинизализировать что-то в экземпляре объекта, но не давать пользователю рукам это что-то перебить. Пример TabPanel, дабы не унаследовать от Panel значение layout по умолчанию 'auto' *childTypesRestrictions* - Ограничения для подчиненных объектов. Состоит из трех массивов со строковыми названиями типов. allowed - то что можно добавлять, disallowed - то что нельзя, single - одиночные типы Каждый из массивов может отсутствовать, в таком случае условие игнорируется при проверке. К примеру disallowed:undefined, allowed:['panel'], single:['panel'] - к текущему компоненту можно добавить ровно одну панель *toolboxData* - Информация для панели инструментов. Может отсутствовать *treeIconCls* - Очевидно иконка типа компонента. Необязательное поле Визуальное отображение компонентов ================================== Код рисующий штуки на экране уютно расположился в файле ui.js Для рисования использовался хитрый паттерн "Посетитель" Для рисования нужно добавить новую функцию объекту mapObject, имя которой совпадало бы с названием типа определенного в файле конфигов. Если функция не определена - ничего не случится. Просто компонент не нарисуется:: comboBox:function(model, cfg) { var store = undefined; //попробуем найти стор for (var i = 0; i < model.childNodes.length; i++) { if (model.childNodes[i].attributes.type == 'arrayStore') { store = new Ext.data.ArrayStore( Ext.apply({ fields:['id',model.attributes.properties.displayField] },model.childNodes[i].attributes.properties) ); } } //или создадим пустой if (!store) { store = new Ext.data.Store({ autoDestroy:true }); } return Ext.apply( cfg , { store:store, mode:'local', xtype:'combo' }); } В аргументе model передается объект внутренней модели дизайнера, через него можно получить доступ к родительскому компоненту или к дочерним. cfg - готовый объект конфига со свойствами отредактированными пользователем. Для простых случаев, например, textField достаточно в объект конфига добавить xtype для того чтобы экст корректно создал визуальный компонент. Можно не использовать xtype, и создавать инстансы классов. В примере выше рассамтривается создание комбобокса. Чаще всего для дизайна нам не требуется сложное поведение компонентов, и поэтому можно создать ограниченую болванку, которой достаточно чтобы послужить отражением более сложного компонента(или закрыть от активации какое то поведение, как правило обмен данными с севрером) Сериализация/десериализация =========================== Код находиться в файле transfer.js В подавляющих случаях туда не нужно ничего добавлять. Но иногда, когда у компонентов есть компоненты не принадлежащие items, приходится добавлять всячески исключения. Пример тому свойство store, или массив columns у грида. Смотреть нужно на объект childPropertyObjects. В массивы добавляются свойства для особенной десериализации, в функции типы требующие сериалзиации как-то поособенному. Серверный маппинг ================= Для того, чтобы код успешно серриализовался в python код и обратно нужно добавлять компоненты в серверный маппинг. Серверный маппинг находится в файле m3_designer/ide/mapping.json. Рассматорим пример маппинга:: { "class": { "objectGrid": "ExtObjectGrid" }, "config": { "urlNew":"url_new" ,"urlEdit":"url_edit" ,"urlDelete":"url_delete" ,"urlData":"url_data" ,"rowIdName":"row_id_name" ,"columnParamName":"column_param_name" ,"allowPaging":"allow_paging" ,"localEdit": "local_edit" ,"urlDataShortName": { "type":"shortname" ,"value":"url_data" } ,"urlEditShortName": { "type":"shortname" ,"value":"url_edit" } ,"urlDeleteShortName":{ "type":"shortname" ,"value":"url_delete" } ,"urlNewShortName":{ "type":"shortname" ,"value":"url_new" } } ,"parent": "gridPanel" } Объект class говорит о том, что клиентский класс *objectGrid* будет маппиться в серверный класс *ExtObjectGrid*. Конфиг объектов данного класса так же маппится из клиенского кода *urlNew* в серверный код *url_new* и наоборот. Могут быть сложные свойтсва, такие свойства помечаются свойством "type", например объект "shortname", имеющий свойство "create" будет отображен в серверный поиска шортнейма - *instanse.attr = urls.get_url('create')*