UI плагин (plugin) в Showcase

Материал из Course Orchestra
Перейти к: навигация, поиск
Showcase

Создание решений на КУРС:Showcase

Общие сведения

Элемент информационной панели типа UI плагин предназначен для подключения произвольных визуальных внешних JavaScript и Flash компонент. Компонента должна быть подготовлена для подключения к Showcase следующим образом:

  • Каждый плагин должен быть помещен в отдельный каталог в general\plugins\${pluginname}, где ${pluginname} - имя плагина
  • Каждый плагин принимает на вход один или несколько параметров (JSON, строковых, числовых...), которые могут содержать данные для отображения, шаблон, другие параметры. Например, имеет смысл разделить динамические данные и “статические” параметры для их отображения. Рекомендуется поместить в папку с плагином файл example.txt, содержащий примерный формат параметров плагина.
  • В папке с плагином должен быть файл-адаптер с именем ${pluginname}.js.
  • JS адаптер плагина должен содержать как минимум одну функцию: create${pluginname} (parentId, data, …), где ${pluginname} – имя компоненты (первая буква имени плагина должна быть с большой буквы, например createNameplugin), parentId – строка-идентификатор родительского HTML элемента (как правило, это div), data – данные в формате JSON.
  • Плагин должен подстраиваться под размеры родительского контейнера, идентификатор которого в DOM страницы передается в функцию create${pluginname}
  • Если подключаемый плагин - это flash, то необходимо передать файлу swf свойство wmode = "opaque". Это связано с тем, что только в этом случае плагин не будет перекрывать всплывающие окна в Showcase (в качестве примера можно посмотреть файл адаптера flashD.js из тестового набора).
  • Плагины могут зависеть от UI библиотек. UI библиотека - это достаточно крупный JavaScript или CSS-фреймворк, который использует плагины при работе. Примером библиотек являются ExtJS, jQuery... Библиотека должна находиться в каталоге general\libraries\${libname}, где ${libname} - имя библиотеки.
  • Зависимости плагинов указываются в файле general\plugins\${pluginname}\import.txt. Каждая строчка в таком файле - эти имя библиотеки, от которой зависит плагин.
  • Библиотеки подключаются к приложению путем добавления на главную страницу приложения элементов JavaScript и CSS файлов. Список подключаемых элементов JavaScript указывается в файле general\libraries\${libname}\scriptList.txt. Список подключаемых CSS указывается в файле general\libraries\${libname}\styleList.txt. Каждая строка должна содержать путь к одному файлу. Путь указывается относительно корневого каталога библиотеки.
  • В случае питона и челесты функции, формирующие данные для плагина, должны возвращать данные в виде xml, а не json!

Внимание: библиотека dojo целиком включена в Showcase. Указывать ее в зависимостях не нужно!

Замечание: Начиная с версии Showcase 3.0.1.3572, папки plugins и libraries при копировании на Tomcat копируются в папку solutions\general, в то время как в старых версиях Showcase копирование происходило в папки, соответствующие каждой из userdat в папке solutions, что вызывало избыточное дублирование. Теперь эта ситуация поправлена.

Зависимость между Showcase, плагинами и библиотеками показана на следующей схеме.


Showcase-plugins-components5.png

Шаблон хранимой процедуры

Шаблон процедуры такой же как у вебтекста:

CREATE PROC 
	@main_context varchar(MAX)='',
	@add_context varchar(MAX)='',
	@filterinfo xml='',
	@session_context xml='',
	@element_Id varchar(MAX)='',
	@data xml ='' output,
        @settings xml ='' output

где в параметре @data находятся данные для передачи в плагин, в параметре @settings - настройки плагина для Showcase (события, размеры).

Алгоритм обработки данных

Алгоритм обработки данных состоит из 4 этапов:

  1. Запуск хранимой процедуры или другого источника данных;
  2. XSL преобразование данных;
  3. Пост-обработка данных в Jython;
  4. Адаптация данных для используемой компоненты в JS файле-адаптере плагина


Алгоритм показан на следующей схеме.

Externalcomponent.png

Предполагается, что источник данных (хранимая процедура) передает данные в формате XML, после чего они преобразуются в формат плагина (например, JSON) с помощью XSL-трансформации или Jython-скриптом.

Структура settings

См. схему pluginsettings.xsd

<properties height="100px" width="200px">
    <action>
	default action
    </action>
    <event name="single_click" linkId="linkId">
	<action>
            ...........
        </action>
    </event>
</properties>

где height и width - высота и ширина для плагина.

Обработка событий (кликов и др.) в UI-Plugin

В Showcase доступно задание событий (например, при кликах, при прокрутке мышки и пр.) привязанных к элементам интерфейса внешнего подключаемого плагина. В общем, набор событий, который можно обрабатывать внутри подключенной компоненты зависит от самой внешней компоненты (что логично - компоненту пишут сторонние разработчики). Компонента сама должна обрабатывать (ловить) необходимые UI события.

Для обеспечения связи между действиями внутри плагина и изменениями (обновление, перерисовка с нужным контекстом) в существующих элементах Showcase (grid, webtext, chart и пр.) - т.е. для задания привычных нам действий Showcase - необходимо:

  1. В настройках settings (см Структура settings в UI-плагин) указать action (см. Задание и структура действия в Showcase), или несколько action с разными linkId (linkId-обязательный атрибут).
  2. Внести изменения во внешнюю компоненту (если необходимо) в функцию обработки события. В данной функции, помимо прочих действий (если они необходимы), требуется вызвать java script процедуру в формате.
gwtPluginFunc(''divId'', ''linkId'');

где divId - это id элемента div в который помещен плагин (в формате: dpe_[имя информационной панели без расширения]__E40F6599F809__[id элемента плагин]_plugin), а linkId - это id события, которое прописано в settings.

Данная функция автоматически определяется в DOM-модели главной страницы приложения.

Plugin "Календарь"

  • Находится в userdatas\general\plugins\calendar
  • В датапанели задается как
	<tab id="04" name="Календарь">
		<element id="0101" type="plugin" proc="pluginCalendarInfo"
			plugin="calendar">
			<proc id="010101" name="plugin/handleCalendar.py" type="POSTPROCESS" />
		</element>
		<element id="5" type="webtext" proc="webtext_filter_and_add" />		
	</tab>
  • В процедуре задается как
ALTER PROCEDURE [dbo].[pluginCalendarInfo]
    @main_context varchar(512) ='',
    @add_context varchar(512) ='',
    @filterinfo xml='',
    @session_context xml ='',
    @element_id varchar(512) ='',    
	@params xml='',
    @data xml output,
    @settings xml output
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;


set    @data=CAST(
'<root>

<metadata date="new Date(2012, 0, 5)" minHours="10" maxHours="20" 
          dateInterval="month" dateIntervalSteps="1" 
          style="position:relative;width:100%;height:700px;" editable="false" toolbarVisible="true"
          timeSlotDuration="20"
/>

<data>
<event className="''Calendar1''" id="''id1''" summary="''Событие 1''" startTime="new Date(2012, 0, 2, 10, 0)" endTime="new Date(2012, 0, 2, 12, 15)" allDay=""/>
<event className="''Calendar2''" id="''id2''" summary="''Событие 2''" startTime="new Date(2012, 0, 3, 15, 0)" endTime="new Date(2012, 0, 4, 12, 45)" allDay=""/>
<event className="''Calendar3''" id="''id3''" summary="''Событие 3''" startTime="new Date(2012, 0, 4, 0, 0)" endTime="new Date(2012, 0, 5, 23, 59)" allDay="true"/>
</data>

<buttons>
	<button id="''previousButton''" hide="false"/>
	<button id="''nextButton''" hide="false"/>
	<button id="''todayButton''" hide="false"/>
	<button id="''dayButton''" hide="false"/>
	<button id="''fourDaysButton''" hide="false"/>
	<button id="''weekButton''" hide="false"/>
	<button id="''monthButton''" hide="false"/>
	<button id="''sixMonthButton''" hide="false"/>
</buttons>



</root>' as xml)

set @settings='<properties width="100%" height="100%">                                    

                       <event name="single_click" linkId="id1">
                        <action >
                            <main_context>current</main_context>                        
							              <datapanel type="current" tab="current">
                                <element id="5">
	                                <add_context>id1</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     

                       <event name="single_click" linkId="id2">
                        <action >
                            <main_context>current</main_context>                        
							              <datapanel type="current" tab="current">
                                <element id="5">
	                                <add_context>id2</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     

                       <event name="single_click" linkId="id3">
                        <action >
                            <main_context>current</main_context>                        
							              <datapanel type="current" tab="current">
                                <element id="5">
	                                <add_context>id3</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     

                    </properties>'

END

где атрибуты <metadata> задают поведение календаря в целом:

    • date - текущая дата,
    • minHours - начало рабочего дня,
    • maxHours - окончание рабочего дня,
    • dateInterval - интервал дат,
    • style - стиль отображения,
    • editable - возможность редактирования пользователем,
    • toolbarVisible - видимость тулбара,
    • timeSlotDuration - интервал сетки (значение по умолчанию 15)

Атрибуты <event> задают свойства конкретного события:

    • id - идентификатор,
    • className - имя класса стиля,
    • summary - название события,
    • startTime - время начала,
    • endTime - время окончания,
    • allDay - признак повторяющегося события

Атрибуты <button > задают свойства кнопки тулбара:

    • hide - необходимость скрыть кнопку
  • Пример функции постобработки
# coding: utf-8
from ru.curs.showcase.core.jython import JythonProc, JythonDTO
from ru.curs.showcase.util.xml import XMLUtils
from org.xml.sax.helpers import DefaultHandler
from ru.curs.showcase.util import TextUtils

# init vars
data = None
resultMetadata = None
resultData = None
resultButtons = None


class myHandler(DefaultHandler):
    def startElement(self, namespaceURI, lname, qname, attrs):
        global resultMetadata
        global resultData
        global resultButtons
        if (qname == "metadata"):
            resultMetadata = u"{date: %s, minHours: %s, maxHours: %s, dateInterval: '%s', dateIntervalSteps: '%s', style: '%s', editable: %s, toolbarVisible: %s, timeSlotDuration: %s}" % (attrs.getValue('date'), attrs.getValue('minHours'), attrs.getValue('maxHours'), attrs.getValue('dateInterval'), attrs.getValue('dateIntervalSteps'), attrs.getValue('style'), attrs.getValue('editable'), attrs.getValue('toolbarVisible'), attrs.getValue('timeSlotDuration'))
        if (qname == "event"):
            resultData += u"{id: %s, summary: %s, startTime: %s, endTime: %s, allDay: '%s', className: %s}," % (attrs.getValue('id'), attrs.getValue('summary'), attrs.getValue('startTime'), attrs.getValue('endTime'), attrs.getValue('allDay'), attrs.getValue('className'))
        if (qname == "button"):
            resultButtons += u"{id: %s, hide: %s}," % (attrs.getValue('id'), attrs.getValue('hide'))
            

class handleCalendar(JythonProc):

    def postProcess(self, context, elId, adata):
        global data
        data = adata
        return mainproc()

def mainproc():
    global resultMetadata
    global resultData
    global resultButtons    
    resultData = u'['
    resultButtons = u'['
    parser = XMLUtils.createSAXParser()
    stream = TextUtils.stringToStream(data)
    parser.parse(stream, myHandler())
    resultData += u']'
    resultButtons += u']'    
    result = u"{metadata: "+resultMetadata+u", data: "+resultData+u", buttons: "+resultButtons+u"}"  
    return JythonDTO([result])

if __name__ == "__main__":
    from org.python.core import codecs
    codecs.setDefaultEncoding('utf-8')
    mainproc()
  • Пример задания стилей событий
.claro .dojoxCalendarEvent.Calendar1 .bg {
  background-color: #00AA00 !important;
}
.claro .dojoxCalendarEvent.Calendar1.Hovered .bg {
  background-color: #00FF00 !important;
}
.claro .dojoxCalendarEvent.Calendar1.Selected .bg {
  background-color: #004400 !important;
}
.claro .dojoxCalendarEvent.Calendar2 .bg {
  background-color: #0000AA !important;
}
.claro .dojoxCalendarEvent.Calendar2.Hovered .bg {
  background-color: #0000FF !important;
}
.claro .dojoxCalendarEvent.Calendar2.Selected .bg {
  background-color: #000044 !important;
}
  • В календаре доступны следующие события
			    	calendar.on("itemClick", function(e){
			    		gwtPluginFunc(parentId, e.item.id);
			    	});
			    	
			    	calendar.on("gridDoubleClick", function(e){
			    		gwtPluginFunc(parentId, "addItem", e.date.toString(), "ADD_CONTEXT");			    		
			    	});
					
			    	calendar.on("onItemEditBegin", function(e){
			    		gwtPluginFunc(parentId, e.item.id + "Delete");
			    	});

где

    • itemClick - клик по событию,
    • gridDoubleClick - двойной клик по календарю (используется для добавления события). При этом, в addcontext в ф-цию gwtPluginFunc передается дата, на которую пришелся клик,
    • onItemEditBegin - начало редактирования события (используется для удаления события).

Plugin "Навигатор"

Выполнен на базе dojo компонента AccordionContainer, в каждой группе которого находится tree-dgrid.

  • Находится в userdatas\general\plugins\navigator
  • В датапанели задается как
	<tab id="05" name="Навигатор">
		<element id="051" type="plugin" proc="pluginNavigatorInfo"
			plugin="navigator">
			<proc id="052" name="plugin/handleNavigator.py" type="POSTPROCESS" />
		</element>
		<element id="053" type="webtext" proc="webtext_filter_and_add" />		
	</tab>
  • В процедуре задается как
ALTER PROCEDURE [dbo].[pluginNavigatorInfo]
    @main_context varchar(512) ='',
    @add_context varchar(512) ='',
    @filterinfo xml='',
    @session_context xml ='',
    @element_id varchar(512) ='',    
	@params xml='',
    @data xml output,
    @settings xml output
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;


set    @data=CAST(
'

  <navigator afterReloadAction="true">

      <group id="0" name="Тестовая группа"
             icon="resources/internal/favicon32.png" classNameTitle="class1" styleTitle="height:37px; font-size: 11pt;" 
      >
      </group>

      <group id="00" name="Фичи" open="true"
             icon="resources/internal/favicon32.png" classNameTitle="class1" styleTitle="height:37px; font-size: 11pt;" 
             classNameGrid="class2"
             classNameColumn="class3" styleColumn=""
      >

         <level1 id="07" name="7-й этап"/>
         <level1 id="08" name="8-й этап"  open="true" closeIcon="resources/internal/TreeGridJointClose.gif" openIcon="resources/internal/TreeGridJointOpen.gif" leafIcon="resources/internal/TreeGridLeafNode.png">
            <level2 id="0801" name="8-й этап, 1-я неделя" classNameRow="class4"/>
            <level2 id="0802" name="8-й этап, 2-я неделя"  leafIcon="resources/internal/TreeGridLeafNode.png"/>

            <level2 id="0803" name="8-й этап, 3-я неделя"  open="true">
							<level3 id="08031" name="8-й этап, 3-я неделя, 1-й день" selectOnLoad="true"/>
            </level2>

            <level2 id="0804" name="8-й этап, 4-я неделя">
							<level3 id="08041" name="8-й этап, 4-я неделя, 1-й день"/>
	    </level2>

            <level2 id="0805" name="8-й этап, 5-я неделя"/>
         </level1>
         <level1 id="09" name="9-й этап"  closeIcon="resources/internal/TreeGridJointClose.gif" openIcon="resources/internal/TreeGridJointOpen.gif" leafIcon="resources/internal/TreeGridLeafNode.png">
            <level2 id="0901" name="9-й этап, 1-я неделя"/>
            <level2 id="0902" name="9-й этап, 2-я неделя"/>
            <level2 id="0903" name="9-й этап, 3-5 недели" />
         </level1>
      </group>

      <group id="1" name="Балансы продовольственных ресурсов" hide="false"
             icon="resources/internal/favicon32.png" classNameTitle="" styleTitle="height:37px; font-size: 11pt;" 
      >
      </group>
      <group id="2" name="Регионы" 
             icon="resources/internal/favicon32.png" classNameTitle="" styleTitle="height:37px; font-size: 11pt;" 
      >
         <level1 id="08" name="8-й этап"  open="true" closeIcon="resources/internal/TreeGridJointClose.gif" openIcon="resources/internal/TreeGridJointOpen.gif" leafIcon="resources/internal/TreeGridLeafNode.png">
            <level2 id="0801" name="8-й этап, 1-я неделя"/>
            <level2 id="0802" name="8-й этап, 2-я неделя"  leafIcon="resources/internal/TreeGridLeafNode.png"/>

            <level2 id="0803" name="8-й этап, 3-я неделя"  open="true">
							<level3 id="08031" name="8-й этап, 3-я неделя, 1-й день" selectOnLoad="true"/>
            </level2>

            <level2 id="0804" name="8-й этап, 4-я неделя">
							<level3 id="08041" name="8-й этап, 4-я неделя, 1-й день"/>
     	    </level2>

            <level2 id="0805" name="8-й этап, 5-я неделя"/>
         </level1>
         <level1 id="09" name="9-й этап"  closeIcon="resources/internal/TreeGridJointClose.gif" openIcon="resources/internal/TreeGridJointOpen.gif" leafIcon="resources/internal/TreeGridLeafNode.png">
            <level2 id="0901" name="9-й этап, 1-я неделя"/>
            <level2 id="0902" name="9-й этап, 2-я неделя"/>
            <level2 id="0903" name="9-й этап, 3-5 недели" />
         </level1>
      </group>
   </navigator>

' as xml)

set @settings='<properties width="300px" height="700px">                                    

                       <event name="single_click" linkId="08031">
                        <action >
                            <main_context>current</main_context>                        
							              <datapanel type="current" tab="current">
                                <element id="053">
	                                <add_context>08031</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     


...

                    </properties>'

END
  • Настройки навигатора
    • afterReloadAction - нужно ли выполнять action для выделенного элемента после отрисовки навигатора
  • Настройки группы
    • id - идентификатор,
    • name - название,
    • open - указывает на то, что группа должна быть открыта,
    • icon - картинка, которая будет показываться в заголовке группы,
    • classNameTitle - имя класса стиля заголовка группы,
    • styleTitle - стиль заголовка группы,
    • classNameGrid - имя класса стиля грида,
    • classNameColumn - имя класса стиля ячеек грида,
    • styleColumn - имя класса стиля ячеек грида
  • Настройки уровня
    • id - идентификатор,
    • name - название,
    • open - указывает на то, что уровень должен быть открыт,
    • closeIcon, openIcon, leafIcon - картинки для закрытого/открытого/"без потомков" уровня (по аналогии с tree-dgrid'ом),
    • classNameRow - имя класса стиля строчки грида, соответствующего данному уровню,
    • selectOnLoad - указывает на то, что уровень должен быть выделен
  • Для того, чтобы указать, что некоторый уровень должен быть открыт/выделен, необходимо явно задать, что его parent'ы должны быть открыты (уровни и группа)
  • В файл css\internalShowcase.css добавлены стили, необходимые для корректной отрисовки навигатора
.plugin-navigator-grid {
   	height: 99%  !important  ;
}

.plugin-navigator-grid-column {
	  border: none !important ;
}
  • Функция постобработки представляет собой преобразование xml-данных в json-данные с помощью стандартного конвертера Showcase
# coding: utf-8
from ru.curs.showcase.util import XMLJSONConverter
from ru.curs.showcase.core.jython import JythonProc, JythonDTO

# init vars
data = None

class handleNavigator(JythonProc):

    def postProcess(self, context, elId, adata):
        global data
        data = adata
        return mainproc()

def mainproc():
    result = XMLJSONConverter.xmlToJson(data)
    return JythonDTO([result])


if __name__ == "__main__":
    from org.python.core import codecs
    codecs.setDefaultEncoding('utf-8')
    mainproc()

Частичное обновление

Указание, что плагин должен быть обновлен частично передается через action. Добавлен атрибут partial_update у действия и у отдельных элементов действия. Указывает на то, что нужно выполнить частичное обновление всех или отдельных элементов панели. Значение атрибута у действия перекрывается значениями атрибута элементов. Примечание: в настоящее время учитывается только для JS-гридов и плагинов, для остальных элементов игнорируется.

                        <action partial_update="false">
                            <main_context>current</main_context>                        
                            <datapanel type="current" tab="current">

                                <element id="051"  partial_update="true">
	                                <add_context>add</add_context>
                                </element>                                                             
                                
                            </datapanel>
                        </action>
                       </event>
  • Если задано частичное обновление, то вызывается функция адаптера создания плагина, но div, в котором отрисовывается плагин предварительно не очищается.
  • При этом, свойство keep_user_settings для плагинов не имеет смысла.

Plugin "Офисный тулбар"

  • Сделан на основе jQuery и GPL - версии "jQuery EasyUI".
  • Эти библиотеки находятся в
    • userdatas\general\js\clientextlib\jquery -- основная библиотека jQuery,
    • userdatas\general\js\clientextlib\jquery-easyui -- "jQuery EasyUI"
    • userdatas\general\js\clientextlib\jquery-easyui-ribbon -- Ribbon-Extension библиотеки "jQuery EasyUI".

При старте томката, согласно общим правилам, они копируются в директорию js развертки Showcase

  • Библиотеки подключаются статическим образом, поэтому в файле app.properties конкретной юзердаты необходимо указать
 import.static.external.css = /jquery-easyui/themes/default/easyui.css,/jquery-easyui/themes/icon.css,/jquery-easyui-ribbon/ribbon.css,/jquery-easyui-ribbon/ribbon-icon.css
 import.static.external.js.libraries = /jquery/jquery.min.js,/jquery-easyui/jquery.easyui.min.js,/jquery-easyui-ribbon/jquery.ribbon.js
  • Сам плагин тулбара находится в userdatas\general\plugins\toolbar
  • В датапанели задается как
	<tab id="03_" name="Офисный ToolBar">
		<element id="0301_" type="plugin" proc="pluginToolBarInfo"
			plugin="toolbar">
			<proc id="030101_" name="plugin/handleToolBar.py" type="POSTPROCESS" />
		</element>
		<element id="053_" type="webtext" proc="webtext_filter_and_add" />		
	</tab>
  • В процедуре задается как
ALTER PROCEDURE [dbo].[pluginToolBarInfo]
    @main_context varchar(512) ='',
    @add_context varchar(512) ='',
    @filterinfo xml='',
    @session_context xml ='',
    @element_id varchar(512) ='',    
	@params xml='',
    @data xml output,
    @settings xml output
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;


set    @data=CAST(
'
<data>

	<selected withoutQuotes="true">0</selected>

	<tabs>
		<groups>
			<title>Clipboard</title>
			<tools>
				<size>large</size>
				<text>Paste</text>
				<iconAlign>top</iconAlign>
				<name>paste</name>
				<type>splitbutton</type>
				<menuItems>
					<iconCls>icon-paste</iconCls>
					<text>Paste</text>
					<name>paste</name>
				</menuItems>
				<menuItems>
					<iconCls>icon-paste</iconCls>
					<text>Paste Special...</text>
					<name>paste-special</name>
				</menuItems>
				<iconCls>icon-paste-large</iconCls>
			</tools>
			<tools>
				<type>toolbar</type>
				<tools>
					<iconCls>icon-cut</iconCls>
					<text>Cut</text>
					<name>cut</name>
				</tools>
				<tools>
					<iconCls>icon-copy</iconCls>
					<text>Copy</text>
					<name>copy</name>
				</tools>
				<tools>
					<iconCls>icon-format</iconCls>
					<text>Format</text>
					<name>format</name>
				</tools>
				<dir>v</dir>
			</tools>
		</groups>
		<groups>
			<title>Font</title>
			<tools>
				<type>toolbar</type>
				<tools>



					<editable withoutQuotes="true">false</editable>
					<panelHeight>auto</panelHeight>
					<width>116</width>
					<data>
						<text>Arial</text>
						<selected>True</selected>
					</data>
					<data>
						<text>Century</text>
					</data>
					<data>
						<text>Tahoma</text>
					</data>
					<valueField>text</valueField>
					<textField>text</textField>
					<type>combobox</type>


          <onSelect withoutQuotes="true">function(record){gwtPluginFunc(''parentId'',record.text);}</onSelect>


<!--
          <onSelect withoutQuotes="true">function(record){gwtPluginFunc(''dpe_Calendar__E40F6599F809__0301__plugin'',record.text);}</onSelect>
-->


				</tools>
				<tools>
					<editable withoutQuotes="true">false</editable>
					<panelHeight>auto</panelHeight>
					<width>50</width>
					<data>
						<text>8</text>
					</data>
					<data>
						<text>12</text>
						<selected>True</selected>
					</data>
					<data>
						<text>14</text>
					</data>
					<valueField>text</valueField>
					<textField>text</textField>
					<type>combobox</type>




				</tools>
			</tools>
			<tools>
				<type>toolbar</type>
				<tools>
					<iconCls>icon-increase-font</iconCls>
					<name>increase-font</name>
				</tools>
				<tools>
					<iconCls>icon-decrease-font</iconCls>
					<name>decrease-font</name>
				</tools>
				<style>
					<marginLeft>5px</marginLeft>
				</style>
			</tools>
			<tools>
				<type>toolbar</type>
				<tools>
					<iconCls>icon-bold</iconCls>
					<toggle>True</toggle>
					<name>bold</name>
				</tools>
				<tools>
					<iconCls>icon-italic</iconCls>
					<toggle>True</toggle>
					<name>italic</name>
				</tools>
				<tools>
					<iconCls>icon-underline</iconCls>
					<toggle>True</toggle>
					<name>underline</name>
				</tools>
				<tools>
					<iconCls>icon-strikethrough</iconCls>
					<toggle>True</toggle>
					<name>strikethrough</name>
				</tools>
				<tools>
					<iconCls>icon-superscript</iconCls>
					<toggle>True</toggle>
					<name>superscript</name>
				</tools>
				<tools>
					<iconCls>icon-subscript</iconCls>
					<toggle>True</toggle>
					<name>subscript</name>
				</tools>
				<style>
					<marginTop>2px</marginTop>
					<clear>both</clear>
				</style>
			</tools>
			<tools>
				<type>toolbar</type>
				<tools>
					<iconCls>icon-case-font</iconCls>
					<name>case-font</name>
				</tools>
				<tools>
					<iconCls>icon-grow-font</iconCls>
					<name>grow-font</name>
				</tools>
				<tools>
					<iconCls>icon-shrink-font</iconCls>
					<name>shrink-font</name>
				</tools>
				<style>
					<clear>both</clear>
				</style>
			</tools>
		</groups>
		<groups>
			<dir>v</dir>
			<tools>
				<type>toolbar</type>
				<tools>
					<iconCls>icon-align-left</iconCls>
					<toggle>True</toggle>
					<name>slign-left</name>
					<group>p1</group>
				</tools>
				<tools>
					<iconCls>icon-align-center</iconCls>
					<toggle>True</toggle>
					<name>align-center</name>
					<group>p1</group>
				</tools>
				<tools>
					<iconCls>icon-align-right</iconCls>
					<toggle>True</toggle>
					<name>align-right</name>
					<group>p1</group>
				</tools>
				<tools>
					<iconCls>icon-align-justify</iconCls>
					<toggle>True</toggle>
					<name>align-justify</name>
					<group>p1</group>
				</tools>
			</tools>
			<tools>
				<type>toolbar</type>
				<tools>
					<iconCls>icon-bullets</iconCls>
					<name>bullets</name>
				</tools>
				<tools>
					<iconCls>icon-numbers</iconCls>
					<name>numbers</name>
				</tools>
				<style>
					<marginTop>2px</marginTop>
				</style>
			</tools>
			<title>Paragraph</title>
		</groups>

		<groups>
			<dir>v</dir>
			<tools>
				<iconCls>icon-find</iconCls>
				<text>Find</text>
				<name>find</name>
				<type>splitbutton</type>
				<menuItems>
					<iconCls>icon-find</iconCls>
					<text>Find</text>
					<name>find</name>
				</menuItems>
				<menuItems>
					<iconCls>icon-go</iconCls>
					<text>Go to...</text>
					<name>go</name>
				</menuItems>
			</tools>
			<tools>
				<iconCls>icon-replace</iconCls>
				<text>Replace</text>
				<name>replace</name>
			</tools>
			<tools>
				<iconCls>icon-select</iconCls>
				<text>Select</text>
				<name>select</name>
				<type>menubutton</type>
				<menuItems>
					<iconCls>icon-selectall</iconCls>
					<text>Select All</text>
					<name>selectall</name>
				</menuItems>
				<menuItems>
					<iconCls>icon-select</iconCls>
					<text>Select Objects</text>
					<name>select-object</name>
				</menuItems>
			</tools>
			<title>Editing</title>
		</groups>
		<title>Home</title>
	</tabs>
	<tabs>
		<groups>
			<title>Table</title>
			<tools toJsonArray="true">
				<size>large</size>
				<text>Table</text>
				<iconAlign>top</iconAlign>
				<name>table</name>
				<type>menubutton</type>
				<iconCls>icon-table-large</iconCls>
			</tools>




		</groups>

		<groups>
			<title>Illustrations</title>
			<tools>
				<size>large</size>
				<text>Picture</text>
				<iconAlign>top</iconAlign>
				<name>picture</name>
				<iconCls>icon-picture-large</iconCls>
			</tools>
			<tools>
				<size>large</size>
				<text>Clip Art</text>
				<iconAlign>top</iconAlign>
				<name>clipart</name>
				<iconCls>icon-clipart-large</iconCls>
			</tools>
			<tools>
				<size>large</size>
				<text>Shapes</text>
				<iconAlign>top</iconAlign>
				<name>shapes</name>
				<type>menubutton</type>
				<iconCls>icon-shapes-large</iconCls>
			</tools>
			<tools>
				<size>large</size>
				<text>SmartArt</text>
				<iconAlign>top</iconAlign>
				<name>smartart</name>
				<iconCls>icon-smartart-large</iconCls>
			</tools>
			<tools>
				<size>large</size>
				<text>Chart</text>
				<iconAlign>top</iconAlign>
				<name>chart</name>
				<iconCls>icon-chart-large</iconCls>
			</tools>
		</groups>


		<title>Insert</title>
	</tabs>

</data>

' as xml)

set @settings='<properties width="610px" height="170px">                                    


                       <event name="single_click" linkId="cut">
                        <action >
                            <main_context>current</main_context>                        
  		                <datapanel type="current" tab="current">
                                <element id="053_">
	                                <add_context>cut</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     



                       <event name="single_click" linkId="picture">
                        <action >
                            <main_context>current</main_context>                        
  	                    <datapanel type="current" tab="current">
                                <element id="053_">
	                                <add_context>picture</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     


                       <event name="single_click" linkId="align-center">
                        <action >
                            <main_context>current</main_context>                        
			    <datapanel type="current" tab="current">
                                <element id="053_">
	                                <add_context>align-center</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     


                       <event name="single_click" linkId="Tahoma">
                        <action >
                            <main_context>current</main_context>                        
		            <datapanel type="current" tab="current">
                                <element id="053_">
	                                <add_context>Tahoma</add_context>
                                </element>                                                             
                            </datapanel>
                        </action>
                       </event>                                                                     


                    </properties>'
END

Ribbon.png

  • Теги, задающие содержимое тулбара, обладают интуитивно понятными названиями. Подробное описание находится здесь

При этом,

  • <iconCls> -- задает название класса картинки, который определяется в jquery-easyui-ribbon\ribbon-icon.css,
  • Для задания события на выборе в комбобоксе используется конструкция
         <onSelect withoutQuotes="true">function(record){gwtPluginFunc(parentId,record.text);}</onSelect>
  • Для возможности использования в функции постобработки стандартного XMLJSONConverter'а Showcase добавлены следующие служебные атрибуты
    • withoutQuotes="true" -- указывает на то, что значение должно перейти в json без двойных кавычек. Пример,
	<selected withoutQuotes="true">0</selected>
    • toJsonArray="true" -- указывает на то, что, если в родительском теге только один child-тег, то он должен перейти не в object, а в array[1]. Пример,
		<groups>
			<title>Table</title>
			<tools toJsonArray="true">
				<size>large</size>
				<text>Table</text>
				<iconAlign>top</iconAlign>
				<name>table</name>
				<type>menubutton</type>
				<iconCls>icon-table-large</iconCls>
			</tools>
		</groups>

Здесь <tools> перейдет в tools: array[1], а не tools: object

  • C учетом вышесказанного, функция постобработки может представлять собой преобразование xml-данных в json-данные с помощью стандартного конвертера Showcase
# coding: utf-8
from ru.curs.showcase.util import XMLJSONConverter
from ru.curs.showcase.core.jython import JythonProc, JythonDTO

# init vars
data = None


class handleToolBar(JythonProc):

    def postProcess(self, context, elId, adata):
        global data
        data = adata
        return mainproc()

def mainproc():
    result = XMLJSONConverter.xmlToJson(data)
    return JythonDTO([result])

if __name__ == "__main__":
    from org.python.core import codecs
    codecs.setDefaultEncoding('utf-8')
    mainproc()