Принципы кодирования

Разработка визуальных элементов управления

Для разработки визуальных элементов управления необходимо описать свой класс и пронаследовать его от 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, между вызовами которых визуального обновления не происходит в целях повышения производительности.

setTimeout, clearTimeout

Вместо стандартных функций 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(<Идентификатор ресурса>).

Dispose

Базовый класс 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 базового класса.

PP.SVG

Для работы с векторной графикой (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;

})();

Использование картинок. ImageList

Использование картинок можно разделить на два случая:

  1. Использование в базовых компонентах.

В этом случае картинки размещаются в папке img.

Их использование осуществляется через css. При компиляции проекта, в css url к картинке заменяется на base64 строку.

DIV.PPCPanel TD.PPCCPaletteColorBtn.selected

{

   background-image: url('img/cc_btn_s.png');

}

  1. Использование в высокоуровневых компонентах.

Картинки необходимо размещать в папке 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 и т.д.

Doctype

Для правильной работы компонентов 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 коду