Vous êtes sur la page 1sur 16

Build your widget using AdapterWidget

Build your widget using AdapterWidget


What is AdapterWidget ?
Why develop AdapterWidget ?
Who should use AdapterWidget ?
How to develop widget based on AdapterWidget ?
Define User Property
Define Widget’s logic

Toggle Widget Demo


1. Download jQuery Toggles
2. Create AdapterWidget and Define User Property
3. Make Data Binding
4. Javascript Coding
5. Deployment
6. Define More User Properties For setTrue/setFalse Actions
7. Hook Widget’s Event To setTrue/setFalse Action
8. Final Tweak
9. Make Your Widget as UserLib

AdapterWidget Programming Interface


Container Dom Element
this.elem: the container dom element object

Callback Methods
requiredScripts()
init()
update(userPropertyName)
cleanup()

Data Service Methods


readData(propertyName)
writeData(userPropertyName, value)
invokeAction(path, [value, [valueDataType=’void’]])
hasData(userPropertyName)
runSqlQuery(query, dataCallback)
hasWritePerm()
readNote(path, dataHandler)
writeNote(path, content)

Preloaded 3rd Javascript Library


What is AdapterWidget ?

AdapterWidget is developed for CPT graphics widget developers, who want to develop his/her
own widgets running on CPT graphics web page, then maybe deliver the new widgets to his/her
customer to use.

Why develop AdapterWidget ?

CPT Tools already provide dozens of widgets for user to choose when building CPT graphics. But it
is hard to meet all user’s diverse requirements, so we come out AdapterWidget.

AdapterWidget already handles the logics of data communication, applying basic widget
properties(size, zorder etc), javascript/css files loading, so that developer of AdapterWidget can
just focus on the specific logic of his/her own widget.

Who should use AdapterWidget ?

AdapterWidget is NOT for non-technical users. To develop new widget based on AdapterWidget,
you will need to be familiar with Javascript, Html and CSS. Otherwise, AdapterWidget is not for
you.

AdapterWidget is a perfect fit under following cases:

want more graphic widgets that CPT Tools not provided yet
the widget provided by CPT Tools not meet your requirement well
provide project specific widgets to your customer, so that they can build logics on them
you know web programming technologies

How to develop widget based on AdapterWidget ?

To develop your widgets based on AdapterWidget, you will need to do two things:

Define User Property


Coding new widgets’s logic

Define User Property


When you define a new widget based on AdapterWidget, you probably want to allow users of your
widget to customize the look-n-feel or logics. You can define your own properties on your widget
for above purpose. We name your own property as User Property.

User Property behaves the same as other property(like size, zorder, visible etc), except one
difference: its name must start with ‘@’. This helps CPT Tools to differentiate User Property from
builtin property.

For example, if you are developing a Slider widget for user to change some integer data point’s
value, you may want user to define the valid value range. You can use User Property to implement
that.

To define a User Property:

Select an AdapterWidget
In AdapterWidget’s property editor, right click, then in the contextual menu, choose “New
User Property …”

In the new User Property dialog, define its name and data type, then save

NOTE: its name must start with character ‘@’.

Then the new property will show up in the property editor tree, and you can give it a default
value

Define Widget’s logic

Now you need to input your widget’s logics(javascript codes) into ‘javascriptCode’ property. Click
‘javascriptCode’ property, a code editor dialog will show up, and CPT have put some code
skeleton and comments there.

We will explain the programming interface of AdapterWidget in details later, now let’s try a demo.

Toggle Widget Demo

Here we will demo how to use AdapterWidget to integrate the wonderful jQuery Toggles 3rd party
javascript library to make our own toggle widget, that can be used on CPT graphics web page.

1. Download jQuery Toggles

Go to jQuery Toggles, download the source codes zipball, unzip it under CPT/grweb/public folder,
it looks like this:
2. Create AdapterWidget and Define User Property

Now we can drag and drop a AdapterWidget(under ‘general’ category) to graphic canvas, then
create a User Property named “@BoolValue”:

3. Make Data Binding

Now bind a boolean slot to the new User Property ‘@BoolValue’:


Here we bind ConstBool.out to ‘@BoolValue’ property for demo.

4. Javascript Coding

Now click the ‘javascriptCode’ property, and input following codes:

this.requiredScripts = function() {
// *Note*, you need to put the javascript/css files
// under 'CPT/grweb/public/user_codes' folder manually,
// otherwise these files cann't be deployed to device
return ["../user_codes/toggles/css/toggles.css",
"../user_codes/toggles/css/themes/toggles-light.css",
"../user_codes/toggles/toggles.js"];
};

// the method will be called just after AdapterWidget finishes


initialization
this.init = function() {
// this.elem is a div element created by AdapterWidget,
// new html element should be created under it
$(this.elem).css("text-align", "center")
.addClass("toggle toggle-light")
.toggles();

// set init state of toggle widget


this.update("@BoolValue");
};

// update toggle state based on the value of '@BoolValue'


// property this method will be called in 'this.init' method
// and everytime '@BoolValue' property changed
this.update = function(userPropertyName) {
// only continue if changed property is '@BoolValue'
if (userPropertyName != "@BoolValue")
return;
// set toggle widget's state
$(this.elem).data('toggles').toggle(
// read value of '@BoolValue'
_.str.toBoolean(this.readData("@BoolValue")));
};

// [required] put possible clean up codes here


this.cleanup = function() {
};

5. Deployment

Now we are ready to push files to controller, do a Full Deployment, wait until it’s done and click
‘preview’ button to see graphic page in browser.

You can change the ConstBool object’s state using setTrue/setFalse actions, and the toggle
button will change its state to reflect your changes.

Till now, the toggle widget is just a readonly widget, when click it in browser web page, it will
toggle its state, but the change will not be pushed to backend object ‘ConstBool’.

6. Define More User Properties For setTrue/setFalse Actions

We will define two more User Properties to allow user to specify the setTrue/setFalse actions’
path, so that when the toggle widget’s state changed, it will invoke related action.
We use ‘@OnAction’ for ‘setTrue’ action, ‘@OffAction’ for ‘setFalse’ action. One important thing is
when create ‘@OnAction’ and ‘@OffAction’, the ‘ActionOnly’ checkbox must be checked, this will
tell CPT Tools that this User Property is only about an action slot’s path, so that when user clicks
the property for editing, CPT Tools will display action selection editor.

set ‘@OnAction’ to ‘/ConstBo.setTrue’, set ‘@OffAction’ to ‘/ConstBo.setFalse’ using the follwoing


action edit dialog:
7. Hook Widget’s Event To setTrue/setFalse Action

Now update ‘javascriptCode’:

this.init = function() {
$(this.elem).css("text-align", "center")
.addClass("toggle toggle-light")
.toggles();

var _this = this;


this.onActionPath = this.readData("@OnAction");
this.offActionPath = this.readData("@OffAction");
$(this.elem).on("toggle", function(e, active) {
if (active)
_this.invokeAction(_this.onActionPath);
else
_this.invokeAction(_this.offActionPath);
});

this.update("@BoolValue");
};

The above code will listen to the ‘toggle’ event, and when the event happens, it will invoke the
action based on the ‘active’ value, that is the current state of toggle widget.
The ‘invokeAction’ method will communicate with backend to trigger the setTrue/setFalse action,
more details later.

Now do a deployment and open preview page, click the toggle widget will change the state of
‘ConstBo’ object.

8. Final Tweak

When bind ‘@BoolValue’ to ‘ConstBo.out’, CPT Tools will set up the object’s actions as the
widget’s contextual menu. That’s why when you click the toggle widget, the action menu will show
up.

It can be turned off by click ‘actions’ property and uncheck all actions:

9. Make Your Widget as UserLib

To make your widget can be reused, you can save it as a graphic UserLib:

Here the User Lib’s name is ‘toggle’, and set its Category as “Toggles”.

Then later you can just drag this new graphic userlib object to canvas to create a new toggle
widget.

AdapterWidget Programming Interface

To make the widget development easier, AdapterWidget isolate the inner widget from outside
environment, it provides the container dom element, several data service methods. On the other
side, the inner widget need to implement several callback methods, that will be called by
AdapterWidget under certain condition.

Container Dom Element

this.elem: the container dom element object

AdapterWidget will create a container ‘div’ dom element for the inner widget. inner widget
should limit its operations(for example, create new dom element) within this container. The
container element looks like this:

<div id="AdapterWidget_1_container" style="width: 92px;


height: 34px; margin: 0px auto;"></div>

AdapterWidget will take care of the container element’s position, size, zorder, visibility etc;
but within the container element, the inner widget has totally control.

You can use ‘this.elem’ to access the container element object, but more convenient way is
using jQuery wrapped object ‘$(this.elem)’, so that all jQuery functionalities are ready to be
use, for example:

// get container's width


$(this.elem).width();

// create a div element


$(this.elem).append("<div>hello</div>");

Callback Methods

requiredScripts()

Return a URL array of required javascript and css resource that are required.

This is the first callback method to be called by AdapterWidget. If the returned value is an
empty array, undefined or null values, AdapterWidget will load nothing; otherwise,
AdapterWidget will load these resource in order. In general, css resource should be loaded
before javascript resource.

All resource files must be put under ‘CPT/grweb/public/user_codes’ folder.

this.requiredScripts = function() {
return ["../user_codes/toggles/css/toggles.css",
"../user_codes/toggles/css/themes/toggles-
light.css",
"../user_codes/toggles/toggles.js"];
};

init()

Will be called after all required resources(css and javascript) loaded.

This is the right place to execute initialization tasks, for example, create widget’s dom
element, initialize widget’s data, set up widget’s style, bind listener to widget’s event etc.
Refer to above toggle widget demo for example.

update(userPropertyName)
Will be called whenever any User Property’s value changed.

This is the right place to update widget’s UI state. readData can be used to get User
Property’s value. Refer to above toggle widget demo for example.

cleanup()

Will be called when the widget will be removed from web page.

Data Service Methods

readData(propertyName)

This method will return property’s value, no matter User Property or not.

All property’s values are returned as string, it is the inner widget’s responsibility to cast it
into correct data type.

// read value of User Property '@maxValue'


var maxVal = parseFloat(this.readData("@maxValue"));

writeData(userPropertyName, value)

Call this method will change an object’s slot that bound to the given userProperty with
‘value’

// change object's slot '/Add2.in1' to 100


// '/Add2.in' is bound to User Property '@data'
this.writeData("@data", 100);

invokeAction(path, [value, [valueDataType=’void’]])

Call this method will invoke action addressed by ‘path’ with optional ‘value’ and optional
‘valueDataType’.

If ‘value’ parameter is omitted, then its default value is null.


If ‘valueDataType’ is omitted, then the framework will try to get the action’s value type
based on path; if that fails, then ‘valueDataType’ will be ‘void’. Possible valueDataType
values: bool, int, long, float, double, sys::Buf(or str for null-terminated string), more details
here.
// invoke 'setTrue' action on object '/ConstBo'
this.invokeAction("/ConstBo.setTrue");

// invoke 'set' action on object '/ConstFl'


this.invokeAction("/ConstFl.set", 80.0, 'float');

// if action path "/ConstFl.set" is stored in a


// User Property, for example '@SetPoint', then
// you can invoke the action like this:
this.invokeAction("@SetPoint", 80.0, 'float');

// Above code is a shortcut for:


this.invokeAction(this.readData("@SetPoint"), 80.0,
'float');

hasData(userPropertyName)

Return if the given userPropertyName has been defined.

// will return true if '@BoolValue' defined


// otherwise, return false
this.hasData("@BoolValue")

runSqlQuery(query, dataCallback)

Run the given sql ‘query’ statement on history db in controller and feed data back to
‘dataCallback’ method.

‘query’ should be a any valid sql query statement, for example:

SELECT strftime("%H", dt) AS hour,


avg(data1) AS data1Avg,
avg(data2) AS data2Avg
FROM foo WHERE dt > date("now", "-1 days")
GROUP BY hour;

Above query will get average data value per hour for columns ‘data1’ and ‘data2’ of
yesterday.

‘dataCallback’ function should accept a data object and the data object looks like this:
data = {
columns: ['hour', 'data1Avg', 'data2Avg'], // result
column labels
rows: [
['00', '505', '780'],
['01', '238', '1024'],
// ... ... more records
]
}

in ‘dataCallback’ function, you can decide how to render the queried result on UI.

hasWritePerm()

Call this method to query if current account has ‘write’ permission on current graphic page.
The return value is boolean value: true or false.

When calling ‘invokeAction’ method, the framework already call this method already, and
will return string ‘permission denied’ when current account doesn’t have permission.

readNote(path, dataHandler)

This method will fetch a note’s content at given ‘path’.

‘dataHandler’ is a callback function, when a note is fetched, dataHandler will be called with
the note’s content string as the only parameter.

// read value of User Property '@maxValue'


function dataHandler(content) {
// insert content into a DOM element, for example:
$("#testDiv").html(content);
}
// @NotePath user property stores the note's path
var path = this.readData('@NotePath');
this.readNote(path, dataHandler);

writeNote(path, content)

Call this method will save ‘content’ into note at ‘path’.

// change object's slot '/Add2.in1' to 100


// '/Add2.in' is bound to User Property '@data'
var path = this.readData('@NotePath');
this.writeNote(path, "this is a test note");

Preloaded 3rd Javascript Library

Following javascript libraries are used by CPT graphic web page, these are ready to be used within
the inner widget, and no need to specify them in the requiredScripts method.

jQuery
Underscore.js
Underscore.string
Backbone.js
Spin.js
Bootstrap.js 2.3.2
Moment.js

If a javascript library or css file are required by multiple widgets, AdapterWidget


will guarantee it loaded only once.

Vous aimerez peut-être aussi