wiki:Plugin_API_Draft

Version 4 (modified by offwhite, 6 years ago) (diff)

--

RoundCube vNext

This is a proposal for a re-write of RoundCube to implement a Plugin-API. If you have feedback, please discuss on the developer mailinglist.

Objective

RoundCube vNext will feature a rich plugin architecture allowing the end-user to select plugins to customize their installation to suit their needs. Plugins will make use an AJAX architecture making use of static HTML pages with Javascript communication with the server by passing JSON messages. The server-side software will not emit HTML or Javascript. It will be limited to only JSON messages.

Architecture

The system design will make use of the clean separation of HTML, CSS and Javascript to draw the user interface. Static files will make up the templates to display. These templates will be made up of HTML and CSS with Javascript references which activate as the page is loading. The Javascript will make a server callback to request JSON messages to get data to display using the templates. The templates will provide a basic structure: control tray, folder tray and the message tray.

Control Tray

This tray will hold buttons and other interface controls. There will be a default set but a plugin may request to have more controls added to this tray.

Folder Tray

This tray will hold folders which are used to navigate to organize messages. Currently folders just hold email messages but a plugin could use them to hold entries from an RSS feed as well.

Message Tray

This tray will both display a listing of the messages for the currently active folder as well as display the full content of a message.

This architecture will make use of the lightweight Javascript library !jQuery. It is only 20k in size and provides features to instrument HTML elements on the page as well as AJAX functionality. It also has a unique feature to detect whether the DOM for a page is ready so that it can start instrumenting a page ahead of the OnLoad event firing. By activating some initialization code when the DOM is ready it is possible to make the page appear as if it was all loaded together. The following is an example for calling the ready function.

$(document).ready(function() {

   // make AJAX requests for !PageInit
 });

On the first page load the Javascript will run a series of requests. First it will load any page settings which may customize the page of the user. It will then request all of the folder data and activate the Inbox folder. Activating a folder will cause it to request message data from the server and populate the message tray. At each step the data pulled from the server will be JSON messages and events will be raised at various steps where hooks can be placed for the plugin architecture.

Hooks for Plugins

The following are locations where hooks will be placed to provide plugin support:

  • PageInit - called once the page is first initialized
  • ControlTrayInit - called when the control tray is initialized
  • FolderTrayInit - called when the folder tray is initialized
  • MessageTrayInit - called when the message tray is initialized
  • FolderSelecting - called when a folder is being selected (before, with the option to cancel)
  • FolderSelected - called after a folder has been selected (after)
  • MessageShowing - called when a message is being shown (before, with the option to cancel)
  • MessageShowed - called after a message has been shown (after)
  • MessageDropping - called when a message is being dropped on a folder (before, with the option to cancel)
  • MessageDropped - called after a message has been dropped on a folder (after)
  • MessageReceived - called when a new message has been received
  • MessageComposing - called when a new message is composed/written
  • MessageSending - called when a message is being send
  • MessageSent - called when a message has been send
  • UserLogin - called when a user logs into RoundCube
  • UserLoggedin - called when the login was successful
  • UserLogout - called when a user logs out from RoundCube

Other events related to logging in and logging out may also be useful.

JSON Messaging

The messaging between the client and server will be managed with Javascript and will be made up of JSON messages.

Example Javascript API

The static HTML will be adjusted only by the Javascript API which is designed to work with the structure of the template as described in the Architecture section. In the following example there are two Javascript objects: RoundCube.ControlTray? and RoundCube.Button. The RoundCube.Button is constructed with name and action and the RoundCube.ControlTray has a method called addButton to add an RoundCube.Button and another method, !updateTray, which updates the display. Internally the RoundCube.C!ontrolTray holds an array of buttons which is initialized with the first 3 buttons. The example then adds 2 more buttons from the page itself using the RoundCube.ControlTray? methods. At no point in this code is HTML created as strings. It instead uses the DOM functionality of HTML and Javascript to add elements to the HTML structure. Once the buttons are added to the tray the OnClick event is set to the action of the RoundCube.Button. You can click them to cause that action to run. For the example it simply runs alert with the numerical representation of the button name to show the actions are associated with their respective button. These alerts could instead call other API function on the RoundCube.ControlTray or more likely on objects which have not been built yet, such as RoundCube.Core, RoundCube.FolderTray, RoundCube.MessageTray.

This example also simulates namespacing which gives the objects a hierarchy. This namespace scheme will keep the code organized. Plugins would be isolated to the RoundCube.!Plugins namespace and perhaps inherit from an object called RoundCube.!Plugins.Base.

Of course this is just the client-side which is all Javascript which instruments the HTML structure of the page. The server-side will be all PHP which emits JSON messages to the Javascript through AJAX requests. A JSON message from could send a message from the server with the following action.

[
    {
      instruction : 'addControlTrayButton',
      name : 'Four',
      action : 'alert("4");'
    }
]

This instruction would be interpreted to add a new button to the ControlTray?. The action in this case is a string which can be run with the Javascript eval statement. All button actions could be wrapped safely within a Try..Catch block with the catch block routing the error to the RC error message display mechanism. The buttons can also have different times, such as link or image buttons. The JSON messages can also carry multiple instructions so there do not need to be multiple calls to get all of the instructions.

[
    {
      instruction : '!addControlTrayButton',
      name : 'Four',
      action : 'alert("4");'
    },
    {
      instruction : '!addControlTrayButton',
      name : 'Five',
      action : 'alert("5");'
    }
]

This example shows how the RoundCube.ControlTray object adds the 3 default buttons while an external script adds 2 more buttons. This is exactly how the third-party plugins would use the API to extend RoundCube.

Initial Example

Example with JSON

The JSON instructions cause the last 2 buttons to be added to the ControlTray. The new object RoundCube.!Application coordinates all of the work.