Extending the Zimbra Canvas

Posted by Quinn Madson | Posted in | Posted on 11:17 AM

1

The Zimbra Canvas is pretty cool but, somewhat limited from the Zimlet XML definition file. For example, you cannot modify the buttons of the container if it's called from the XML. You can get around it by using the Zimbra JavaScript implementation.

It's pretty easy to get a canvas going from the JS side but, I was having issues getting the iframe style <actionUrl> functionality from the XML side. I had to reverse engineer this based on the source of ZmZimletBase();.

Here is the XML:

<zimlet name="edu_myschool_myzimlet" version="1.0" description="Some Zimlet">

<include>http://www.myschool.edu/LOCATION/TO/ZIMLET/zimlet.js</include>
<includeCSS>http://www.myschool.edu/LOCATION/TO/ZIMLET/zimlet.css</includeCSS>
<handlerObject>Edu_myschool_myzimlet</handlerObject>

<zimletPanelItem label="Some Zimlet" icon="My-panelIcon">
<toolTipText>This is a super awesome zimlet that does something.</toolTipText>
<contextMenu>
<menuItem label="Do something" id="doSomething" icon="My-panelIcon">
<canvas type="dialog" width="700" height="500" />
<actionUrl target="http://www.myschool.edu/LOCATION/TO/MASHUP/AWESOMENESS/" />
</menuItem>
</contextMenu>
</zimletPanelItem>
</zimlet>
This sets a right-click menu using the <zimletPanelItem> directive. More importantly, (for us, right now) is that it calls out to our JavaScript. Here is what the JavaScript should look like:
function Edu_myschool_myzimlet() {
}

Edu_myschool_myzimlet.prototype = new ZmZimletBase();
Edu_myschool_myzimlet.prototype.constructor = Edu_myschool_myzimlet;

Edu_myschool_myzimlet.prototype.init =
function() {
};

// Called by the Zimbra framework when the panel item was double clicked
Edu_myschool_myzimlet.prototype.doubleClicked = function() {
this.singleClicked();
};

// Called by the Zimbra framework when the panel item was clicked
Edu_myschool_myzimlet.prototype.singleClicked = function() {

var view = new DwtComposite(this.getShell());
view.setSize("500px", "500px");
var el = view.getHtmlElement();
var myBox = document.createElement("div");
el.appendChild(myBox);

var html = new Array();
var i = 0;
html[i++] = "First line of HTML <br/>";
html[i++] = "More lines of HTML";

// package up html and display it
myBox.innerHTML = html.join('');
this._dialog = this._createDialog({title:"My Dialog Title", view:view});
this._dialog.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this.myHandler));
this._dialog.setButtonTitle(DwtDialog.OK_BUTTON, "Go go gadget Zimlet!");
this._dialog.popup();
};

Edu_myschool_myzimlet.prototype.myHandler =
function(ev) {
//do come more stuff: web services, api calls, etc
this._dialog.popdown();
}
This will show some HTML within the Zimbra Canvas. You can create a form and allow it to call web services, the Zimbra API, etc based on what the user did. This is pretty handy. Also, if you look at the code, you can add handler functions to the buttons, change the button text, etc.

In some cases, you may just want to call out to some other code: PHP, JSP, ASP, (or in my case) ColdFusion, etc. To do an iframe the exact same way that <actionUrl> does, change the click action functions:
Edu_myschool_myzimlet.prototype.singleClicked =
function() {
var view = new DwtComposite(this.getShell());
view.setSize("700px", "500px");
var el = document.createElement("iframe");
el.src = "http://www.myschool.edu/PATH/TO/MY/CODE/mashup.cfm";
var sz = view.getSize();
if (!AjxEnv.isIE) {
// substract default frame borders
sz.x -= 4;
sz.y -= 4;
}
el.style.width = sz.x + "px";
el.style.height = sz.y + "px";
view.getHtmlElement().appendChild(el);

//TITLE OF THE DIALOG BOX
var dialog_args = {
title : "Example",
view : view
};
var dlg = this._createDialog(dialog_args);
dlg.popup();
};
From here you could add code to modify the buttons, pass a query string from JavaScript via the URL, etc.