Developing an IBM® Lotus® Quickr™ Firefox connector using Quickr services
by user
Comments
Transcript
Developing an IBM® Lotus® Quickr™ Firefox connector using Quickr services
Developing an IBM® Lotus® Quickr™ Firefox connector using Quickr services Shun Zhang IBM Software Group Software Engineer IBM, Beijing, China Hui Jian He IBM Software Group Software Engineer IBM, Beijing, China April 2009 © Copyright International Business Machines Corporation 2009. All rights reserved. Abstract: This article explains, step by step, how to build a customized Mozilla Firefox connector for IBM® Lotus® Quickr™, using Lotus Quickr Representational State Transfer (REST) services. All the source code for the example is provided. Contents 1. 2. 3. 4. 5. 5.1 5.2 5.3 5.4 5.5 5.6 6. 7. 8. Overview..........................................................................................................2 Lotus Quickr content services ..................................................................2 Firefox extensions ........................................................................................3 Quickr Connector for Firefox.....................................................................4 Anatomy of the Quickr Firefox Connector .............................................5 Getting started ..............................................................................................5 Deploy the extension to Firefox...............................................................6 Add a menu item to launch the connector extension ........................8 The connector’s main UI............................................................................9 Initialize connector ....................................................................................12 Tree implementation .................................................................................13 Conclusion....................................................................................................22 Resources .....................................................................................................22 About the authors .......................................................................................22 1. Overview IBM Lotus Quickr is Web 2.0-based team collaboration software for knowledge sharing and collaboration. It includes a content repository, content management and team collaboration capabilities, and connectors that allow you to access Lotus Quickr from within desktop applications. Quickr connectors enable users to work with documents on a Lotus Quickr server from familiar desktop applications such as IBM Lotus Notes®, IBM Lotus Sametime®, Microsoft® Windows® Explorer, Microsoft Outlook, Microsoft Office and Lotus Symphony™. Quickr connectors interact with Lotus Quickr content using a set of published remote Simple Object Access Protocol (SOAP) and REST interfaces. Lotus Quickr encourages customers or business partners to build applications on these open interfaces. This article presents an example of how to use these service interfaces to build a custom connector. We select Firefox as the base application sample because Firefox is designed to be extensible with a rich programming interface; moreover, there is a mature developer community. With this Firefox connector, customers can manipulate their documents from multiple Quickr servers in a Firefox browser. Also, since Firefox is cross platform, it is the first connector that can run on non-Windows platforms. And since Lotus Quickr, IBM FileNet® Content Manager Collaboration Edition, and IBM Content Manager Collaboration Edition also provide the same suite of remote services, this connector can also work with all these servers. 2. Lotus Quickr content services Quickr content services make it possible to create, manage, update, search, query, and delete Quickr content, enabling users to access and manipulate content in Lotus Quickr. Lotus Quickr REST Services are designed around open standards and Web 2.0 technologies, allowing you to build applications with a basic understanding of existing Web technologies, such as HTTP and XML. The services are based on the Atom Syndication Format, as described in RFC 4287 for accessing content from Lotus Quickr, and on the emerging Atom Publishing Protocol as described in RFC 5023 for publishing content to Lotus Quickr. See the developerWorks article, Introducing IBM Lotus Quickr REST services, for more information about the REST services. Currently Lotus Quickr provides the services as shown in table 1. Table 1. Lotus Quickr services Release Service Supports the ability to: 8.0 Document services Manipulate document-oriented component types (Document Library) 8.0 Search services Discover information across multiple content component types 8.1 Place services Manipulate collaboration component containers 8.1 Template services Manipulate initial structure of places 8.1 Policy services Control server resource usage 8.1 Web Content services Control Web content In this connector we use the Document services. If you’d like to extend the Firefox connector with other services, you can leverage all the above services shown in table 1. 3. Firefox extensions Firefox provides an extensibility model to allow third-party code modules, called extensions, to modify the core browser's functionality or appearance and to add new features or user interface (UI) elements. An extension consist of three parts: (1) XUL documents, which describe the layout of the UI, (2) CSS directives that define the appearance of interface elements, and (3) Java™Script code that determines the behavior of such elements. For more information, refer to the Mozilla Extensions page. The connector extension architecture is as follows (see figure 1): • XUL UI. Uses XUL language to define the connector UI, including launch menu item, main UI, context menu, add library dialog, and property dialog. • Control Module. Interacts with user interface (UI) inputs and the IO module, accepts user’s input and drive IO module to fetch data from the remote server, and then parses data for presenting in the UI. JavaScript is the implementing language. IO Module. First it communicates with the server to get/post Atom feed/entry using IBM dojo Atom extensions. Then it reads/writes libraries information storied in local file systems, using the Mozilla programming interface. Figure 1. Firefox connector architecture This connector supports four types of servers now. In addition, IBM Business Partners have implemented the Quickr Content Services on other platforms (see the Lotus Business Partners and Solutions Catalog for more information about these solutions). Note that the Quickr services for Domino implementation should be version 8.2 or later. 4. Quickr Connector for Firefox The Lotus Quickr Connector for Firefox is a Firefox extension that provides many of the features of Lotus Quickr connectors. It lists document libraries by server, it can filter libraries by library name, and can easily interact with the Quickr Web UI. The main features of this connector are as follows: Servers/platforms supported: • Servers: Lotus Quickr, IBM FileNet Content Manager Collaboration Edition, IBM Content Manager Collaboration Edition • OS: All platforms on which Firefox can run Basic connector operation: • Browse library contents • Send content via mail • Download document • Drag and drop documents across libraries from multi-servers More: • Bookmark favorite content • Drag and drop Web elements (for example, images from Google) to library directly See the download, “Screen record of Lotus Quickr connnector for Firefox,” for a demonstration. 5. Anatomy of the Quickr Firefox Connector Now let’s discuss the essentials of the Firefox Connector. 5.1 Getting started First, you may want to familiarize yourself with the basic concepts and technical requirements for building a Firefox connection by visiting Mozilla.org and reviewing “Building an Extension”. Then, to deploy the source code for the Quickr Connector, follow these steps: 1. Create an empty project using your favorite Integrated Development Environment (IDE). The project name can be [email protected]. 2. Download the [email protected] file from the Downloads section. 3. Extract all the files to the root folder of the project. The project hierarchy should look something like that shown in figure 2. Figure 2. Project directory structure All the XUL and JavaScript files are in the content folder, the i18n files are in the locale folder, and the images and CSS files are in the skin folder. The files Chrome.manifest and install.rdf are required for an extension to be recognized and run by Firefox, and those two files should be in the root folder of the project. The creation of the files is described in section 5.2 below. 5.2 Deploy the extension to Firefox Before deploying the extension to Firefox, we need to look in the chrome.manifest and install.rdf files mentioned above, and then create a link file to the extension project under the Firefox extension directory. chrome.manifest chrome.manifest is under the project root directory, and the contents are shown in listing 1. Listing 1. chrome.manifest contents content quickrconnector content/ overlay chrome://browser/content/browser.xul chrome://quickrconnector/content/overlay.xul locale quickrconnector en-US locale/en-US/ locale quickrconnector zh-CN locale/zh-CN/ skin quickrconnector classic/1.0 skin/ The content element says that, for a chrome package quickrconnector, we can find its content files at the location content/ (note that the “/” is required), which is a path relative to the location of chrome.manifest. We need Firefox to merge our overlay with the browser window whenever it displays one. So add the overlay element to tell Firefox to merge overlay.xul into browser.xul when browser.xul loads. Since we have only one launch entry, we just add one overlay element. The locale elements describe the languages supported by the connector, and the skin element describes which skin to use. install.rdf file install.rdf is also under the project root directory, and the contents are shown in listing 2. Listing 2. install.rdf contents <?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>[email protected]</em:id> <em:name>Quickr Connector Demo</em:name> <em:version>1.0.6</em:version> <em:description>Lotus Quickr Connector Firefox Plugin</em:description> <em:creator>Sean Zhang</em:creator> <em:contributor>Jeff He</em:contributor> <em:homepageURL>http://quickr.tap.ibm.com</em:homepageURL> <!-- Firefox --> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>1.5</em:minVersion> <em:maxVersion>3.0.*.*</em:maxVersion> </Description> </em:targetApplication> </Description> </RDF> The connector’s em:id element must be a GUID or in the form of an email address (whether valid or not). The em:id of the target application is Firefox’s ID, which is fixed. Create a link file To deploy the extension, create a file named [email protected] (notice this is the same name as the em:id from the install.rdf file) in the <Firefox installation path>/extensions directory and edit the file, adding the project folder’s path as its contents. Test and debug So far we’ve performed all the steps to deploy a simple extension. When you restart Firefox, you should find the Quickr Connector menu item under the Tools menu, and the sidebar should open with the main UI XUL file quickrconnector.xul. To debug the Firefox extension, first set up an extension development environment, such as the Extension Developer's extension, to save time when you reload the XUL changes. Otherwise, you must restart the Firefox application. See the Mozilla development center for more information about chrome.manifest, install.rdf, and building a Firefox extension. 5.3 Add a menu item to launch the connector extension Now that you have a basic idea about how the Firefox connector extension is built and deployed, let’s discuss how to add the menu item to launch the connector. First we need to create an overlay XUL file to add the Quickr menu item to the Tools menu. The file is in the content directory with the name overlay.xul, and the contents are shown in listing 3. Listing 3. XUL file contents <?xml version="1.0"?> <?xml-stylesheet href="chrome://quickrconnector/skin/overlay.css" type="text/css"?> <!DOCTYPE overlay SYSTEM "chrome://quickrconnector/locale/overlay.dtd"> <overlay id="quickrconnector-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul "> <menupopup id="menu_ToolsPopup"> <menuitem observes="viewQuickrSidebar" label="&quickrconnector;" accesskey="&quickrconnector.accesskey;" key="key_gotoQuickrConnector"/> </menupopup> <broadcasterset id="mainBroadcasterSet"> <broadcaster id="viewQuickrSidebar" autoCheck="false" sidebartitle="&quickrconnector;" type="checkbox" group="sidebar" sidebarurl="chrome://quickrconnector/content/quickrconnector. xul" oncommand="toggleSidebar('viewQuickrSidebar');"/> </broadcasterset> </overlay> This file tells Mozilla to load locale file chrome://quickrconnector/locale/overlay.dtd, add a menu item to the Tools menu at the end by default, and then define the action of this menu item. toggleSidebar is a built-in function to open the sidebar. The sidebarurl attribute refers to the connector main UI XUL; when the menu item is clicked, the sidebar will open with sidebarurl. We’ll talk about the main UI in detail later. Locale file If you look in the menuitem element in overlay.xul, you will find the label and accesskey attributes’ values start with “&” and end with “;”. That means the actual value of this attribute comes from a locale file, and the present string between “&” and “;” is just a key to get that value. To support a certain languages and locale, you need to create a corresponding locale file. For example, to support English in the United States, create an en-US folder under the locale directory, create the overlay.dtd file mentioned above, and input the following contents: <!ENTITY quickrconnector "Quickr Connector"> <!ENTITY quickrconnector.accesskey "Q"> 5.4 The connector’s main UI The main UI inside the sidebar is an XUL page (see figure 3). The file quickrconnector.xul is under the content directory. Of course, since there must be some localized text in the UI, quickrconnector.dtd is used to store locale key-value pairs data in the corresponding locale directory. Figure 3. Connector extension main UI There are four parts of the sidebar: • Title. Actually, the title isn’t set in the main UI XUL; instead, it’s set when the launch menu item is clicked. • Toolbar. hbox is a container that can group elements horizontally. The first functional element is a timeout textbox and, since its timeout attribute is set to 500ms, the oncommand action will be triggered every 500ms when editing the textbox. Then we add two image elements and set their onclick value to addLibrary and collapseAll as shown in listing 4. (You’ll know what they do when they are clicked by the function name.) Listing 4. Toolbar contents <hbox align="center"> <label value="&find.label;" control="search-box"/> <textbox id="search-box" flex="1" type="timed" timeout="500" oncommand="searchLibrary();"/> <image id="addLibraryImage" onclick="addLibrary();" src="../skin/images/addLibrary.gif" /> <image id="collapseAllImage" onclick="collapseAll();" src="../skin/images/collapseAll.gif" /> </hbox> • Library tree. This is the most important element in the main UI. context refers to a context menu id. The onkeypress value means that, when the ENTER key is pressed, the node’s URL will open in the current tab. onclick tells what to do when the mouse is left-clicked. Two other options you can set are tab, to open in a new tab, and window, to open in a new Firefox instance. Since the tree is a little complicated, we decided to use a customized tree view, in which the child elements under the tree are just placeholders (see listing 5). We’ll render the tree dynamically by programming. Listing 5. Customized tree view <tree id="quickrTree" flex="1" class="plain" context="quickrContextMenu" onkeypress="if (event.keyCode == 13) openURLIn('current');" onclick="handleQuickrConClick(event);" hidecolumnpicker="true" ondraggesture="if (event.originalTarget.localName == 'treechildren') nsDragAndDrop.startDrag(event, quickrDNDObserver);" ondragdrop="nsDragAndDrop.drop(event,quickrDNDObserver)" canDrop="nsDragAndDrop.canDrop(event,quickrDNDObserver);"> <treecols id="quickrTreeCols"> <treecol flex="1" id="Name" persist="sortActive sortDirection" hideheader="true" primary="true"/> </treecols> <treechildren/> </tree> You can go to the Mozilla development center to learn more about the XUL tree and the custom tree view. • Context menu. The context menu pops up when you right-click the mouse or as otherwise defined by Firefox. Pop-up menus are displayed automatically, but before the menu renders, you can do things like hide certain menu items by setting the popupshowing attribute to the function you’d like to call (see listing 6). Listing 6. Context menu example <popup id="quickrContextMenu" popupshowing="buildContextMenu(event);"> <menuitem id="miOpen" label="&openLinkInWindow.label;" accesskey="&openLinkInWindow.accesskey;" default="true" oncommand="openURLIn('current');"/> ………… ………… <menuseparator id="pre-properties-separator"/> <menuitem id="miProperties" label="&properties.label;" accesskey="&properties.accesskey;" oncommand="showProperties();"/> </popup> So far we’ve discussed elements the can be displayed in the UI. We also need to tell Firefox to load locale files and dependent script files such as dojo files: <script type="application/x-javascript" src="dojo12/dojo/dojo.js"/> Control module The control module is a set of functions working in the background of the UI. There are many language options such as C++, Java, and JavaScript that can be used to implement the functions; however, JavaScript may be the most convenient. You don’t need to do any extra compile or other work to deploy your code with JavaScript, and since it meets our needs, we used it as our implementation language. Note that most control code is in content/quickrconnector.js. 5.5 Initialize connector So far we’ve been describing the basic UI components of the connector. Now we discuss how the connector interacts with the Quickr server. The initialize function QuickrConnectorCommonInit is set as the page’s onload attribute value in quickrconnector.xul. The most important thing is reading the config file to get the list of Quickr document libraries. Libraries data are stored in the config file as a JSON object. FileIO.js encapsulates the file read/write operations using Mozilla file IO. When the data is read from the config file, the content is translated into JavaScript variables so it can be accessed from the connector: var filein = FileIO.open(gConfigFilePath); var data = FileIO.read(filein); var data = eval(data); A class, quickrcon.QuickrLib, is introduced to hold the library’s metadata (see listing 7). Setters and getters are ignored here. Listing 7. Document library metadata dojo.declare("quickrcon.QuickrLib",null,{ constructor: function(title,url,feedUrl,server,user,password){ this.title = title; this.url = url; this.feedUrl = feedUrl; this.server = server; this.user = user; this.password = password; } } The Quickr document library metadata include the library’s name, a view URL to open the library in a browser, a feed URL to fetch its children folder/document, the server to which it belongs, and log-on credential information. After the config file is loaded, the libraries are filled into an array, namely, libs of quickrcon.QuickrLib objects. Then a data model is built for the tree view, which we address below in subsection 5.6.3, “Building the data model.” Note that the Class quickrcon.QuickrLib definition is in the file content/dojo12/quickrcon/QuickrData.js. 5.6 Tree implementation The tree adopts a Model-View-Controller (MVC) pattern. Let’s look at the tree view interface to see what the model should be. 5.6.1 Tree view The tree view is the interface called by the tree object to render the tree. gTreeView implements this interface. Table 2 is excerpted from the nsITreeView page and shows the methods and attributes we should implement in order for the tree view of Quickr content to be rendered properly. The methods are described in more detail later in this section. Table 2. Method overview void getRowProperties(in long index, in nsISupportsArray properties); void getCellProperties(in long row, in nsITreeColumn col, in nsISupportsArray properties); void getColumnProperties(in nsITreeColumn col, in nsISupportsArray properties); boolean isContainer(in long index); boolean isContainerOpen(in long index); boolean isContainerEmpty(in long index); boolean isSeparator(in long index); boolean isSorted(); boolean canDrop(in long index, in long orientation); void drop(in long row, in long orientation); long getParentIndex(in long rowIndex); boolean hasNextSibling(in long rowIndex, in long afterIndex); long getLevel(in long index); AString getImageSrc(in long row, in nsITreeColumn col); long getProgressMode(in long row, in nsITreeColumn col); AString getCellValue(in long row, in nsITreeColumn col); AString getCellText(in long row, in nsITreeColumn col); void setTree(in nsITreeBoxObject tree); void toggleOpenState(in long index); void cycleHeader(in nsITreeColumn col); void selectionChanged(); void cycleCell(in long row, in nsITreeColumn col); boolean isEditable(in long row, in nsITreeColumn col); boolean isSelectable(in long row, in nsITreeColumn col); void setCellValue(in long row, in nsITreeColumn col, in AString value); void setCellText(in long row, in nsITreeColumn col, in AString value); void performAction(in wstring action); void performActionOnRow(in wstring action, in long row); void performActionOnCell(in wstring action, in long row, in nsITreeColumn col); Attributes: Attribute Type rowCount long selection nsITreeSelection Description Readonly: The total number of rows in the tree (including the offscreen rows). The selection for this view. 5.6.2 Tree model analysis The following methods and attributes are useful for data model analysis: • • • • • rowCount: Returns how many nodes the tree has, including all the server, library, folder, and document nodes. isContainer(): Returns whether the node can contain child nodes. There are container nodes like folder nodes and non-container nodes like document nodes in the data model. getLevel(): Returns the node’s level, which is used to determine how much it’s indented when rendering getCellText(): Returns the node’s label. getImageSrc(): Returns the image to be used to represent the node. Listing 8 defines a generic tree node, ignoring the setters and getters: Listing 8. Generic tree node dojo.declare("quickrcon.TreeNode",null,{ constructor: function(lib,title,nodeType,url,entry,parent,level){ this.lib = lib; this.title = title; this.url = url; this.nodeType = nodeType; this.parent = parent; this.entry = entry; this.level = level == null? 0 : level; this.imageSrc = null; } } There are four types of tree nodes: quickrcon.TreeNode.DOCUMENT = "document"; quickrcon.TreeNode.FOLDER = "folder"; quickrcon.TreeNode.LIBRARY = "library"; quickrcon.TreeNode.SERVER = "server"; Figure 4 shows the design of the tree model class, in which the folder and the library have almost the same properties and methods, and they both can be a FolderNode instance. ServerNode has a few more properties than FolderNode because it holds the user’s name and password on the server. ServerNode is also the root node of the tree, which means its level is zero. Figure 4. Tree model class quickrcon.TreeNode quickrcon.DocumentNode quickrcon.FolderNode quickrcon.ServerNode Note that all the class definitions are in content/dojo12/quickrcon/Tree.js. 5.6.3 Building the data model There are only libraries entries in the config file, but servers can be calculated by traversing the libraries. The corresponding function is getAllServerNodes, which builds a map with the server URL as the key and an array of libraries on the server as the value. The data model is a “forest,” in data structure terminology. The root nodes are server nodes, the second-level children are library nodes, and the lower-level nodes are folder or document nodes. The gDataModel is constructed after the connector is initialized, a forest is built, and there are just two levels, the server nodes and library nodes (see listing 9). Listing 9. gDataModel gDataModel = new Array(); for(var i in serverNodesMap.keys){ var server = serverNodesMap.keys[i]; var nodes = serverNodesMap.getServerNodes(server).nodes; var serverNode = new quickrcon.ServerNode(null,server,quickrcon.TreeNode.SERVER,null); serverNode.setLevel(0); serverNode.setChildren(new Array()); serverNode.setUser(serverNodesMap.getServerNodes(server).user); serverNode.setPassword(serverNodesMap.getServerNodes(server).password); gDataModel.push(serverNode); for(var j = 0; j < nodes.length; j++){ var node = nodes[j]; serverNode.getChildren().push(node); node.setParent(serverNode); } } The data model is enriched when you click on a library or folder, which leads to fetch feed/entry from a remote server. 5.6.4 Updating the tree view As mentioned above, the tree view needs an array to store the tree nodes so that the row index can be used to fetch the node data. So we need preorder traversal of the data model, which can be done by a recursive call of buildTreeData function (see listing 10). Listing 10. buildTreeData function gTreeData = new Array(); var buildTreeData = function(node){ if(node == null) return; gTreeData.push(node); if(node.isContainer() && node.getOpen() && node.getChildren()){ for(var i = 0; i < node.getChildren().length; i++){ buildTreeData(node.getChildren()[i]); } } }; When gTreeData is ready, we update rowCount of gTreeView and refresh the tree view. Updating the tree view is encapsulated in the updateTreeView method. 5.6.5 Consume REST services Quickr provides REST services, following the Atom specification. We use IBM’s dojo Atom extension—contributed to the dojo open source community in version 1.3—to simplify the handling of Atom service requests/responses. The code snippet in listing 11 demonstrates how to use it. Listing 11. dojo Atom extension in use function getChildrenData(node,preventCache){ var handle = new FeedHandler(); handle.currentNode = node; var atomIO = new ibm_atom.io.atom.AtomIO(); atomIO.user = node.getLib().getUser(); atomIO.password = node.getLib().getPassword(); var url = null; if(node.getNodeType() == quickrcon.TreeNode.LIBRARY || node.getNodeType() == quickrcon.TreeNode.FOLDER){ url = node.getFeedUrl(); if(url == null) return; url += "?pagesize=10000&pageSize=10000"; node.setStatus("waiting"); searchLibrary(); atomIO.getFeed(url, dojo.hitch(handle,"handleFeed"), function(err){node.setStatus("done");alert(err);}); } } Quickr libraries feed service returns 10 entries by default, as do FileNet® and Content Manager content services. Since we’d like to return all the entries in one request, in the above code we add a pagesize parameter with a large value (10000). Note that the page size parameter for the Content Manager server is pageSize. We can add both pagesize and pageSize, to support all the servers. Also, note the following: • • • node.setStatus("waiting") tells the tree view to set a loading image for the node the next time the tree view is updated. searchLibrary filters out libraries to be displayed and updates the tree view. getFeed uses dojo.xhr calls REST services. The three parameters of this function are the service URL, the callback when the response is correct, and the error callback when an error occurs. The FeedHandler is a wrapper of the handleFeed function (see listing 12). When the service response is correct, the feed handler parses the response Atom document and create folder/document nodes, integrate them into the data model, change the parent node’s status to done and, finally, call searchLibrary to update tree view. Listing 12. Feedhandler var FeedHandler = function(){ this.handleFeed = function (feed, ioArgs){ var cnode = this.currentNode; cnode.setOpen(true); cnode.setStatus("done"); var entries = feed.entries; if (entries != null) { cnode.children = new Array(); for(var i = 0; i < entries.length; i++){ var entry = entries[i]; try{ var title = entry.title.value; var category = entry.getCategories()[0]; var type = category.term.value; var url = null; if(entry.links){ for(var j = 0; j < entry.links.length; j++){ var link = entry.links[j]; if(link.rel && link.rel.value == "alternate"){ url = link.href.value; break; } } } var node = null; if(type == quickrcon.TreeNode.FOLDER){ node = new quickrcon.FolderNode( cnode.getLib(), title,quickrcon.TreeNode.FOLDER, url, entry,cnode, cnode.getLevel() + 1,null,false); } else if(type == quickrcon.TreeNode.DOCUMENT){ node = new quickrcon.DocumentNode(cnode.getLib(), title, quickrcon.TreeNode.DOCUMENT, url, entry, cnode, cnode.getLevel() + 1); } if(node != null) cnode.getChildren().push(node); }catch(e){} } cnode.getChildren().sort(function(a,b){ if(a.getNodeType() != b.getNodeType()) return a.getNodeType() > b.getNodeType() ? 1 : -1; else return a.getTitle().toLowerCase() > b.getTitle().toLowerCase() ? 1 : -1; }); } searchLibrary(); }; }; Build context menu There are 13 menu items in total, but not all of them are shown at one time. The buildContextMenu function decides which items should be displayed in the context menu pop-up. First it checks whether there is a selected node. If there’s not, then only the add library item can be displayed; if there is, it will check the node type and decide what item should appear. 5.6.6 Operation functions Almost all the connector functions are triggered by menu items. When a menu item is selected, the following corresponding functions are called: • addLibrary. Prepares the parameter for the Add Library dialog box and calls window.openDialog to open that dialog. When the OK button of this dialog box is clicked, the callback is called to save the added library to the config file and to update the data model and tree view: var params = {atomIO:atomIO,callback:callback,servers:gDataModel,out:null}; window.openDialog("addLibrary.xul", "", "chrome, dialog, centerscreen, resizable=yes", params).focus(); • renameLibrary. Renames a library. This operation can change only local data (meaning it does not rename the actual Document Library on the server). • deleteLibrary. Deletes a library in the tree view and config file. This operation can change only local data. (meaning it does not delete the actual Document Library on the server). • collapseAll. Collapses all the tree nodes by setting all the nodes’ open state to false and then updating tree view. • collapseExpand. Collapses or expands a tree node. If a node is already open, then it collapses it. If it’s collapsed, you should check whether the child data has been fetched; if not, then call service should be called to load data first. • openURLIn. Opens a URL in a specific place, either in the current tab, a new tab, or in a new window. If there is an event object such as a click event, the function whereToOpenLink can be used to determine the place to open. • refresh. Refreshes the current node’s child data, and will call the REST service and rebuild the child nodes. • quickrAddBookmarks. Adds the current node’s view URL to bookmarks via the Firefox programming interface. In Firefox 3, it looks like this: var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var uri = ios.newURI(url, null, null); PlacesUIUtils.showMinimalAddBookmarkUI(uri,title); • quickrCopyLink. Copies the current node’s view URL to the clipboard: var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"] .getService(Components.interfaces.nsIClipboardHelper ); clipboard.copyString(url); • mailto. Sends the current node link to a recipient. The easiest way is by using the mailto protocol; you just need to prepare the email’s subject and body content as a string, and then combine them into a mail URL and open it (see listing 13). Listing 13. mailto example var url = node.getUrl(); var title = node.getTitle(); var htmlString = "<A HREF='" + url + "'>" + title + "</A>"; var mailUrl = 'mailto:?subject=' + escape(title) + '&body=' + escape(htmlString); var tab = openUILinkIn(mailUrl,"tab"); • downloadDocument. Downloads a document. It applies only to a document node, and can be done by opening its download URL. • showProperties. Shows a folder or a document’s metadata. These data are stored in an entry that comes from the parent’s feed service. A simple XUL dialog propertyDialog.xul file is also created to show these properties. Refer to this file for more details. 5.6.7 Adding libraries to a connector For a user to add a document library to the list shown by this connector, there are two steps involved.. First, the user must enter the server information in the Add Library dialog box and click Next (see figure 5). Figure 5. Input server information At this point, the document feed service http://host:port/dm/atom/libraries is called to get all the libraries that the server hosts, after which a library treeview will display as shown in figure 6. Figure 6. Select libraries All the XUL elements in this view are defined in addLibrary.xul. When the dialog is launched, the initialize function addLibraryInit filters out the elements to display from the first step. When the user clicks the Next button, doNext is called to hide some elements and display others. To hide or display an element, the hide attribute is set to true or false. When the user clicks the Save button, doOK is called to prepare data and call the callback function to save the list of libraries locally. 6. Conclusion Lotus Quickr provides rich and powerful REST/SOAP services to customize the functions of servers. This article has demonstrated how to use Quickr document REST services to build a customized Firefox connector. Through these programming interfaces you can build your own Quickr connectors easily and quickly. 7. Resources • developerWorks Lotus Quickr product page: http://www.ibm.com/developerworks/lotus/products/quickr/?S_TACT=105AGX1 3&S_CMP=LP • Lotus Quickr application programming interfaces: http://www-10.lotus.com/ldd/lqwiki.nsf/dx/documents-services • Lotus Quickr Enablement Materials: http://www-10.lotus.com/ldd/lqwiki.nsf/dx/ibm-lotus-quickr-technical-enablement -materials-for-business-partners • Lotus Quickr documentation page: http://www.ibm.com/developerworks/lotus/documentation/quickr/ • Mozilla Developer Center, Main page: https://developer.mozilla.org/En • Dojo Toolkit: http://www.dojotoolkit.org 8. About the authors Shun Zhang is a software engineer for IBM in Beijing, with a focus on Lotus Quickr, and Web 2.0 and SOA technologies. You can reach him at [email protected]. Hui Jian He is a staff software engineer for IBM in Beijing, focusing on Lotus Quickr from its first release. Before that he worked on IBM Workplace Collaboration Services, WebSphere Portal, and Workplace Services Express products. You can reach him at [email protected]. Acknowledgement The authors would like to thank Greg Melahn for his valuable assistance in technically reviewing this paper. Trademarks • • • • developerWorks, FileNet, IBM, Lotus, Notes, Quickr, Sametime, and Symphony are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both. Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States, other countries, or both. Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Other company, product, and service names may be trademarks or service marks of others.