Você está na página 1de 22

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
10. Export Your Widget as a package file(.gul)
11. Import Widget from a package file(.gul)

Reuse AdapterWidget in CPT Dashboard


Develop Widget using AdapterWidget
Convert AdapterWidget based UserLib into a CPT Dashboard
widget
Manage CPT Dashboard widget converted from AdapterWidget

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)
startSpinner()
stopSpinner()

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 and/or CPT dashboard, 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.

After you developed a AdapterWidget, you can save it as a Graphic UserLib, then export it
as single package file to share it with others for reuse, more details on how to export a
Graphic UserLib and how to import a Graphic UserLib.

Most of AdapterWidget can be converted to a CPT Dashboard widget with one click,
without changing any code. That means your efforts spent on developing AdapterWidget
can be reused on CPT Dashboard. More details on how to reuse AdapterWidget in CPT
Dashboard.

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 use 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.

Till now, there are 7 data types(String, Integer, Float, Boolean, Area, Color and Image) for
User Property. When you creating a new User Property, you can choose the most suitable
data type. When user edits User Property, CPT Tools will choose the most suitable
property editor widget based on the User Property’s data type.

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 ‘@’.

’Placeholder’: tooltip text for the User Property, displayed when user mouse
over your User Property in CPT Tools.
‘ActionOnly’: specify the User Property is an action, CPT Tools will only
display all component’s actions when you edit it. To enable this, the User
Property must be a String.

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.
There are 3 areas in the AdapterWidget Editing window: Code Editor, Preview and Test
Data:

Code Editor is plain code editor, that support javascript syntax highlight, simple code
error checking etc. And you change the font’s size at the bottom of the Code Editor.
Preview is a simple embed web browser, that will create a container for
AdapterWidget, set up mock APIs used by AdapterWidget. Note: This preview area
is only designed to have a quick look on the widget’s UI looking, it does not
communicate with controller backend. If you don’t need it, you can hide it by clicking
the checkbox ‘Enable Preview’ at the bottom of Code Editor.
Test Data is a list of User Property. For example, you can change ‘@BoolValue’ User
Property and see what the toggle widget behaves on the fly.

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() {
};

Click “Save” button, you can see that the toggle widget works in the Preview area. And in
“Test Data” area, you can change property ‘@BoolValue’ to ‘true’, the toggle button will
display ‘on’ state; change it to ‘false’, the toggle button will display ‘off’ state.

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.

10. Export Your Widget as a package file(.gul)

After you finish your widget, you can export it as a single package file, all required
files(css, javascript, images etc) are packed together. The package file’s extension name
is .gul(Graphic UserLib). You can share it with others, just like share a plain file.

Right click on your widget, there will be a contextual menu showing up:

Click the ‘Export Graphic UserLib …’ menu, CPT will ask for where to save the exported
package file, choose a folder then click ‘Save’ button. By default, CPT will generate a
default package name, for example Toggles-Toggle_20160804.gul, although you can
change it, better to leave it as default. At last, CPT Tools will open the exported package file
in File Explorer, so that you can easily find it and send it to others.
11. Import Widget from a package file(.gul)

If you want to reuse a widget shared by others, you need to get the .gul file, then in Graphic
UserLibs UI box, right click and in the contextual menu click “Import Graphic UserLib …”
menu item, then locate the package file and click ‘Ok’. During import, CPT may ask you to
confirm before a file is overwritted.

After import, you can start to use the widget.

Reuse AdapterWidget in CPT Dashboard

We design AdapterWidget in a way that it is easy to be converted as CPT dashboard


widget. So most of your developing efforts on AdapterWidget will be reused. Here are some
examples:
Develop Widget using AdapterWidget

When you developing a widget based on AdapterWidget and want to reuse it in CPT
dashboard, you need to keep something in mind:

Only depends on APIs documented in the AdapterWidget Programming Interface


Don’t depends on existence of any outside dom element, your widget should be self-
contained.

If you beer these rules in mind, then your widget is able to be used in dashboard.

Note: Now dashboard widget is readonly, it can not change underlying data. Writing
data may be supported in future.

Convert AdapterWidget based UserLib into a CPT Dashboard widget

After you finish developing your widget and it works well on CPT Graphics web page, then
you can follow these steps to make it work in CPT dashboard:

1. Save your widget as a graphic UserLib


2. Convert your widget to dashboard widget

3. Do a deployment

Now open CPT dashboard, create a new Pane, then click ‘+’ button to add a widget, on the
widget selection menu, your widget will be there.
If you want to more examples for reference, you can contact us at cptsuite@gmail.com.

Manage CPT Dashboard widget converted from AdapterWidget

All converted dashboard widgets are stored under


CPT/grweb/public/dashboard/plugins/cpt/widgets folder. You can open the folder in File
Explorer.

To make it easier, CPT Tools provides a dashboard widget management UI. You can open
the management UI, open any graphic file, click menu Tools -> Dashboard Widget
Management … , or you can right click in graphic UserLib box, there is a menu item, too.

You can rename or delete a dashboard widget here, after your changes is done, you need
to run FULL deployment to make your changes happen on controller side.

NOTE: After deployment, the dashboard widgets on controller side will be exact the
same as your computer. That means any dashboard widget on controller that does
not exist on your computer, will be removed.
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.
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.

Non-admin users can only run ‘select’ sql query, that means they can not
change the data in DB; Users with admin role can run any sql query.
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");

startSpinner()

Call this method to start a loading spinner, indicating that some work is under going.

stopSpinner()

Call this method to stop the spinner started by above ‘startSpinner’ method.
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.

Você também pode gostar