Skip to content
Javier Pedemonte edited this page Aug 19, 2011 · 1 revision

Table of Contents

About this wiki page

NOTE: THE INFORMATION HERE IS LIKELY AT LEAST PARTLY OUT OF DATE. MUCH OF THE CONTENT WAS WRITTEN 11/2009

This wiki page documents Maqetta's current plugin system (using the BBT mini app framework) and then lists possible areas for changes.

Existing code base

davinci/Runtime.js

Key data structures

  • this.plugins: associative array, one entry for each plugin that is loaded
  • this.extensionPoints: associative array, one entry for each type of extension point in the system. Each entry is an array that holds all registered extensions for that particular extension point.
  • this.subscribtions: list of subscribers that previously called davinci.Runtime.subscribe()
    • Do we have a unified publish/subscribe system in the code today?
    • Shouldn't we use OAHub for pubsub? That would allow pubsub for both inline components and iframe'd components
  • this.currentSelection: list of subscribers that previously called davinci.Runtime.subscribe()
    • Is this used, or is there a different mechanism for managing selection?
  • this.commandStack: set to new davinci.commands.CommandStack(). Just a pointer. Command stack is managed by a different JS file.
  • this.clipboard: not used at this point

Extension points

  • davinci.actionSets - ?
  • davinci.actionSetPartAssociations - ?
  • davinci.editor - ?
  • davinci.editorActions - ?
  • davinci.keyBindings - Key bindings as you would expect. Only one key binding so far, defined in js_plugin.js: { platform : "win" /*???*/, sequence: "M1+C", commandID : "davinci.js.copy" , contextID : "davinci.js.JSEditor"}. Retrieved by davinci/Workbench.js.
  • davinci.perspective - ?
  • davinci.preferences - plugins can add new categories to preferences dialog. At this point, it appears that a plugin must provide an entire preferences pane (via the 'pane' property on the JS object passed into the davinci.preferences extension point). For example, the davinci/htmledit/htmledit_plugin.js plugin adds the "Visual Editor" preferences pane to the "davinci.html.general" (i.e., "HTML") preferences category, where the 'pane' property is set to "davinci.htmledit.HTMLEditPreferences" because that's the class that renders the Visual Editor Preferences pane, and is found in file "davinci/htmledit/HTMLEditPreferences.js" (loaded by virtue of a dynamic call to dojo.require("davinci.htmledit.HTMLEditPreferences"). In the current code:
    • js_plugin.js defines the "davinci.js.general" category and the "davinci.js.format" sub-category (with pane "davinci.js.ui.formatOptions")
    • html_plug.js defines the "davinci.html.general" category
    • htmledit_plugin.js defines the "davinci.htmledit.htmledit" sub-category (with pane "davinci.htmledit.HTMLEditPreferences")
    • Can plugins append new preferences items to an existing pane, or must a plugin always create a new pane?
    • Is there a way with the current code that the main Maqetta app can control the order of the items in the preferences dialog? It might be better from a UI perspective to put preferences in a particular order
  • davinci.prop.edit - ?
  • davinci.properties.pages - ?
  • davinci.view - ?
  • davinci.viewActions - ?

davinci.Runtime.addPlugin(pluginName)

  1. url = "./" + pluginName + "_plugin.js";
  2. Then does a synchronous dojo.xhrGet to grab the plugin file
  3. Passes the responseObject to davinci.Runtime._loadPlugin(responseObject,url)

davinci.Runtime.run()

Two lines of code:

this.subscribe("/davinci/ui/selectionChanged",davinci.Runtime._selectionChanged );
davinci.Workbench.run();

davinci.Runtime._loadPlugin(plugin,url)

Notes:

  • plugin holds JS object that is the plugin
  • url is the relative URL for the JS file that contained the plugin's JS source code
  • Plugin added to list of plugins:
var pluginID = plugin.id;
this.plugins[pluginID]= plugin;
  • Load associated CSS file, if present
if (plugin.css)
  this._loadCSS(plugin,url);
  • Add all extensions defined in the plugin
    • Loop through all properties of the plugin object (for ( var id in plugin) {...})
    • Properties of type 'string': ignore
    • Properties of type 'object': call this._addExtension() on the property's object value
    • Properties of type 'array': call this._addExtension() on each of the array's children
    • Note: Not bulletproof. What if property is of type Regexp, Date or Function? What if array children are not objects?

davinci.Runtime._addExtension(id, extension, pluginID)

Boils down to:

  • this.extensionPoints[id].push(extension);

davinci.Runtime.getExtensions(extensionID, testFunction), davinci.Runtime.getExtension(extensionID, testFunction)

If testfunction is a function, then candidate extensions at extension point this.extensionPoints[extensionID] are run through the testFunction as a filter function. Otherwise, testfunction is assumed to be a particular extension name, and only candidate extensions that have the given extension name are matched.

davinci.Runtime.getExtensions(extensionID, testFunction) returns all matches. davinci.Runtime.getExtensions(extensionID, testFunction) returns the first match.

davinci.Runtime._loadCSS()

Loads a CSS file to the HEAD as a LINK element. The CSS file is assumed to be either in the same folder as the plugin JS file or a deeper folder.

davinci.Runtime.executeCommmand()

Only called by Workbench.js

  • How does this relate to the dojoy command stack?

davinci.Runtime._selectionChanged(selection), davinci.Runtime.getSelection()

davinci.Runtime._selectionChanged(selection) is the callback for a subscription to "/davinci/ui/selectionChanged".

davinci.Runtime.getSelection() is only called by davinci/resource.js.

  • How does the selection logic here relate to the other selection logic elsewhere in the code base?

davinci.Runtime.doLogin()

Called only if serverJSONRequest returns a 401 error code.

  • Which workflows invoke this code?

davinci.Runtime.serverJSONRequest(ioArgs), davinci.Runtime.serverPut(args)

davinci.Runtime.serverJSONRequest(ioArgs) is called by the following:

  • pagedesigner.html: at launch time, sends a /MaqettaCmd/getUserInfo request to server
  • resource.js:
    • davinci.resource.Resource.deleteResource: sends a /MaqettaCmd/deleteResource request to server
    • davinci.resource.Resource.createResource: sends a /MaqettaCmd/createResource request to server
    • davinci.resource.Resource.getChildren: sends a /MaqettaCmd/listfiles request to server
    • davinci.resource.Resource.getContents: sends a /MaqettaCmd/loadFile request to server

The plugins

(need to sketch out the role of each of the built-in plugins)

Looking forward

This section contains notes about changes we might want to make to the existing plugin system:

Questions:

  • Is the code set up such that a plugin consists of a directory tree?
  • Are plugins relocatable or must they appear in a particular location within the Maqetta directory structure?

Kinds of plugins we might support

Client-side JavaScript plugins

Probably will use Eclipse Orion's plugin technology for 3rd party macro-plugins and RequireJS/AMD for project-internal micro-plugins.

Server-side JavaScript plugins

May want to integrate NodeJS into our server

Widgets

Ultimately, we need to support OpenSocial Gadgets. These "widget" technologies represent a specialized type of extension to Maqetta.

We need the ability for sites and users to add their own widget libraries to their copy of Maqetta.

Extension points

This is the hard part of our extensibility story: how we allow extensions to interact with the core.

Clone this wiki locally