Skip to end of metadata
Go to start of metadata

 

Definicja gadżetu przechowywana jest w pliku XML. Poniżej znajduje się opis, w jaki sposób daną definicję przygotować.

Struktura

Deklaracja jest plikiem XML. W pliku tym ustawiamy takie parametry jak tytuł, nazwa, miniaturka oraz ustawienia gadżetu. 


NazwaWymaganyOpis
name(tick)I18N. Nazwa gadżetu, która widoczna będzie w wyszukiwarce.
url(tick)Adres, pod którym powinno zostać zwrócone ciało gadżetu (strona HTML wraz z skryptami JS). Link ten jest relatywny do wtyczki.
description I18N. Opis tego gadżetu. Opis widoczny jest podczas dodawania nowego gadżetu.
thumbnail Obrazek ( w dowolnym formacie, obsługiwanym przez tag <img/>), który przedstawia wygląd działającego gadżetu. Jest on widoczny podczas wyszukiwania gadżetu. Zalecane wymiary: 120x100 px. Gadżet bez miniaturki będzie miał ustawione jako zdjęcie logo Suncode.

Podstawowa definicja:

<?xml version="1.0" encoding="UTF-8"?>
<gadget>
	<name>gadget.test.name</name>
	<url>/gadget/test</url>
	<description>gadget.test.desc</description>
	<thumbnail>/resources/thumb.png</thumbnail>
</gadget>

Konfiguracja gadżetu

Każdy gadżet ma zdefiniowany własny zestaw właściwości. Właściwości te pozwalają użytkownikowi na dostosowanie gadżetu do swoich potrzeb.

Właściwości gadżetów są zalecaną metodą przechowywania danych na potrzeby gadżetów.

Właściwości przechowywane są w formie tekstowej (schemat bazy danych) , dlatego bardziej skomplikowane obiekty możemy serializować np. do formatu JSON.

Właściwości gadżetu stosowane są zazwyczaj do:

  • zapis wyświetlanego raportu/widoku etc.
  • konfiguracji ilości wyświetlanych wyników
  • konfiguracji czasu odświeżania gadżetu
  • wyboru konkretniej skórki gadżetu

Definiowanie właściwości

 

Definicja XML
<?xml version="1.0" encoding="UTF-8"?>
<gadget>
	<!-- Pola podstawowe -->
	
	<!-- Opis konfiguracji gadżetu -->
	<configuration>
		
		<!--Definicja właściwości -->
		<properties>
			<property name="textproperty" type="text" />			
			<property name="numberproperty" type="number" />
			<property name="booleanproperty" type="boolean" value="false" />
		</properties>
		
		<!-- Skrypt budujący formularz -->
		<build-script>
		<![CDATA[
			// skrypt JavaScript odpowiedzialny za budowę formularza właściwości gadżetu
		]]>
		</build-script>
	</configuration>
</gadget>


Element property

Element property tworzy właściwość, która zostanie stworzona po dodaniu gadżetu do dashboardu.

NazwaWymaganyOpis
name(tick)Nazwa, która jednoznacznie identyfikuje właściwość gadżetu ( do 100 znaków )
type
 Typ właściwości (domyślnie text). Określa, jakie wartości mogą być zapisane w podanym polu. Ustawienie odpowiedniego typu ułatwia pracę z tymi właściwościami z poziomu Javy.
value Wartość domyślna właściwości.


Typy właściwości

Każda właściwość gadżetu implementuje interfejs: com.suncode.plugin.dashboard.gadget.Property<T>.

Właściwości przechowują wartość jako konkretny obiekt. Jeżeli nie znamy typu właściwości, możemy odczytywać i zmieniać jej wartość tylko używając tekstu (metody getRawValue(), setRawValue(String rawValue) )

Text - tekstowa

Właściwość typu text przechowuje wartość jako java.lang.String.

 

Definicja XML
<property name="textproperty" type="text" />			
com.suncode.plugin.dashboard.gadget.properties.TextProperty
TextProperty property = gadget.getProperty("textproperty", TextProperty.class);

 

Number - liczbowa

Właściwość typu text przechowuje wartość jako java.lang.Numberjava.lang.Long lub java.lang.Double, w zależności czy wartość zawiera separator dziesiętny .(kropka) ).

 

Definicja XML
<property name="numberproperty" type="number" />
com.suncode.plugin.dashboard.gadget.properties.NumberProperty
NumberProperty property = gadget.getProperty("numberproperty", NumberProperty.class);
 
// pobieranie wartości liczbowych
property.getValue();
property.getValueAsDouble();
property.getValueAsInteger();
property.getValueAsLong();

 

Boolean - logiczna

Właściwość typu boolean przechowuje wartość jako java.lang.Boolean.

 

Definicja XML
<property name="booleanproperty" type="boolean" />
com.suncode.plugin.dashboard.gadget.properties.NumberProperty
BooleanProperty property = gadget.getProperty("booleanproperty", BooleanProperty.class);

 

Budowa formularza ustawień

Konfiguracja gadżetów może ograniczać się do kilku pól, które muszą być uzupełnione przez użytkownika. Mogą jednak istnieć przypadki, gdy konfiguracja jest bardziej dynamiczna ( np. gadżet raportów jasper wymaga wygenerowania dynamicznych pól, w zależności, który raport zostanie wybrany), dlatego twórca gadżetu musi sam zbudować cały formularz, korzystając z udostępnionego API.

 

Formularz w całości bazuje na ExtJS 3. Wszystkie pola dodane znajdują się w obiekcie Ext.form.FieldSet.

Skrypt wywoływany jest po po zakończeniu metody initComponentale przed wyrenderowaniem formularza. W tym momencie obiekt formy Ext.form.BasicForm nie zawiera jeszcze żadnych pól - nie możemy używać metody findField(id), o ile formularz nie został jeszcze wyrenderowany.

Poniższy skrypt zbuduje formularz z 2 takimi samymi polami:

Prosty formularz
<!-- Skrypt budujący formularz -->
<build-script>
<![CDATA[
	// dodanie pola tekstowego
	Properties.add( Properties.text('nazwa', '#I18N#gadget.label#') );
	
	// dodanie takiego samego pola używając ExtJS api
	Properties.add({
		xtype: 'textfield',
		name: 'nazwa',
		fieldLabel: '#I18N#gadget.label#',
		value: Properties.value('nazwa') // opcjonalne, wartość pola ustawiana automatycznie
	});
]]>
</build-script>

 

Tłumaczenia skryptu

Możliwe jest tłumaczenie skryptu (np. labeli, tooltip'ów). Tłumaczenia pobierane są ze standardowego mechanizmu wtyczek - modułu I18N (TODO: link do modułu)

Jeżeli skrypt zawiera token #I18N#{messagekey}# gdzie {messageKey}  to klucz wiadomości zdefiniowany w pliku *.properties, to token ten jest zamieniany na odpowiadającą mu przetłumaczoną wiadomość.

Tłumaczenie
Properties.add({
	xtype: 'numberfield',
	fieldLabel: '#I18N#number.label#',
	tooltip: '#I18N#number.tooltip#'
});
 
// zostanie zamienione na
Properties.add({
	xtype: 'numberfield',
	fieldLabel: 'Numer',
	tooltip: 'Number tooltip'
});

Obiekt Properties

 W skrypcie budowania formularza dostępny jest obiekt Properties, który umożliwia pobranie obiektu formularza i udostępnia zestaw metod do pobierania właściwości gadżetu, dodawania standardowych pól etc.

MetodaOpis
getFormZwraca obiekt formularza Ext.form.FormPanel.
getFieldSetZwraca kontener Ext.form.FieldSet, do którego powinniśmy dodawać wszystkie pola. Dzięki temu wszystkie gadżety mają zunifikowany wygląd.

add(fields)

    • fields: komponent Ext.Component lub tablica komponentów

Skrót do getFieldSet().add(components). Dodaje do kontenera podany komponent.

insert(index, field)

    • index: miejsce dodania komponentu Ext.Component
    • field: komponent Ext.Component
Skrót do getFieldSet().insert(index, component). Dodaje do kontenera podany komponent na określonym miejscu.

remove(field)

    • field: komponent Ext.Component albo identyfikator, który chcemy usunąć
Skrót do getFieldSet().remove(component). Usuwa z kontenera podane pole. Możliwe jest także podanie identyfikatora komponentu.
removeAllSkrót do getFieldSet().removeAll(). Usuwa z kontenera wszystkie komponenty (pola).

getPluginUrl(url)

    • url: relatywny adres url wtyczki

Zwraca absolutny adres URL do wtyczki, z podanego relatywnego URL. Absolutny adres url ma budowę: <contextPath>/plugin/<pluginKey>/<url>

getAbosluteUrl(url)

    • url: relatywny adres url
Zwraca absolutny adres URL, dodając do podanego adresu context path. (Analogicznie do Suncode.getAbsolutePath(url))

getProperty(name)

    • name: nazwa właściwości

Zwraca właściwość o podanej nazwie. Zwrócona właściwość:

{
	name: 'nazwa',
	value: 'wartość',
	type: 'text'
}

value(name)

    • name: nazwa właściwości
Skrót do getProperty(name).value. Zwraca wartość właściwości o podanej nazwie lub undefined, jeżeli nie ma takiej właściwości
refreshLayout

Odświeża layout formularza oraz całego dashboardu. Funkcja powinna być użyta, jeżeli np. dodajemy dynamicznie pola już po wyrenderowania formularza.

Metody pomocnicze do tworzenia pól formularza

W przypadku użycia tych metod, wartość pól jest automatycznie ustawiana na podstawie właściwości gadżetu o tej samej nazwie.

 

hidden(name, config)

    • name: nazwa właściwości
    • config: obiekt konfiguracyjny, którym możemy dodać/nadpisać domyślne wartości

Tworzy pole ukryte (xtype: hidden) o podanej nazwie.

Pole ukryte może być wykorzystywane do zapisywania bardziej skomplikowanych lub dynamicznych pól.

Np. jeżeli liczba pól jest dynamiczna, pole ukryte może służyć do przechowywania definicji tych pól w formacie JSON.

text(name, label, config)

    • name: nazwa właściwości
    • label: label pola
    • config: obiekt konfiguracyjny, którym możemy dodać/nadpisać domyślne wartości

Tworzy pole tekstowe (xtype: textfield) o podanej nazwie, labelu.

 

number(name, label, config)

    • name: nazwa właściwości
    • label: label pola
    • config: obiekt konfiguracyjny, którym możemy dodać/nadpisać domyślne wartości
Tworzy pole liczbowe (xtype: numberfield) o podanej nazwie, labelu.

list(name, label, data, config)

    • name: nazwa właściwości
    • label: label pola
    • data: dane listy w formacie [[<value>, <name>], [<value>, <name>]]
    • config: obiekt konfiguracyjny, którym możemy dodać/nadpisać domyślne wartości
Tworzy statyczną listę rozwijaną (xtype: combo), o podanych wartościach. Pierwsza wartość jest wybierana automatycznie.

dynamicList(name, label, data, config)

    • name: nazwa właściwości
    • label: label pola
    • url: adres url servletu
    • config: obiekt konfiguracyjny, którym możemy dodać/nadpisać domyślne wartości

Tworzy dynamiczną listę rozwijaną (xtype: numberfield), która zawiera dane zwrócone przez określony servlet.


Servlet musi zwrócić dane w określonym formacie ( możemy użyć klasy pomocniczej com.suncode.plugin.dashboard.web.support.DynamicListResult)

Format danych
{
	records: [{
		name: <nazwa>,
		value: <wartość>
	}, {
		name: <nazwa>,
		value: <wartość>
	}]
}
Przykład servletu
@Controller
public class TestController {
   
    @ResponseBody
    @RequestMapping( value = "/list", method = RequestMethod.GET )
    public DynamicListResult getList()
    {
        DynamicListResult views = new DynamicListResult();
        views.addEntry( "pierwszy", 1 );
        views.addEntry( "drugi", 2 );
  
        return views;
    }
}



Przykład rozbudowanego formularza właściwości

Budowany formularz właściwości nie musi być prosty. Możemy stworzyć dowolny formularz, mając do dyspozycji obiekt formularza i listenery. 

Rozbudowany formularz wymagany był w gadżecie wyświetlającym raporty Jasper. Dla każdego raportu zdefiniowane były pola, które mógł uzupełnić użytkownik aby zmienić jego wygląd. Wymagane było pobieranie raportu wraz z definicjami jego właściwości, i dynamiczne dodawanie odpowiednich pól. Wartości z tych pól zapisywane były w formacie JSON do pola ukrytego.

Format danych
<properties>
	<!-- Wybrany raport -->
	<property name="report" type="number" />
	
	<!-- Parametry widoku -->
	<property name="params" type="text" />
	
	<!-- Częstotliwość odświeżania raportu -->
	<property name="refreshInterval" type="number" value="60"/>
</properties>

 

Poniżej przedstawiono cały skrypt gadżetu raportów Jasper:

Listing skryptu
var form = Properties.getForm(),
	paramsProperty = Properties.value('params'),
	reportProperty = Properties.value('report'),
	reportServlet = Properties.getPluginUrl('/gadget/jasper-report/reports'),
	store;

store = new Ext.data.JsonStore({
	autoLoad: true,
    autoDestroy : true,
    proxy : new Ext.data.HttpProxy({
        method : 'GET',
        url : reportServlet
    }),
    root : 'data',
    fields : [ 'id', 'name', 'parameters' ]
});
 
// on first load, render current report parameters
store.on('load', function(store){
    if(!Ext.isEmpty(reportProperty)){
        var record = store.getById(reportProperty);
        if(record){
            renderParameters(record, true);
        }
	}
}, form, {single: true});

form.getForm().on('beforeaction', function(basicForm, action){
	var params = {},
		field = basicForm.findField('params');
		
	form.cascade(function(param){
		if(param.jasperParam === true){
			var value = param.getValue();
			if(Ext.isDate(value)){
				value = value.format('Y-m-d');
			}
			params[param.jasper.name] = value;			
		}
	});
	field.setValue(Ext.encode(params));				
});
 
// on every select, render report parameters
function reportSelected(field, report){
	renderParameters(report);
};

// add static properties
Properties.add([
	Properties.hidden('params'),
	{
		xtype: 'combo',
		hiddenName: 'report',
		value: reportProperty,
		fieldLabel: '#I18N#gadget.jasper.report#',
		tooltip: '#I18N#gadget.jasper.report.tooltip#',
             	mode: 'remote',
             	triggerAction: 'all',
             	autoSelect: true,
             	valueField: 'id',
             	displayField: 'name',
             	store: store,
             	listeners: {
             		select: reportSelected
             	}
	}, {
		xtype: 'fieldset',
		ref: '../reportsParam',
		title: '#I18N#raport.params#',
		hidden: true,
		width: 250,
		defaults: {
			width: 200,
			submitValue: false,
			jasperParam: true
		},
		items: []
	},
	Properties.list('refreshInterval', '#I18N#refresh#', [
		[-1, '#I18N#never#'],
		[5, 5],
		[10, 10],
		[30, 30],
		[60, 60]
	],
	{
		tooltip: '#I18N#refresh#'
	})
]);
var paramsContainer = form.reportsParam;

// renders report parameters
function renderParameters(record, setValues){
	var parameters = record.get('parameters'),
		empty = Ext.isEmpty(parameters),
		parameter;
	
	paramsContainer.removeAll();
	paramsContainer.setVisible(!empty);
	
	if(!empty){
		for(var i=0; i<parameters.length; i++){
			parameter = parameters[i];
			addParameter(parameter, paramsContainer, setValues);
		}						
	}
	Properties.refreshLayout();
};

function addParameter(parameter, container, setValue){
	var config;
	
	switch(parameter.type)
	{
	case 'STRING':
		config = {
			xtype: 'textfield',
			jasper: parameter,
			fieldLabel: parameter.label
		}
		break;
	case 'INTEGER':
	case 'FLOAT':
		config = {
			xtype: 'numberfield',
			jasper: parameter,
			fieldLabel: parameter.label
		}
		break;
	case 'DATE':
		config = {
			xtype: 'datefield',
			jasper: parameter,
			fieldLabel: parameter.label
		}
		break;
	case 'LIST':
		var data = [], value;
		for(value in parameter.values){
			data.push([value, parameter.values[value]]);
		}
		
		config = Properties.list(null, parameter.label, data, {
			jasper: parameter,
			value: data[0][0],
			forceSelection: true,
			editable: false
		});
		
		break;	
	case 'USERNAME':
		config = {
			xtype: 'displayfield',
			jasper: parameter,
			fieldLabel: parameter.label,
			value: Suncode.getCurrentUser()
		}
		break;
	}
	
	if(setValue){
		if(!Ext.isEmpty(paramsProperty)){
			var saved = Ext.decode(paramsProperty),
				value = saved[parameter.name];
				
			config.value = value;
		}
	}
	
	// dodajemy pole
	if(config){
		container.add(config);
	}
};
Write a comment…