Indice

EventAttributes Guidelines (Eventi Attributi Linee Guida)

This document represent the guidelines useful to implement event attribute support on new widgets.

In General

gwClass detail structure (from general/outer to specific/inner):

Every gwWidget (aka gwAttribute dojo widget) has got, in general, two model representation: one for the gwClassDetail in 'edit' mode, and one for the 'visualization' mode. All gwWidgets marked with gwAttributeId_* should implement a specific shared js API to allow configuration user to configure the desired dynamic behavior inside gwClassDetail.

Developers should to provide to every gwAttribute dojo widget (marked with class 'gwAttributeId_*', see below):

  1. commons shared properties (and, eventually, all needed JS API implementation, see below)
  2. a publish of the event 'gwClassDetail/gwAttributeReady' (typically inside startup function, see below)

Publish Chain Table

entity waits for publish event of all sub component publish event
gwClassDetail 'gwClassDetail/formManagerReady' 'gwClassDetail/ready'
gwAttributeGroup 'gwClassDetail/gwAttributeReady' 'gwClassDetail/formManagerReady'
gwAttribute (eventually) 'gwClassDetail/allFormManagerStarted' 'gwClassDetail/gwAttributeReady'

Providing the 'gwClassDetail/gwAttributeReady' publish it's very important to make all gwClassDetail logics to work:

it's own 'gwClassDetail/formManagerReady' publish (and 'gwClassDetail/formManagerStarted' publish, see below)

it's own 'gwClassDetail/ready' publish (and 'gwClassDetail/allFormManagerStarted' publish, see below)

Maintaining the publish chain will grant the publish of the 'gwClassDetail/ready' event. This is very important because on it is based the execution of all gwAction of type onDetailReady, and the correct execution of all the gwAttribute event handlers configured in gwAdmin.

In addiction 'gwClassDetail/gwAttributeReady' publish it's important to allow the fire of 'gwClassDetail/formManagerStarted' from the parent gwAttributeGroup (that will trigger the publish of the 'gwClassDetail/allFormManagerStarted' event id the gwClassDetail) This is a publish mechanism parallel to the 'gwClassDetail/formManagerReady'/'gwClassDetail/ready' publish. This is useful for some gwWidgets (like dbComboBox) that, before be able to publish their 'gwClassDetail/gwAttributeReady' event, needs to compute their value basing on current values of the others gwWidgets in the form (because, for example, they have a queryClause with some #{} expressions that depends on it). These gwWidgets typically waits for 'gwClassDetail/allFormManagerStarted' event before performing it's own 'gwClassDetail/gwAttributeReady' publish.

A direct consequence of this is that if even only one gwWidget do not publish it's 'gwClassDetail/gwAttributeReady' event, the behavior of all gwWidgets (like dbComboBox) depending on 'gwClassDetail/allFormManagerStarted' publish, belonging to the same gwClassDetail, will be 'broken'.

Javascript Shared API

This js API can be used in all configurable js on Geoweb. Typically they should be used in:

Available incoming parameters: /*Object*/ widget /*Object*/ eventWidget /*String*/ eventType /*String*/ gwClassName /*String*/ itemId /*Object*/ item /*Object*/ data /*Object*/ detailContainer /*String*/ detailContainerId /*Object, optional*/ eventChain

Available js api on widget/eventWidget (see all js API here)

Available js api on detailContainer (see all js API here):

This applies only in eventHandler for gwWidget events: Parameter 'eventChain' is useful to prevent cycles in event handler functions configured by configurator user. To allow the system to perform all needed checks, this parameter had to be propagated when using the use js gwWidget shared API. It should to be provided to API function that support it every time gwWidget API js function are used inside an event handler function. In all event handler functions parameter 'eventChain' should be always available as incoming argument. When a cycle is discovered a warning is logged in console e the cycle is stopped. Sometime configurator user could intentionally create cycles the bond more than one widget one to each other: this is an allowed configuration.

Example of allowed and handled cycles (Letters 'A', 'B', .. symbolize gwWidgets, '⇒' symbolizes an event handler bondind somehow them):

  1. A ⇒ B and B ⇒ A
  1. A ⇒ C and C ⇒ D and D ⇒ A
  1. A ⇒ E and E ⇒ F and G ⇒ H and H ⇒ A

Note that all the 3 cycle example above can to be configured at the same time and are handled each one separately from the others. This means that when the cycle 1 is releaved and stopped, cycle 2 and 3 continues to run until it return wo widget A.

If gwWidget js API are used outside eventHandler for gwWidget events, 'eventChain' cannot to be pass, but it will be generated internally and passed automatically to all the eventually configured event handlers (that should be written in aim to propagate the event chain!!)

Developers infos

All js API are added to very gwAttribute dojo widget (marked with class 'gwAttributeId_*', see below) in an automatic and centralized way Every gwAttribute widget can customize each function following it's needs.

All gwSet*() function must publish, depending on the *, a specific topic:

function topic:

.gwSetValue() publish only 'gwClassDetail/gwset/value' because the 'gwClassDetail/changed/value' is published after the onChange(). onChange() is a hook function exposed by all dojo widget that somehow holds a value, and it's automatically called on every change of value Geoweb by default, if a onChange() function exist, tries to use dojo aspect after to hook the code that makes the 'gwClassDetail/changed/value' published.

All publish are fired with an object passed as argument done like this, that will be available as incoming parameters in all subscriptor's callbacks.

 var params = {
	 gwClassName: detailContainer.gwClassName,
 	itemId: detailContainer.itemId,
 	detailContainer: detailContainer,
 	detailContainerId: detailContainerId,
 	data: detailContainer._gwClassDetail_data,
 	gwAttributeName: this.gwAttributeName,
 	gwAttributeGwid: this.gwAttributeGwid,
 	eventGwWidget: this,
 	value: value, //or hidden: hidden, etc..
 	eventChain: eventChain
 };

If a particular function has no meaning for the particular gwWidget, or it had not been deliberately implemented, developer user should however to override the function using the correspondent pattern below. This in aim to notify configuration user that he is eventually using an API function with no meaning for the specific gwWidget (or deliberately not yet implemented).

 gwGetValue: function(){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwGetReadonly()');
 
 	console.error('gwGetValue() function not implemented for '+this._gwWidgetType+': \'value\' parameter has no meaning for this widget');
 },
 gwSetValue: function(/*Object*/ value, /*Object, optional*/ eventChain){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwSetRequired()');
 
 	console.error('gwSetValue() function not implemented for '+this._gwWidgetType+': \'value\' parameter has no meaning for this widget');
 },
 gwGetReadonly: function(){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwGetReadonly()');
 
 	console.error('gwGetReadonly() function not implemented for '+this._gwWidgetType+': \'readonly\' parameter has no meaning for this widget');
 },
 gwSetReadonly: function(/*Boolean*/ readonly, /*Object, optional*/ eventChain){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwSetRequired()');
 
 	console.error('gwSetReadonly() function not implemented for '+this._gwWidgetType+': \'readonly\' parameter has no meaning for this widget');
 },
 gwGetRequired: function(){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwGetRequired()');
 
 	console.error('gwGetRequired() function not implemented for '+this._gwWidgetType+': \'required\' parameter has no meaning for this widget');
 },
 gwSetRequired: function(/*Boolean*/ required, /*Object, optional*/ eventChain){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwSetRequired()');
 
 	console.error('gwSetRequired() function not implemented for '+this._gwWidgetType+': \'required\' parameter has no meaning for this widget');
 },
 gwGetDisabled: function(){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwGetDisabled');
 
 	console.error('gwGetDisabled() function not implemented for '+this._gwWidgetType+': \'disabled\' parameter has no meaning for this widget');
 },
 gwSetDisabled: function(/*Boolean*/ disabled, /*Object, optional*/ eventChain){
 	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - gwSetDisabled()');
 
 	console.error('gwSetDisabled() function not implemented for '+this._gwWidgetType+': \'diabled\' parameter has no meaning for this widget');
 },

In general the following js API should not be overridden directly, because are always automatically added and they leverage on the implementation of .gwGetHidden() and .gwSetHidden() functions (custom or the default one).

Use of html classes

Use of gwAttribute dojo widget properties/function

Every gwAttribute dojo widget should provide this properties:

//ALWAYS
_gwWidgetType: 'widgetBaseWidget',
gwAttributeName: '${attributeList[param.index].name}',
gwAttributeGwid: ${attributeList[param.index].gwid},
_gwEventChain: [], //used internally to temporally pass eventChain parameter in the time intercurring between 'gwClassDetail/gwset/value' publish and 'gwClassDetail/changed/value' publish
 
...
 
//EVENTUALLY
//some custom implementation of function of the shared API (gwGetValue(), gwSetValue(), gwGetReadonly(), etc...)
gwGetValue: function(){
	...
},
...
 
//ALWAYS, or an alternative way to make the 'gwClassDetail/gwAttributeReady' publish
startup: function(){
	console.log((this._gwWidgetType ? this._gwWidgetType : 'gwWidget')+' - startup()');
 
	...
 
 	//XXX
	//IMPORTANT: the next publish must be done in all widget's startup()
 	var detailContainerId = '${detailContainerId}';
 	var gwClassName = '${currentClass.className}';
 	var itemId = '${itemId}';
 	var attributeGwid = '${attributeList[param.index].gwid}';
 	var formManagerId = '${param.formManagerId}';
 	var params = {
 		detailContainerId: detailContainerId,
 		gwClassName: gwClassName,
 		itemId: itemId,
 		attributeGwid: attributeGwid,
 		formManagerId: formManagerId
 	};
	topic.publish('gwClassDetail/gwAttributeReady', params);
 }

For now the convention is to implement the properties marked as ALWAYS in both 'edit' and 'visualization' gwWidget jsp implementation Even the 'gwClassDetail/gwAttributeReady' must be implemented in both. The js API are actually only implemented in 'edit' jsp, because only these jsp are inside a dynamic layout context. If a gwSet*() generic function is overridden the important thing is to publish the related event (see above).