Для разработки визуальных элементов управления необходимо описать свой класс и пронаследовать его от PP.Ui.Control, в котором заложена функциональность по работе с DOM.
PP.Ui.MyControl = function (settings)
{
this._Template = "<div>{Content}</div>";
PP.Ui.MyControl.base.constructor.apply(this, arguments);
this._render(); //Сразу после создания компонента вызываем рендеринг компонента
};
PP.initClass(PP.Ui.MyControl, PP.Ui.Control, "PP.Ui.MyControl");
PP.Ui.MyControl.prototype._render = function ()
{
this._initFromHTML(this._Template); //Главный элемент, в котором будет рисоваться элемент управления
this._DomNode.className = "PPMyControl"; //проинициализируется через шаблон и его DOM вершина будет записана в поле _DomNode
if (this._ParentNode)
this.addToNode(this._ParentNode); //Проверяем, задана ли родительская вершина для данного компонента; если задана, то вызываем метод addToNode для вставки компонента на страницу
};
PP.Ui.MyControl.prototype._bindEvents = function ()
{
PP.Ui.MyControl.base._bindEvents.apply(this, arguments);
//В данном методе осуществляем подписку на необходимые события
//Например:
this._addEvent(this._DomNode, "click", this._onMyClicked); //Обработчик события this._onMyClicked автоматически будет вызван в контексте объекта this.
};
PP.Ui.MyControl.prototype._unBindEvents = function ()
{
PP.MyControl.base._unBindEvents.apply(this, arguments);
//В данном методе осуществляем отписку от используемых событий
//Например:
this._removeEvent(this._DomNode, "click", this._onMyClicked);
};
this._DomNode - это главная вершина компонента, на которую вешаются базовые обработчики стандартных событий.
this._ParentNode - это dom-вершина, куда необходимо положить самого себя.
Размеры компонента определяются через свойство Width, Height, определённые в базовом классе.
Компоненты PP не должны подписываться на глобальные события JavaScript, например window.resize или document.mousedown.
Для каждого класса можно создать несколько компонентов, и они должны работать независимо друг от друга.
Каждый визуальный компонент содержит свойство Content, которое определяет содержимое элемента управления. В качестве значения могут выступать строки, html-элементы или же другие визуальные компоненты.
При изменении визуального свойства компонента оно должно сразу отражаться в самом компоненте. Если компонент имеет сложную логику расчётов своей визуальной части, то необходимо предоставлять методы beginUpdate/endUpdate, между вызовами которых визуального обновления не происходит в целях повышения производительности.
Вместо стандартных функций setTimout, clearTimout рекомендуется использовать методы PP.setTimeout, PP.clearTimeout, которые позволяют вызвать функцию с параметрами и в заданном контексте.
Запрещено использование замыканий и описание функций внутри других функций.
Для реализации анимации рекомендуется использовать класс PP.Ui.Animation.
Для поддержки мультиязычности в высокоуровневых компонентах необходимо использовать объект PP.resourceManager и свойство ResourceKey у наследников класса Control. Например, если в кнопке нужно отобразить текст «Маша» на русском языке, а на английском «Mary», то необходимо написать следующий код:
var btn2 = new PP.Button({
ParentNode: document.getElementById("example"),
ResourceKey: "MyButton"
});
При этом в проекте с ресурсами (.NET сборка PP.Resources) в каком-либо resx файле должен быть ресурс с идентификатором MyButton_Сontent. Здесь «Content» означает - какое свойство необходимо заполнить в объекте btn2 при создании кнопки или при динамической смене текущей культуры.
Для простых надписей необходимо использовать компонент PP.Ui.Label для работы с ресурсами.
Для ручного извлечения текста ресурса необходимо использовать метод PP.resourceManager.getString(<Идентификатор ресурса>).
Базовый класс PP.Object реализует метод dispose, который проверяет по всем свойствам текущего объекта и если свойство является объектом и также имеет метод dispose, то у него тоже вызывается данный метод. Само свойство из объекта удаляется.
Данный алгоритм может привести к некоторым неочевидным ошибкам.
Например, при разработке собственного компонента, который имеет три свойства, задаваемые извне.
PP.Ui.MyButton = function (settings)
{
this._ImageList = null;
this._Metabase = null;
this._Source = null;
PP.Ui.MyButton.base.constructor.apply(this, arguments);
};
PP.initClass(PP.Ui.MyButton, PP.Ui.Control, "PP.Ui.Button");
//Пример использования данного компонента:
var imgList = new PP.ImageList({ Source: "bla.png" });
var source = new PP.Exp.EaxAnalyzer();
var mb = new PP.Mb.Metabase();
var btn = new PP.Ui.MyButton({
IamgeList: imgList,
Source: source,
Metabase: mb
});
btn.dispose();
После выполнения данного примера и вызова dispose у кнопки объектам source, imgList, mb также будет вызван метод dispose согласно алгоритму, описанному выше. Но так как эти свойства задаются извне и создаются вне кнопки, то это является ошибкой. Поэтому для свойств, значения которых являются ссылками на объекты типа PP.Object и задаются извне, нельзя вызывать dispose внутри класса-пользователя этих объектов. Таким образом, в классе MyButton необходимо переопределить базовый метод dispose следующим образом:
PP.Ui.MyButton.prototype.dispose = function ()
{
delete this._ImageList;
delete this._Metabase;
delete this._Source;
PP.Ui.MyButton.base.dispose.apply(this, arguments);
};
В переопределённом методе обязательно необходимо вызвать dispose базового класса.
Для работы с векторной графикой (SVG, VML) и графическими примитивами необходимо использовать PP.SVG.
Определение: высокоуровневый компонент - это визуальный компонент, который для отображения какой-либо информации использует данные с какого-либо сервиса.
Каждый такой компонент может использовать для отображения данных низкоуровневые компоненты - TabSheet, TreeList, ComboBox и так далее.
Высокоуровневый компонент имеет важное свойство - Source, источник данных, который поставляет данные в JSON формате для представления. Объект Source является пассивной моделью, сам себя он не строит. Для построения источника данных должен быть отдельный класс – сервис, который предоставляет упрощённый API для взаимодействия с внешними сервисами. Источник у компонента может только один.
При установке источника данных в высокоуровневый компонент, он должен сразу построить по нему визуальную часть.
Каждый такой компонент должен реализовывать интерфейс:
(PP.ISourceView = function ()
{
/// <summary> Базовый интерфейс для всех компонентов, работающих через источник данных Source </summary>
/// <field name="refresh" type="Method">Метод для обновления части представления в зависимости от того, что изменилось в метаданных</field>
/// <field name="refreshAll" type="Method">Метод на полное обновление представления</field>
/// <field name="Source" type="Property">Источник данных</field>
/// <field name="PropertyChanged" type="Event">Событие на визуальное изменение метаданных источника</field>
/// <field name="RequestMetadata" type="Event">Событие запроса метаданных источника для отрисовки представления</field>
var intf = PP.ISourceView;
PP.initInterface(intf, "ISourceView");
intf.refresh =
intf.refreshAll = PP.ClassMembers.Method;
intf.Source = PP.ClassMembers.Property;
intf.RequestMetadata =
intf.PropertyChanged = PP.ClassMembers.Event;
})();
Использование картинок можно разделить на два случая:
В этом случае картинки размещаются в папке img.
Их использование осуществляется через css. При компиляции проекта, в css url к картинке заменяется на base64 строку.
DIV.PPCPanel TD.PPCCPaletteColorBtn.selected
{
background-image: url('img/cc_btn_s.png');
}
Картинки необходимо размещать в папке img/<название инструмента>/.
Данные картинки можно использовать как в css, так и через компонент PP.ImageList, который предоставляет удобный API для работы со спрайтами.
Чтобы высокоуровневые компоненты корректно находили путь к картинкам, необходимо в них определять свойство ImagePath, которое должно указывать на корневую папку img. При этом его использование в API будет следующим:
expressBox = new PP.Exp.Ui.ExpressBox({
ParentNode: document.body,
Source: source,
Service: service,
ImagePath: "../Debug/img/"
});
А в реализации:
this._imageList = new PP.ImageList({
Source: this._ImagePath + "olap/olap_ribbon.png",
IconHeight: 32,
IconWidth: 32
});
Разметку элементов управления относительно друг друга следует задавать с помощью специальных компонентов - PP.Ui.Panel, PP.Ui.StackPanel, PP.Ui.LayoutGrid, PP.Ui.FlexLayout, PP.Ui.TabControl, PP.Ui.NavigationBar, PP.Ui.LayoutBox.
Запрещается создавать объекты классов динамически, т.е. так: new PP[“Button”]. В этом случае необходимо использовать метод PP.create. Например:
PP.create({PPType : ‘”PP.Ui.Button”, Content “Кнопка”})
Запрещается использование в теле функции свойств arguments.callee, а также оператора присоединения with.
Запрещается использование функции eval, а также конструктора new Function для создания динамического кода из строки.
Запрещается использовать встроенные getter’ы setter’ы для определения собственных свойств.
Запрещено какое-либо использование сторонних библиотек, в том числе jQuery, Dojo и т.д.
Для правильной работы компонентов Prognoz Platform 8 в Internet Explorer и других браузерах страница должна содержать следующее описание типа документа:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html> - для современных браузеров.
Также на странице должен быть тег:
<meta http-equiv="X-UA-Compatible" content="IE=edge" charset="utf-8"/>
Компоненты Prognoz Platform 8 не поддерживают режимы совместимости Internet Explorer.
Для синхронизации с ресурсами Prognoz Platform 8 необходимо указать кодировку «utf-8».
Проверку входного типа необходимо следующим образом:
classPrto.setTextWrapping = function (value)
{
//#ifdef DEBUG
if (!PP.isMemberOf(PP.Ui.TextWrapping, value))
throw PP.ArgumentException(this);
//#endif
this._TextWrapping = value;
};
Следующая статья: Требования к CSS коду