Содержание


OpenLaszlo - платформа для быстрого создания и развертывания многофункциональных интернет-приложений

Что такое OpenLaszlo, и как это упрощает создание и внедрение многофункциональных интернет-приложений

Comments

Обзор

Одна из серьезнейших проблем, с которыми сталкиваются разработчики RIA, это проблема совместимости браузеров. Так как технология OpenLaszlo основана на парадигме языка Java "написал однажды – работает везде", она гарантирует, что приложения, основанные на OpenLaszlo, одинаково работают в разных браузерах и на разных операционных системах.

Архитектура

На следующем рисунке показана архитектура OpenLaszlo со стороны сервера и клиента.

Рисунок 1. Серверная и клиентская подсистемы OpenLaszlo
Схема архитектуры серверной и клиентской подсистем OpenLaszlo
Схема архитектуры серверной и клиентской подсистем OpenLaszlo

Сервер OpenLaszlo

OpenLaszlo Server — это приложение Java servlet/JSP. Он позволяет разрабатывать LZX-приложения на одном дыхании.

В OpenLaszlo Server входят пять основных подсистем:

  • Компилятор интерфейса – Компилятор интерфейса (Interface Compiler) содержит модули LZX Tag Compiler и Script Compiler, которые преобразуют исходные файлы в исполняемые (SWF) и подают их либо как байт-код в плагинн, который работает в браузере клиента (таком как Flash или J2ME), либо как JavaScript (DHTML), исполняемый самим браузером.
  • Медиатранскодер – Медиатранскодер (Media Transcoder) преобразует весь спектр медиаактивов в единый формат для обработки целевым механизмом клиент-рендеринга OpenLaszlo. Это позволяет приложениию OpenLaszlo представляять поддерживаемые типы носителей в едином формате на одном холсте без использования нескольких вспомогательных приложений или дополнительных программ воспроизведения. Медиатранскодер автоматически обрабатывает следующие типы медиа: JPEG, GIF, PNG, MP3, TrueType и SWF (только art/animation).
  • Диспетчер данных – Диспетчер данных (Data Manager) выступает в качестве интерфейса между приложениями OpenLaszlo и другими приложениями в сети, такими как базы данных и Web-сервисы XML. Он состоит из компилятора данных, который преобразует данные в сжатую бинарную форму, и ряда соединителей данных, которые позволяют приложениям OpenLaszlo извлекать данные с помощью XML/HTTP.
  • Кэш – Кэш содержит последнюю скомпилированную версию любого приложения. При первом обращении к приложению OpenLaszlo оно компилируется, и клиенту направляется результирующий файл SWF. Копия кэшируется на сервере, так что последующим запросам уже не нужно ждать компиляции.

Клиент OpenLaszlo

На стороне клиента архитектура OpenLaszlo в основном состоит из классов Laszlo Foundation, что обеспечивает рабочую среду для исполнения приложений OpenLaszlo. Всякий раз, когда клиент вызывает приложение OpenLaszlo по его URL, вместе с исходным кодом загружаются также необходимые библиотеки времени выполнения. Клиент всегда поддерживает связь с сервером.

Клиент OpenLaszlo состоит из следующих основных подсистем:

  • Система событий – Система событий (Event System) отвечает за обработку различных событий пользователя, таких как нажатие кнопки мыши или передача данных. Она позволяет также повысить производительность приложения путем выполнения различных операций на стороне клиента, таких как сортировка и проверка, вместо того, чтобы передавать их на сервер.
  • Загрузчик данных/компоновщик – Загрузчик данных (Data Loader) получает данные со стороны сервера и компонует их с соответствующими элементами пользовательского интерфейса, такими как меню, текстовые поля и текстовые области на стороне клиента.
  • Система верстки и анимации – Система верстки и анимации (Layout and Animation) управляет различными алгоритмами, связанными с анимацией, так что пользователь может просматривать компоненты без видимых прерываний. Он управляет также расположением различных компонентов с использованием относительного и абсолютного положения пикселей при минимальном программировании.

Цикл запроса

Типичный поток запросов проходит следующий путь:

  1. Пользователь отправляет запрос на ресурс через браузер в форме URL.
  2. Сервер OpenLaszlo извлекает ресурс из URL и направляет его в компилятор интерфейса для компиляции.
  3. Компилятор интерфейса преобразует теги описания приложение LZX и JavaScript в исполняемый байт-код (SWF) для передачи в клиентскую среду OpenLaszlo. Этот код помещается в кэш, откуда передается клиенту.
  4. В зависимости от того, как запущено приложение, он передается в виде файла SWF или файла HTML с внедренным объектом SWF вместе с соответствующими основными классами Laszlo.
  5. В том случае, если ответ передан в HTML-формате, приложение отображается браузером. Если ответ передан в формате SWF, его отображает Flash-плеер.
  6. Пользователь вводит некоторые данные запроса на стороне клиента и передает эти данные.
  7. Сервер OpenLaszlo вызывает соответствующий коннектор данных, который, в свою очередь, получает данные XML.
  8. Сервер OpenLaszlo возвращает данные клиенту.
  9. Базовые классы Laszlo на стороне клиента связывают данные с соответствующими объектами пользовательского интерфейса. Элементы экрана обновляются с учетом ответных данных.

Типичный цикл запроса приложения OpenLaszlo, описанный выше, показан на рисунке 2.

Рисунок 2. Цикл запроса
Блок-схема описанного цикла запроса
Блок-схема описанного цикла запроса

Ваше первое приложение OpenLaszlo

Разработка приложения OpenLaszlo включает в себя:

  • Написание программы OpenLaszlo (на XML и JavaScript) с помощью текстового редактора.
  • Сохранение файла в виде файла LZX.
  • Компиляция файла LZX в файл SWF или DHTML, вручную или с помощью сервера OpenLaszlo, и просмотр результата в браузере.

Написание первого приложения OpenLaszlo

Как уже упоминалось, приложение OpenLaszlo – это документ XML. Таким образом, для написания кода можно использовать любой текстовой редактор. Код, приведенный в листинге 1 – это простое LZX-приложение HelloWorld.

Листинг 1. HelloWorld.lzx
<canvas height="350" width="1050" bgcolor="#FFBE7D" >
	<view width="500" height="250" align="center" valign="middle" bgcolor="#FFFF66">
		<text align="center" valign="middle">
			<font size="25">Welcome to Hello World!</font>
		</text>
	</view>
</canvas>

Сохранение исходного файла

Теперь сохраните сценарий как HelloWorld.lzx. Файл должен быть сохранен где-то в каталоге Server/lps-4.0.х, который находится в каталоге установки OpenLaszlo Server.

Компиляция и запуск сценария

Самый простой способ компиляции файла LZX – это использование сервера OpenLaszlo. Убедитесь, что на компьютере работает Apache Tomcat, и направьте браузер по следующему адресу: http://localhost:8080/lps-4.0.x/path. Здесь: path это путь к файлу LZX относительно каталога Server/lps-4.0.x.

Например, если сценарий будет сохранен как Server/lp2-4.0.x/hello/HelloWorld.lzx, URL для компиляции приложения OpenLaszlo будет http://localhost:8080/lps-4.0.x/hello/HelloWorld.lzx, см. рисунок 3. Контейнер сервлета передаст запрос HTTP на сервер OpenLaszlo. Сервер открывает и компилирует правильный файл LZX, генерирует выходные данные и сохраняет его во временном каталоге.

Затем сервер OpenLaszlo отправляет сгенерированный выход в браузер. Если программа скомпилирована как Flash, созданный файл SWF и связанные с ними файлы кэшируются. Последующие запросы к тому же немодифицированному файлу LZX будут обрабатываться гораздо быстрее, так как не нужна никакая повторная компиляция. Если компиляция не удалась, в браузере будет отображаться сообщение об ошибке.

Рисунок 3. Пример приложения OpenLaszlo Hello World.
Пример приложения OpenLaszlo Hello World
Пример приложения OpenLaszlo Hello World

В нижней части дисплея показан инструмент разработки, содержащий кнопки, которые позволяют просмотреть исходный код OpenLaszlo, развернуть приложение, перекомпилировать исходный код, а также выполнять другие функции. Можно обойтись и без инструмента разработки, передав соответствующий тип запроса и цель времени выполнения в качестве параметров. Пример:

http://127.0.0.1:8080/lps-4.3.0/helloWorld/HelloWorld.lzx?lzr=swf9&lzt=html

и

http://127.0.0.1:8080/lps-4.3.0/helloWorld/HelloWorld.lzx?lzr=dhtml&lzt=html

На рисунке 4 приведен пример исполнения приложения HelloWorld с параметрами для замены панели инструментов.

Рисунок 4. Пример приложения OpenLaszlo Hello World
Скриншот примера приложения OpenLaszlo Hello World представляет собой экран без панели инструментов разработки
Скриншот примера приложения OpenLaszlo Hello World представляет собой экран без панели инструментов разработки

Основные компоненты

OpenLaszlo поставляется с набором классов - простых и многофункциональных компонентов, которые делают LZX-программирование простым и быстрым. Класс BaseComponent – это подкласс LzView и суперкласс всех компонентов LZX.

Canvas (холст)

Тег canvas представляет собой верхний контейнер для всех представлений и элементов в приложении LZX. Для каждого приложения LZX существует только один холст. Когда компилятор LZX встречает тег canvas, обрабатывается класс LzCanvas. Например, код в листинге 2 демонстрирует, как использовать тег canvas и некоторые из его атрибутов.

Листинг 2. Canvas.lzx
<canvas width="450" bgcolor="#6699FF" height="200" title="Canvas">
	<text align="center" valign="middle">
			<font size="25">Openlaszlo World!</font>
	</text>
</canvas>

Приведенное выше приложение можно вызвать, обратившись по адресу: http://localhost:8080/lps-4.0.x/canvas/Canvas.lzx. Результат приведен на рисунке 5.

Рисунок 5. Canvas
Скриншот Canvas с текстом 'OpenLaszlo World!
Скриншот Canvas с текстом 'OpenLaszlo World!

View (Представление)

Представление – это прямоугольная область, в которой можно отображать текст и другие элементы. Представление можно создать с помощью тега view или экземпляра класса LzView. В качестве примера в листинге 3 показано приложение LZX с использованием тега view.

Листинг 3. View.lzx
<canvas width="300" bgcolor="#ddddee" height="200">
	<view align="center" valign="middle" bgcolor="#6699FF" width="300" height="150"/>
</canvas>

Приведенное выше приложение можно просматривать с помощью http://localhost:8080/lps-4.0.x/view/View.lzx. На рисунке 6 показан результат, сгенерированный файлом view.lzx.

Рисунок 6. Использование представления
Скриншот демонстрирует представление в виде пустого синего прямоугольника.
Скриншот демонстрирует представление в виде пустого синего прямоугольника.

В типичном приложении LZX часто используется несколько представлений, вложенных друг в друга. В листинге 4 показано приложение LZX с вложенными представлениями.

Листинг 4. NestedView.lzx
<canvas height="370">
	<view width="150" height="150" bgcolor="black">
		<view width="100" height="100" bgcolor="white">
			<view width="50" height="50" bgcolor="gray"/>
		</view>
	</view>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/view/NestedView.lzx. Результат приведен на рисунке 7.

Рисунок 7. Использование вложенных представлений
Скриншот с серым прямоугольником представления, вложенным в синий прямоугольник родительского представления.
Скриншот с серым прямоугольником представления, вложенным в синий прямоугольник родительского представления.

Тег view можно использовать также для отображения или воспроизведения внешних ресурсов, таких как изображения, файлы MP3 и других Flash-файлы. Типы поддерживаемых медиа: JPG, GIF, PNG, MP3 и SWF. Обратите внимание, что поддержка MP3 ограничена аудиофайлами с дискретизацией 44.1 кГц, 22 кГц, 11 кГц, 8 кГц и 5.5 кГц. В качестве примера в листинге 5 приведено приложение LZX с использованием тега view для отображения изображения.

Листинг 5. ResourceView.lzx
<canvas width="300" bgcolor="#ddddee" height="200">
	<view align="center" resource="IBMLogo.jpg" valign="middle" bgcolor="#6699FF" 
		width="300" height="150"/>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/view/ResourceView.lzx. Результат показан на рисунке 8.

Рисунок 8. Использование Resource View
Скриншот Resource View - синий прямоугольник с логотипом IBM в верхнем левом углу
Скриншот Resource View - синий прямоугольник с логотипом IBM в верхнем левом углу

Window

Объект Window представляет собой окно переменного размера. Класс Window – это подкласс WindowPanel, который, в свою очередь, является подклассом BaseWindow. BaseWindow – это прямой потомок BaseComponent. Файл Window.lzx в листинге 6 представляет собой приложение LZX, которое отображает окно переменного размера.

Листинг 6. Window.lzx
<canvas width="450" bgcolor="#6699FF" height="200" title="Canvas">
	<window align="center" valign="middle" resizable="true" width="300" height="150">
		<text>OpenLaszlo World!</text>
	</window>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/window/Window.lzx. Результат показан на рисунке 9.

Рисунок 9. Window
Скриншот с синим холстом, содержащим текст в плавающем окне 'OpenLaszlo World!'
Скриншот с синим холстом, содержащим текст в плавающем окне 'OpenLaszlo World!'

Alert

Объект Alert представляет собой модальное диалоговое окно для отображения сообщения. У окна Alert есть кнопка ОК. По умолчанию она не отображается. Чтобы сделать ее видимой, нужно вызвать метод Alert open. Класс Alert – это подкласс ModalDialog, полученный из WindowPanel. Объект Modal Dialog представляет собой плавающее диалоговое окно. Код в листинге 7 демонстрирует, как использовать окно Alert.

Листинг 7. Alert.lzx
<canvas>
	<alert name="warning">Press OK to continue.</alert>
	<script>
		canvas.warning.open ();
	</script>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/alert/Alert.lzx. Результат показан на рисунке 10.

Рисунок 10. Окно Alert
Скриншот с окном предупреждения
Скриншот с окном предупреждения
Листинг 8. AlertWithButtons.lzx
<canvas>
	<alert name="warning" buttonl="OK" button2="No">
		Click OK to Process.
		<handler name="onresult">
		if (this.result) {
			parent.message.setText("Processing Started");
		} else {
		parent.message.setText ("Processing Stopped'");
		}
		</handler>
	</alert>
	<script>
		canvas.warning.open ();
	</script>
	<text name="message"> Do you want to start processing?</text>
</canvas>

AlertWithButtons запрашивает подтверждения у пользователя в форме окна предупреждения с кнопками Да/Нет и выполняет соответствующие действия.

Button

Объект Button представляет собой интерактивную кнопку, которая позволяет выполнить действие, вызывая событие. Этот класс является подклассом BaseButton, который, в свою очередь, является подклассом BaseComponent. Файл Button.lzx в листинге 9 представляет собой приложение LZX с использованием кнопки. Текст кнопки гласит: "Здравствуй, мир!"

Листинг 9. Button.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<button width="200" height="80" align="center" valign="middle">
		Hello World!!</button>
</canvas>

Выполните пример, направив браузер по ссылке http://localhost:8080/lps-4.0.x/layout/Button.lzx. Результат показан на рисунке 11.

Рисунок 11. Холст с кнопкой
Скриншот показывает синий прямоугольник холста, содержащий интерактивную кнопку с надписью 'Hello World!!' в центре.
Скриншот показывает синий прямоугольник холста, содержащий интерактивную кнопку с надписью 'Hello World!!' в центре.

Работа с макетами

Диспетчер макетов позволяет располагать компоненты в контейнере. Класс LzLayout является подклассом LzNode, который несет ответственность за расположениее представлений. Класс LzLayout – это базовый класс, который обеспечивает данную функциональность. Никогда не создавайте экземпляр этого класса напрямую, а только экземпляр его подкласса. В листинге 10 представлены подклассы LzLayout.

SimpleLayout

SimpleLayout используется для размещения компонентов рядом друг с другом по горизонтали или по вертикали. Экземпляр создается с помощью тега simplelayout, как показано ниже.

Листинг 10. SimpleLayout.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<simplelayout axis="x" spacing="4"/>
	<view align="center" valign="middle" bgcolor="silver" width="100" height="100"/>
	<view align="center" valign="middle" bgcolor="gray" width="100" height="100"/>
	<view align="center" valign="middle" bgcolor="blue" width="100" height="100"/>
</canvas>

Этот пример можно вызывать по адресу: http://localhost:8080/lps-4.0.x/layout/SimpleLayout.lzx. Результат показан на рисунке 12.

Рисунок 12. Пример макета
Скриншот с тремя смежными разноцветными квадратами на синем холсте
Скриншот с тремя смежными разноцветными квадратами на синем холсте

ResizeLayout

ResizeLayout аналогичен SimpleLayout и позволяет располагать представления по горизонтали или по вертикали. Однако с помощью ResizeLayout можно также изменять размер представлений, как показано в листинге 11.

Листинг 11. ResizeLayout.lzx
<width="450" bgcolor="#6699FF" height="200">
	<resizelayout axis="y" spacing="20"/>
	<view valign="middle" width="100" height="100" bgcolor="silver"/>
	<view valign="middle" width="100" height="100" bgcolor="gray"/>
	<view valign="middle" width="100" height="100" bgcolor="blue" 
	options="releasetolayout"/>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/layout/ResizeLayout.lzx. Результат показан на рисунке 13.

Рисунок 13. Изменение размера представлений
Скриншот с тремя смежными разноцветными прямоугольниками на синем полотне
Скриншот с тремя смежными разноцветными прямоугольниками на синем полотне

SimpleBoundsLayout

SimpleBoundsLayout располагает представления по горизонтали или вертикали, как и SimpleLayout. Однако SimpleBoundsLayout гарантирует, что при вращении ни одно представление не наложится на другое. Пример приведен в листинге 12.

Листинг 12. SimpleBoundsLayout.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<simpleboundslayout axis="x"/>
	<view valign="middle" width="100" height="100" bgcolor="silver"/>
	<view valign="middle" width="100" height="100" bgcolor="gray" rotation="30"/>
	<view valign="middle" width="100" height="100" bgcolor="blue"/>
</canvas>

Это приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/layout/SimpleBoundsLayout.lzx. Результат показан на рисунке 14.

Рисунок 14. SimpleBoundsLayout
Скриншот с тремя цветными квадратами на синем холсте, изображающими смежные представления
Скриншот с тремя цветными квадратами на синем холсте, изображающими смежные представления

ReverseLayout

ReverseLayout выстраивает представления справа налево (вдоль оси x) или снизу вверх (вдоль оси y). Листинг 13 демонстрирует приложение LZX с использованием ReverseLayout.

Листинг 13. ReverseLayout.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<reverselayout axis="x" end="false" spacing="20"/>
	<view align="center" valign="middle" width="100" bgcolor="silver"/>
	<view align="center" valign="middle" width="100" bgcolor="gray"/>
	<view align="center" valign="middle" width="100" bgcolor="blue"/>
</canvas>

Этот пример вызывается по адресу http://localhost:8080/lps-4.0.x/layout/ReverseLayout.lzx. Результат показан на рисунке 15.

Рисунок 15. Обратное расположение
Скриншот с тремя смежными цветными прямоугольниками на синем холсте
Скриншот с тремя смежными цветными прямоугольниками на синем холсте

ConstantLayout

Этот макет располагает представления одно над другим. Как и в случае SimpleLayout, нужно указать атрибут оси. Затем ContantLayout смещает каждое представление на число пикселей, указанное в параметрах xoffset и yoffset. Результатом становится каскад представлений, смещенных на эти значения.

Листинг 14. ConstantLayout.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<constantlayout axis="x" value="10"/>
	<view valign="middle" width="300" height="150" bgcolor="silver"/>
	<view valign="middle" width="200" height="80" bgcolor="gray" xoffset="-15"/>
	<view valign="middle" width="40" height="40" bgcolor="blue" xoffset="-50"/>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/layout/ConstantLayout.lzx. Результат показан на рисунке 16.

Рисунок 16. Расположение с постоянным смещением
Скриншот с вложенными друг в друга прямоугольниками разного цвета и формы
Скриншот с вложенными друг в друга прямоугольниками разного цвета и формы

WrappingLayout

WrappingLayout переносит представления, изменяя строку или столбец при выходе за пределы экрана. Пример приведен в листинге 15.

Листинг 15. WrappingLayout.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<wrappinglayout axis="x" spacing="20"/>
	<view align="center" valign="middle" bgcolor="silver" width="200" height="100"/>
	<view align="center" valign="middle" bgcolor="gray" width="200" height="100"/>
	<view align="center" valign="middle" bgcolor="blue" width="200" height="100"/>
</canvas>

Приведенное выше приложение можно вызвать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/layout/WrappingLayout.lzx. Результат показан на рисунке 17.

Рисунок 17. WrappingLayout.lzx
Скриншот с цветными прямоугольниками слишком большого размера, чтобы расположиться рядом друг с другом
Скриншот с цветными прямоугольниками слишком большого размера, чтобы расположиться рядом друг с другом

Обработка событий

Чтобы программы были более интерактивными, объекты OpenLaszlo могут вызывать события в ответ на действия пользователя, такие как buttonclick. Это делается путем записи события в обработчик событий, содержащий код, исполняемый при вызове события объектом. Существует несколько способов записать событие в обработчик событий. Один из них – присвоить событию имя обработчика событий в теге декларации объекта, как показано в листинге 16. Показанный ниже тег создает объект Window, событие onx для которого записано в обработчике событий myHandler.

Листинг 16. Window.lzx
<window name="win" onx="myHandler">

Другой подход заключается в написании метода, вложенного в тег декларации объекта, и назначении обработчика событий атрибуту события этого метода. Фрагмент, приведенный в листинге 17, связывает событие нажатия кнопки onclick с обработчиком событий в соответствующих тегах.

Листинг 17. Window.lzx
<button>
	<handler name="onclick">
		// Event handler code
	</handler>
</button>

Пример в листинге 18 демонстрирует событие onclick, вызванное нажатием кнопки, отображаемым на обработчик событий.

Листинг 18. EventWiring.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<button width="200" height="80" align="center" valign="middle">Hello Button
	<handler name="onclick">
		setAttribute("text", "Hello Button Clicked");
		setAttribute ('width', 200);
	</handler>
	</button>
</canvas>

Пример EventWiring.lxz можно выполнить, направив браузер по адресу: http://localhost:8080/lps-4.0.x/event/EventWiring.lzx. На рисунке 18 показан результат, сгенерированный первоначально, и тот, что получен после вызова события нажатием кнопки.

Рисунок 18. Обработка событий
Два скриншота с холстом и одной кнопкой'
Два скриншота с холстом и одной кнопкой'

Иначе, код обработчика событий может быть встроен в тег объекта, как показано в листинге 19.

Листинг 19. EmbeddedEventHandling.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<button width="200" height="80" align="center" valign="middle" 
		onclick="setAttribute ('text', 'Hello Button Clicked');
		setAttribute ('width', 200);">
		Hello Button
	</button>
</canvas>

Обработчики глобальных событий

Обработчик глобальных событий можно написать с помощью функций JavaScript, которые вызваются из нескольких объектов. Например, в листинге 20 определяется функция myHandler, которую можно вызвать из любого места программы.

Листинг 20. GlobalEventHandler.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<button width="200" height="80" align="center" valign="middle" id="button1" 
		onclick="globalHandler()"> Hello Button
	</button>
	<script>
		<![CDATA[
			function globalHandler () {
				button1.setAttribute ("text", "Hello Button Clicked");
				button1.setAttribute ('width', 200);
			}
		]]>
	</script>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/event/GlobalEventHandler.lzx.

Передача ссылки на объект

В OpenLaszlo можно даже передавать ссылку на объект методу, как показано в листинге 21.

Листинг 21. PassingObjectReference.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<simplelayout axis="x"/>
	<button width="200" height="80" align="center" valign="middle" id="button1" 
		onclick="globalHandler (this)"> Hello Button 1
	</button>
	<button width="200" height="80" align="center" valign="middle" id="button2" 
		onclick="globalHandler (this)"> Hello Button 2
	</button>
	<script>
		<![CDATA[
			function globalHandler (b) {
				b.setAttribute ("text", "Hello Button Clicked");
				b.setAttribute ('width', 200);
			}
		]]>
	</script>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/event/PassingObjectReference.lzx.

Добавление анимации

В общем случае анимацию объекта можно получить путем динамического изменения значений ее координат х и у. В OpenLaszlo анимация легко создается с помощью тегов animator и animatorGroup. Тег animator используется внутри объекта для выполнения движения, тогда как тег animatorGroup используется для группирования нескольких тегов animator с целью выполнения нескольких типов анимации. Приложение LZX, приведенное в листинге 22, отображает кнопку, которая движется вдоль горизонтальной линии.

Листинг 22. SimpleAnimation.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<button width="200" height="80" align="center" valign="middle" 
		text="Animated Stuff">
		<animator attribute="x" from ="0" to="300" duration="5000"/>
	</button>
</canvas>

Кнопка в приведенном выше примере проходит путь из точки х=0 в точку х=450 за 5000 мс. Этот пример можно выполнить через http://localhost:8080/lps-4.0.x/animation/SimpleAnimation.lzx. Результат показан на рисунке 19.

Рисунок 19. Простая анимация
Скриншот кнопки с надписью 'Animated Stuff' with an arrow indicating motion to the right side of the screen
Скриншот кнопки с надписью 'Animated Stuff' with an arrow indicating motion to the right side of the screen

Анимация из нескольких частей

Используя несколько тегов animator, объект можно перемещать в двух или нескольких направлениях одновременно. Он будет вращаться при движении вдоль оси x. В листинге 23 приведен код с использованием нескольких тегов animator.

Листинг 23. MultipleAnimation.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<view width="100" height="60" align="center" valign="middle" 
		resource="IBMLogo.jpg>
		<animator attribute="x" from ="0" to="450" duration="5000"/>
		<animator attribute="rotation" to="360" duration="5000"/>
	</view>
</canvas>

Кнопка в приведенном выше приложении проходит путь из точки х=0 в точку х=450 и поворачивается на 360 градусов за 5000 мс. Выполните пример, направив браузер по ссылке http://localhost:8080/lps-4.0.x/animation/MultipleAnimation.lzx. Результат показан на рисунке 20.

Рисунок 20. Сложная анимация
Скриншот с логотипом IBM в процессе движения, слегка повернутый вправо
Скриншот с логотипом IBM в процессе движения, слегка повернутый вправо

В предыдущих примерах анимация начинается сразу после загрузки сгенерированного приложения. Установив атрибут тега animator start в значение false и вызвав метод doStart объекта animator, можно сделать так, чтобы анимация запускалась по событию, такому как onClick. Это сделано в листинге 24.

Листинг 24. ManualAnimationStart.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<button width="100" height="60" valign="middle" 
		text="Start Animation" onclick="this.a.doStart()">
		<animator name="a" attribute="x" start="false"
			from ="0" to="450" duration="1000" motion="easein"/>
	</button>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/animation/ManualAnimationStart.lzx.

Повторяющаяся анимация

Атрибут repeat тега animator можно настроить так, чтобы он определял количество циклов анимации. Чтобы анимация повторялась бесконечно, присвойте ему значение Infinity. Например, приложение OpenLaszlo из листинга 25 демонстрирует анимацию, которая повторяется трижды.

Листинг 25. RepeatAnimation.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<view width="100" height="60" align="center" valign="middle" 
		resource="IBMLogo.jpg>
		<animator attribute="rotation" from ="0" to="360" duration="3000" 
			repeat="3"/>
	</view>
</canvas>

Этот пример вызывается по адресу http://localhost:8080/lps-4.0.x/animation/RepeatAnimation.lzx.

В листинге 26 показано представление, которое окружает другое представление.

Листинг 26. CircularAnimation.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<view valign="middle" align="center" bgcolor="#ddddee" width="350" height="150"/>
		<view width="40" height="40" bgcolor="silver"
			x="${ 180 + 30 * Math.cos (angle*Math.PI/180) }"
			y="${ 100 + 30 * Math.sin (angle*Math.PI/180) }">
			<attribute name="angle" value="0"/>
			<animator motion="linear" attribute="angle" from ="0"
				to="360" duration="2000" repeat="Infinity"/>
			<animator motion="linear" attribute="rotation" from ="0"
				to="360" duration="2000" repeat="Infinity"/>
	</view>
</canvas>

Этот пример вызывается по адресу http://localhost:8080/lps-4.0.x/animation/CircularAnimation.lzx. Результат показан на рисунке 21.

Рисунок 21. Круговая анимация
Скриншот с наклонным квадратиком в прямоугольном представлении
Скриншот с наклонным квадратиком в прямоугольном представлении

Использование тега animatorgroup

Для создания группы из нескольких тегов animator можно использовать тег animatorgroup. Атрибут process определяет, как работает этот тег. Чтобы все события происходили одновременно, присвойте атрибуту process значение "simultaneous". Если значение process равно "sequential", они будут происходить друг за другом. По умолчанию атрибут process имеет значение sequential. Использование тега animatorGroup иллюстрируется в листинге 27.

Листинг 27. AnimatorGroup.lzx
<canvas height="400">
	<button width="70" text="Click here">
		<animatorgroup process="sequential">
			<animator attribute="x" from ="0" to="300" duration="1000"/>
			<animator attribute="rotation" from ="0" to="90" duration="1000"/>
		</animatorgroup>
	</button>
</canvas>

Использование тега timer

Таймер – это объект, который может быть установлен для вызова метода по истечении указанного периода времени. Например, после 10-минутного бездействия пользователя может отображаться предупредительное сообщение, как показано в листинге 28.

Листинг 28. Timer.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<alert id="alertBox" width="250">10 minutes left for Completion!</alert>
	<handler name="oninit">
		var delegate = new LzDelegate (this, "showAlertBox");
		lz.Timer.addTimer (delegate, 3000);
	</handler>	
	<method name="showAlertBox">
		alertBox.open();
	</method>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/animation/Timer.lzx. Результат показан на рисунке 22.

Рисунок 22. Служба Timer
Скриншот с надписью 'Осталось 10 минут компиляции' в диалоговом окне с кнопкой ОК
Скриншот с надписью 'Осталось 10 минут компиляции' в диалоговом окне с кнопкой ОК

Еще один пример, приведенный в листинге 29, отображает цифровые часы.

Листинг 29. DigitalClock.lzx
<canvas fontsize="45" width="450" bgcolor="#6699FF" height="200">
	<text id="display" width="250" bgcolor="#ddddee" align="center" valign="middle"/>
	<handler name="oninit">
		lz.Timer.addTimer (new LzDelegate (this, "refreshClock"), 1000);
	</handler>
	<method name="refreshClock">
		lz.Timer.addTimer (new LzDelegate (this, "refreshClock"), 1000);
		var now = new Date ();
		var hour = now.getHours ();
		var minute = now.getMinutes();
		var second = now.getSeconds();
		display.setText (hour + ":" + minute + ":" + second);
	</method>

	<![CDATA[
		if (n < 10) {
			return "0" + n;
		} else {
			return n;
		}
	]]>
</canvas>

Этот пример вызывается по адресу http://localhost:8080/lps-4.0.x/animation/DigitalClock.lzx. Результат показан на рисунке 23.

Рисунок 23. Цифровые часы
Скриншот показывает время  '15:47:40'
Скриншот показывает время '15:47:40'

Создание многофункциональных компонентов

OpenLaszlo предоставляет пользователям богатый набор компонентов, которые можно легко использовать для любого приложения LZX. На рисунке 24 показана иерархия классов некоторых встроенных компонентов OpenLaszlo.

Рисунок 24. Иерархия классов компонентов
Схема дерева компонентов OpenLaszlo
Схема дерева компонентов OpenLaszlo

Slider

Компонент Slider позволяет выбрать значение, перетаскивая ползунок. Класс slider представляет собой шаблон для всех ползунков. Это прямой потомок класса Baseslider. Класс Baseslider, в свою очередь, расширяет класс Basevaluecomponent, прямой потомок класса Basecomponent. Код, приведенный в листинге 30, использует ползунок для управления прозрачностью представления.

Листинг 30. Slider.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<slider name="s" valign="middle" align="center"  height="100" 
		showvalue="true" width="200" value="50"/>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/richComponents/Slider.lzx. Результат показан на рисунке 25.

Рисунок 25. Компонент Slider
Скриншот с ползунком в центре шкалы 0-100
Скриншот с ползунком в центре шкалы 0-100

datepicker

Как предполагает его название, компонент datepicker позволяет легко выбрать дату. Данный компонент представляет класс datepicker, который является прямым потомком класса Basedatepicker. Basedatepicker – это абстрактный класс и подкласс Basecomponent. Например, код, приведенный в листинге 31, позволяет выбрать дату и отображает выбранную дату в текстовой метке.

Листинг 31. Datepicker.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<script>
		var today = new Date ();
		var lastYear = new Date (today.getFullYear () – 1,
		today.getMonth (), today.getDate ());
		var nextYear = new Date (today.getFullYear () + 1,
		today.getMonth (), today.getDate ());
	</script>
	<simplelayout axis="y" spacing="5"/>
	<datepicker earliestdate="${lastYear}"
		selecteddate="${today}"
		latestdate="${nextYear}">
		<handler name="onselecteddate">
			if ( this.selecteddate != null ) {
				display.year.setText (
				this.selecteddate.getFullYear() );
				display.month.datapath.setXPath(
				"datepicker_strings_en:/months/month[@index='" +
				this.selecteddate.getMonth() + "']/@full" );
				display.date.setText ( this.selecteddate.getDate() );
			}
		</handler>
	</datepicker>
	<view id="display">
		<text name="month" resize="true" datapath="."/>
		s<text name="date" resize="true"/>
		<text name="year" resize="true"/>
		<simplelayout axis="x" spacing="2"/>
	</view>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/richComponents/DatePicker.lzx. Результат показан на рисунке 26.

Рисунок 26. Выбор даты
Скриншот с календарем выбора даты, указывающим 1 ноября 2009 г.
Скриншот с календарем выбора даты, указывающим 1 ноября 2009 г.

Scrollbar

Компонент полосы прокрутки представлен классом scrollbar. Это подкласс Basescrollbar, который является прямым подклассом Basecomponent. Код в листинге 32 демонстрирует приложение LZX, которое использует одну полосу прокрутки по вертикали и одну по горизонтали.

Листинг 32. ScrollBar.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<view name="main" width="100" height="100" clip="true">
		<text multiline="true">
			OpenLaszlo is an open source platform invented by Laszlo Systems, 
			a company based in San Mateo, California for the development and
			deployment of rich Internet based applications.It is released 
			under the Open Source Initiative-certified Common Public License. 
			One of the greatest challenge faced by Rich Interactive 
			Applications (RIA) developers today is that of Browser 
			Compatibility. Since OpenLaszlo is based on the famous Java 
			paradigm of write-once-run-everywhere, it ensures that 
			applications based on OpenLaszlo runs uniformly in various 
			browsers in multiple operating systems. 
		</text>
		<scrollbar axis="y"/>
		<scrollbar axis="x"/>
	</view>
</canvas>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/richComponents/ScrollBar.lzx. Результат показан на рисунке 27.

Рисунок 27. Scrollbar
Скриншот с текстом в окне с горизонтальной и вертикальной полосами прокрутки
Скриншот с текстом в окне с горизонтальной и вертикальной полосами прокрутки

Tabs и Tabpane

Tab – это представление, которое может содержать панели вкладок. У каждой вкладки есть заголовок и могут быть другие компоненты. Вкладка и панели вкладок – хороший способ организовать компоненты в небольшую область, как показано в листинге 33.

Листинг 33. TabbedPane.lzx
<canvas width="450" bgcolor="#6699FF" height="300">
	<form inset_top="10">
		<tabs tabalign="right">
			<tabpane bgcolor="silver"  text="Name" tabwidth="80">
				<simplelayout axis="y"/>
				<text>Customer Name</text>
				<edittext name="customerName"/>
				<text>Email</text>
				<edittext name="email"/>
				<radiogroup name="customerType">
					<radiobutton>Silver</radiobutton>
					<radiobutton>Gold</radiobutton>
				</radiogroup>
				<button>Submit</button>
			</tabpane>
			<tabpane bgcolor="silver" text="Address" tabwidth="80">
				<simplelayout axis="y"/>
				<text>Address</text>
				<edittext name="address"/>
				<text>City</text>
				<edittext name="city"/>
				<text>State</text>
				<edittext name="astate"/>
				<text>Pin Code</text>
				<edittext name="pincode"/>
			</tabpane>
		</tabs>
	</form>
</canvas>

Вызовите приведенный выше пример, перейдя по ссылке http://localhost:8080/lps-4.0.x/richComponents/TabbedPane.lzx. Результат показан на рисунке 28.

Рисунок 28. TabbedPane
Скриншот с двумя вкладками, Имя и Адрес
Скриншот с двумя вкладками, Имя и Адрес

Tree

Дерево – это компонент OpenLaszlo для отображения иерархических данных, таких как данные XML. Класс tree представляет собой дерево и является подклассом Basetree. Basetree – это дочерний класс Basecomponent. В листинге 34 показано, как создать и использовать дерево.

Листинг 34. TreeView.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
	<view valign="middle" align="center" width="200" height="150">
		<tree open="true" text="OpenLaszlo Article">
			<tree text="Chapter 1: Overview" isleaf="true"/>
			<tree open="true" text="Chapter 2: Basic Components">
				<tree text="Section 1: Slider" isleaf="true"/>
				<tree text="Section 2: ScrollBar" isleaf="true"/>
			</tree>
		</tree>
</view>
</canvas>

Для выполнения этого примера используйте ссылку http://localhost:8080/lps-4.0.x/richComponents/TreeView.lzx . Результат показан на рисунке 29.

Рисунок 29. Представление дерева
Скриншот показывает графическое дерево папок, подпапок и объектов
Скриншот показывает графическое дерево папок, подпапок и объектов

Работа с данными XML

OpenLaszlo может использоваться для отображения данных и манипулирования данными с помощью XPath, языка для извлечения данных из XML-документов. Класс LzDataset используется для хранения данных XML и получения данных по запросам HTTP GET или POST. На рисунке 30 показана иерархия классов LzDataset.

Рисунок 30. Иерархия классов LzDataset
Дерево с узлом LzNode в вершине.  Влево отходят ветви lzDataNode, LzDataElement и LzDataset

Данными из набора данных можно манипулировать, используя <datapath> и <datapointer>.

DataPath

С помощью XPath DataPath можно использовать для доступа к данным, содержащимся в наборе данных, как показано ниже. Пример применения DataPath приведен в листинге 35.

Листинг 35. Использование DataPath.lzx
<canvas width="600" bgcolor="#6699FF" height="220">
	<dataset name="myData" request="true" type="http" src="data.xml"/>
	<grid height="100" valign="middle" datapath="myData:/company" 
		contentdatapath="department">
		<gridcolumn width="100">
			Name
			<text datapath="name/text ()"/>
		</gridcolumn>
		<gridcolumn width="100">
			ID
			<text datapath="id/text ()"/>
		</gridcolumn>
		<gridcolumn width="200">
			Description
			<text datapath="desc/text ()"/>
		</gridcolumn>
		<gridcolumn width="100">
			Location
			<text datapath="location/text ()"/>
		</gridcolumn>
		<gridcolumn width="70">
			<view datapath="position ()">
			<button text="delete">
				<handler name="onclick">
					parent.datapath.deleteNode ();
				</handler>
			</button>
			</view>
		</gridcolumn>
	</grid>
</canvas>

Листинг 36 демонстрирует содержимое data.xml.

Листинг 36. Содержимое data.xml
<company>
	<department headCount="19">
		<name>HR</name>
		<id>Comp-HR-01</id>
		<location>First-Flr</location>
		<desc>Looks after Human resources</desc>
	</department>
	<department headCount="200">
		<name>Manufacturing</name>
		<id>Comp-MFG-02</id>
		<location>Ground-Flr</location>
		<desc>Manufactures Components</desc>
	</department>
	<department headCount="65">
		<name>Marketing</name>
		<id>Comp-Mktg-01</id>
		<location>Third-Flr</location>
		<desc>Markets the product</desc>
	</department>
</company>

Приведенное выше приложение можно скомпилировать и вызывать, направив браузер по адресу: http://localhost:8080/lps-4.0.x/data/UsingDataPath.lzx. Результат показан на рисунке 31.

Рисунок 31. Использование DataPath
Скриншот с представлением данных в стиле электронной таблицы
Скриншот с представлением данных в стиле электронной таблицы

DataPointer

DataPointer выступает в качестве курсора в наборе данных. DataPointer можно использовать для последовательного перемещения по записям, содержащимся в наборе данных. Листинг 37 иллюстрирует, как использовать DataPointer.

Листинг 37. UsingDataPointer.lzx
<canvas width="450" bgcolor="#6699FF" height="200">
  <simplelayout spacing="5"/>
  <script>
    var isLast = false;
  </script>

  <dataset name="mydata" request="true" type="http" src="data.xml"/>

  <alert name="myalert"/>

  <view id="tt" height="60" valign="middle" width="450" font="verdana" fontsize="20">
	<text name="output" y="30" align="center"/>
  </view>

  <view height="150" align="center" valign="middle" >
    <simplelayout  axis="x" spacing="4" />
    <datapointer id="mydp" xpath="mydata:/company/department[1]"/>
    <button font="verdana" fontsize="15"> Next Record
      <handler name="onclick">
		isFirst = false;
		var s = mydp.xpathQuery('name/text()');
		if(isLast){
			s = 'Last Record!';
		}
		if(!mydp.selectNext()){
		   isLast = true;
		}
        tt.output.setText(s);
      </handler>
    </button>
  </view>
</canvas>

Этот пример вызывается по адресу http://localhost:8080/lps-4.0.x/data/UsingDataPointer.lzx. Результат показан на рисунке 32.

Рисунок 32. Использование DataPointer
Скриншот с названием 'Производство' и кнопкой 'Следующая запись'
Скриншот с названием 'Производство' и кнопкой 'Следующая запись'

Отладка

При разработке программного обеспечения хорошие инструменты отладки помогают сделать приложения более надежными и безошибочными. OpenLaszlo оснащен усовершенствованным инструментарием отладки, который позволяет разработчику просматривать сообщения времени выполнения, оценивать значения переменных и т.д.

Чтобы вывести на экран окно отладки, выполните следующие действия:

  • Установите значение true атрибута debug тега canvas: <canvas debug="true">
  • Добавьте параметр запроса debug=true в конечный URL, используемый для обращения к приложению OpenLaszlo. Например:
    http://localhost:8080/lps-4.0.x/app14/debugTest.lzx?debug=true
  • Нажмите кнопку Debug и кнопку Compile.

В качестве примера в листинге 38 показана кнопка на холсте.

Листинг 38. DebugButton.lzx
<canvas width="450" bgcolor="#6699FF" height="800">
	<button id="buttonId" width="200" height="80" align="center" valign="middle">
		Hello World!!</button>
</canvas>

Приведенное выше приложение можно вызвать с включенным инструментом отладки, открыв его URL с параметром debug=true: http://localhost:8080/lps-4.0.x/debug/DebugButton.lzx?debug=true. Это позволит загрузить приложение и открыть окно отладчика Laszlo с полем ввода текста в нижней части.

Наберите ID кнопки buttonId и нажмите Enter. Вводимый текст будет отображаться зеленым цветом, а объект отладчик выведет в виде голубой гиперссылки.

Затем нажмите на ссылку объекта в окне отладчика <<button>#0| #buttonId>>. Отладчик выведет атрибуты объекта JavaScript, как показано на рисунке 33.

Рисунок 33. Окно отладчика
Скриншот с окном отладчика в действии с перечнем различных параметров, связанных с запущенными приложениями
Скриншот с окном отладчика в действии с перечнем различных параметров, связанных с запущенными приложениями

При вводе выражения JavaScript в отладчик выражение будет компилироваться с распечаткой результата. Например, buttonId.width возвратит значение атрибута ширины. Аналогично, ввод команды buttonId.setAttribute('width', 400) изменит ширину отображаемой на холсте кнопки. Окно Debugger представляет собой экземпляр класса Debug, который является подклассом LzView. Таким образом, все атрибуты класса LzView имеются также в классе Debug.

Ниже приводятся методы, определенные в классе Debug:

  • backtrace (frameCount) – Копирует снимок текущего состояния стека вызовов в объект LzBacktrace, который затем можно распечатать или проверить. Этот способ доступен только в том случае, если приложение скомпилировано с параметром -option debugBacktrace=true. Аргумент frameCount определяет количество кадров, которые нужно исключить из трассировки. (Значение по умолчанию 1).
  • error (control, args) – Выводит сообщение об ошибке на консоль. Аргумент control определяет элемент управления форматом, а аргумент args - любое количество аргументов.
  • format (control, args) – Форматирует выход с использованием метода formatToString. Аргумент control определяет элемент управления форматом, а аргумент args – любое количество аргументов.
  • formatToString (control, args) – Этот метод аналогичен функции printf в языке C. Аргумент control определяет элемент управления форматом, а аргумент args – любое количество аргументов.
  • inspect (object, reserved) – Отображает свойства указанного объекта на консоли отладки. Аргумент reserved зарезервирован для использования в будущем.
  • log (message) – Отправляет сообщение в файл журнала регистрации событий.
  • monitor (object, property) – Контролирует указанное свойство указанного объекта. При каждом изменении значения свойства в окне отладчика будет отображаться соответствующее сообщение.
  • trace (object, method) – Контролирует использование указанного метода для указанного объекта. Каждый раз, когда вызывается метод, в окне отладчика будет отображаться сообщение.
  • unmonitor (object, property) – Отменяет контроль указанного свойства указанного объекта.
  • untrace (object, method) – Отменяет контроль использования указанного метода для указанного объекта.

Окно отладчика можно использовать также для оценки глобальных переменных и выражений JavaScript, а также для выполнения операторов JavaScript. Evaluator – это текстовое поле с кнопкой EVAL в нижней части окна отладчика.

Заключение

OpenLaszlo это открытая платформа разработки для создания многофункциональных Web-приложений, написанных на LZX, языке на основе XML со встроенным JavaScript.

Однако в отличие от многих решений Ajax, приложения OpenLaszlo совместимы с различными браузерами. Это стало возможным благодаря технологии компилятора OpenLaszlo, который заботится о деталях времени выполнения, позволяя разработчику сосредоточиться на поведении/логике приложения и его внешнем виде. Это делает OpenLaszlo настоящей платформой типа "написал однажды – работает везде". OpenLaszlo поддерживает многофункциональную модель изображений с большим количеством встроенных и повторно используемых компонентов, а также передовые инструменты редактирования текста и графики WYSIWYG.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source, WebSphere
ArticleID=833095
ArticleTitle=OpenLaszlo - платформа для быстрого создания и развертывания многофункциональных интернет-приложений
publish-date=09042012