In some cases you want to be able to let users lock a widget so that other user’s cannot make any changes. To implement this feature you need to be making use of event notifications, so your widget manifest must include:
<feature name=”comet” required=”true”/>
To lock or unlock a widget, the API provides two methods: Widget.lock()
Widget.unlock()
The methods can have a callback function attached, but in general this method is fairly safe to call without it.
To make use of locking and unlocking, your widget needs to be able to respond to locking and unlocking events that are pushed from the Wookie server. To do this you need to create handler functions that respond to the events; for example:
Widget.onLocked = handleLocked; Widget.onUnlocked = handleUnlocked;
These declarations assign “handleLocked” to be invoked when the widget receives an event notifying it that the widget has been locked, and “handleUnlocked” to be invoked on receiving an event notifying it that the widget has been unlocked. For a detailed example of locking, look at the source code of the default chat widget included with Wookie server.
8.3.3.2 Working with shared data
If you want widgets to have collaborative or social functionality, you need to make use of the shared data API. Shared Data provides methods for storing and accessing data that can be shared among all instances of a widget that share a common context. The meaning of “context” varies according to how the Wookie Plugin is configured to work with the container, but typically means a widget occupying a single space in the system. For example, for Wordpress the context is the blog; for Moodle it’s the course; for Elgg it’s the user profile page. For more information on contexts, see the Plugin Developer’s Guide.
To implement this feature you need to be making use of event notifications, so your widget manifest must include:
<feature name=”comet” required=”true”/> The Shared Data API contains the following methods:
Widget.appendSharedDataForKey(key, value, callback) Widget.setSharedDataForKey(key, value, callback) Widget.sharedDataForKey(key, callback)
The appendSharedDataForKey() method is a safe way of setting a shared value as it will only append the value you set to the end of the existing value of the shared data entry. You can use this method to do things like append messages to a shared chat log, for example.
The calls are asynchronous, and so it is not reliable to just invoke some of the methods on Widget without providing a callback handler. For example: Widget.sharedDataForKey(“foo”,”bar”,myHandler);
This means that when the service returns a value, your handler is called. If you need to call a series of services, a common way to do this is to chain the handlers together, e.g.: Widget.setSharedDataForKey(“foo”, myHandler); function myHandler(data){ sharedDataForKey(“bar”, myOtherHandler); } function myOtherHandler(data){ // do something }
Chaining service calls like this prevents your widget from getting into a tangle of colliding responses that can affect the validity of its state.
The get and set methods work in a similar fashion to the preference methods;
however, you need to take care of how you use them as multiple users are using your widget, which makes it highly likely that messages will overlap each other causing the state to be inconsistent. In general you should only use setSharedDataForKey() and sharedDataForKey() for values that are designed to be only ever set by a single widget instance, but are designed to be read by multiple instances.
For example, if you have a voting widget, you may want to store each user’s vote separately, but add them together to make the final score; this makes it possible for the user to change their vote without potentially messing up the tally if several users were to try to change it at the same time.
To generate an instance-specific shared data key, you should invoke the instanceId atrribute:
Widget.instanceId
This returns a unique identifier for your widget instance.
Whenever a shared data value is set or appended, widgets receive an event notifying them of the changes. Your widget can handle notifications by setting a function as the event handler in your script; for example:
Widget.onSharedUpdate = handleSharedUpdate;
This sets the handleSharedUpdate method to be invoked whenever there is an event notifying the widget that a shared data value has been updated.
Each event contains an array of keys for the values that have been updated; your widget can use these to determine what actions, if any, that it needs to take. For example:
function handleUpdate(keys){ for (String key:keys){ if( key.equals("chat"){
sharedDataForKey("chat", refreshChatDisplay()); }
} }
There are many different strategies that can be employed for working with shared data; a good starting point is to look at the code for the default widgets provided with the Wookie Engine.
In some cases, the functionality you need for your widget may be more than the shared data API can offer, in which case you should consider connecting to an external service to implement the features remotely.
8.3.3.3 Working with state coupling events This feature will be added in v1.0 of Wookie Server. 8.3.3.4 Working with secure services
Whenever your widget needs to call a secure service, you face a range of options for how to handle this situation. Each has its pros and cons.
8.3.3.4.1 ASK THE USER TO DIRECTLY PROVIDE THEIR LOGIN INFORMATION TO THE WIDGET, AND THEN ACCESS THE SERVICE PREFIXING THE AUTHENTICATION DETAILS
This has the benefit of simplicity but is extremely poor practice from the viewpoint of security and user education. Not only is the widget able to act on behalf of the user, it means storing credentials in plain text on the Widget Engine, which requires that the person running that server has to make sure its database is safe from snooping.
If you really, really must do this, then you can add the optional username and password parameters onto the proxified URL for the service.
8.3.3.4.2 USE AN ACCESS TICKET
An alternative to using credentials is to generate a ticket from the service that the user can paste into the widget instead of their credentials. The ticket can be specific to the widget and not usable by other agents or applications, enabling the service to track usage.
The advantage of this approach is nothing sensitive is saved in the Widget Engine database, or transmitted insecurely over the network. The disadvantage is that it shifts responsibility to the service for generating and managing tickets.
To use a ticket-based solution requires adding the appropriate ticket parameter to the service call.
8.3.3.4.3 USE OAUTH
OAuth is a standard ticket architecture used by a number of services, including Google’s applications and services. OAuth provides a mechanism for an application to request access to a service, prompting the user to login and grant a ticket.
OAuth is the most likely future scenario for accessing secure services in a consistent, user-centric way. Unfortunately, the current version of Wookie has not yet implemented it, so you’ll have to wait!
8.3.4 Appendix A to Wookie Widget Developers Guide: Widget API