UI extensibility example: calculator bundle

This documentation shows how to use extensibility scenarios that are experimentally deployed in update 9. The APIs described here are manually deployed, which currently prevents installation in the Cloud. They are usable only in an Early adopter program context.

This article explains how you can add a custom action button at the top of every SAFE X3 web page.

To keep things simple we will add a simple button that opens up a popup with a calculator.

Creating our calculator bundle

Before writing our JavaScript code we must create a bundle's directory and a package.json file.

Our bundle will have the following structure:

xa1-calculator/package.json public/calculator-widget.jsplugin/jquery.calculator.jsjquery.calculator.css

The package.json file contains:
CODECODE CODE json{"name": "xa1-calculator","description": "Calculator widget extension","version": "1.0.0","author": "ACME Inc.","private": true,"sage": {"x3": {"extensions": {"shell-widgets": [{"module": "xa1-calculator/public/calculator-widget"}]}}}}

The shell-widgets extension key indicates that the package contains a UI shell extension. The module value gives the path to the JavaScript module which implements the extension.

The jquery plugin

We will not write the calculator ourselves. Instead, we will use the calculator jquery plugin.

The widget file

The calculator-widget.js file provides the glue between the SAFE X3 web framework and the jquery plugin:

CODECODE CODE javascript"use strict";require('./plugin/jquery.plugin');require('./plugin/jquery.calculator');// load CSS files['/xa1-calculator/public/plugin/jquery.calculator.css'].forEach(function(href) {$("<link/>", {rel: "stylesheet",type: "text/css",href: href,}).appendTo("head");});exports.create = function(container) {// add a 'calculator' button to the container var $button = $('<div>').text('calculator').appendTo($(container.div)).click(function() {$popup.toggle();}).css({color: 'white',});// create the calculator popup which is toggled by the buttonvar $popup = $('<div>').appendTo($(container.div)).calculator().css({position: 'fixed',margin: '7px 0px',}).hide();// return our widget's API (empty)return {};};

Let us walk through this file. First we load the JavaScript source for the jsquery plugin:
CODECODE CODE javascriptrequire('./plugin/jquery.plugin');require('./plugin/jquery.calculator');

Then, we load our extension's CSS file:
CODECODE CODE javascript['/xa1-calculator/public/plugin/jquery.calculator.css'].forEach(function(href) {$("<link/>", {rel: "stylesheet",type: "text/css",href: href,}).appendTo("head");});

Now, we have to provide a create function that the UI framework will call to create our widget. This create function is defined as follows:
CODECODE CODE javascriptexports.create = function(container) {var $button = ....;$button.appendTo($(container.div));return {// our widget's interface}}

The container parameter of the create function is the interface that the widget can use to interact with its container. This interface contains the following members and functions:

Note: the container API is very limited at this stage. It will be enhanced in the future.

Important: your widget should only use the container interface to interact with the rest of the UI framework. JavaScript is very permissive and you could bypass this interface and interact directly with internal APIs of the UI framework. Even if this is technically possible, this is forbidden. If you do so, your code may break at any point when the UI framework is upgraded. Instead you should file a request for an API enhancement if you have needs that are not covered by the current API.

The widget that you create will be displayed in the application's top bar. You should design it as a small button or icon that opens your widget as a popup.

The calculator button is created by:

CODECODE CODE javascriptvar $button = $('<div>').text('calculator').appendTo($(container.div)).click(function() {$popup.toggle();}).css({color: 'white',});

The calculator popup is created by:
CODECODE CODE javascriptvar $popup = $('<div>').appendTo($(container.div)).calculator().css({position: 'fixed',margin: '7px 0px',}).hide();

These two code fragments are basic jQuery code. We chose to write this widget with jQuery but it could also be implemented with another library (provided it does not conflict with jQuery), or directly with DOM API calls.

Note that you do not need to require the core jQuery library. It is already loaded by the SAFE X3 UI framework.

The last line of the create function returns the API that the UI framework will use to interact with your widget. For a shell widget, this API is empty. But for other extension scenarios the widget will need to expose some functions to its container. See the color picker extension for example.

The create function is designed as an API or interface handshake: the container passes its API and receives the widget's API in return.

Deploying our extension on the node.js web server

Deployment is easy: add your extension directory under the node_modules directory of the SAFE X3 'node.js' server, and restart the 'node.js' server.

Do not forget to restart the 'node.js' server everytime you make a change to your bundle. Otherwise it won't pick up the latest code.