My favorites | Sign in
Logo
                
Search
for
Updated Apr 27, 2009 by sven.wagnerboysen
Labels: Featured
HowToDevelopAnEditorPlugin  
Guideline on how to develop a plugin

Introduction

Oryx can easily be extended by implementing a plugin. Most of the features are implemented as plugins. Plugins can be implemented on client side and on server side. Both types will be explained here.

Create a Server Side Plugin

Server side plugins are simply Java Servlets that extends the class javax.servlet.http.HttpServlet. If you want to know more about Java Servlets go here. You can add your servlet to the folder trunk/editor/server/src/org/oryxeditor/server. The web.xml file where you have to add information about your servlet can be found in trunk/editor/etc. You should also define the URL of your servlet in the editor's config.js file.

Create a Client Side Plugin

With client side plugins you can extend the functionality of the editor. For example, you can implement an import plugin for a specific data format. This feature will be offered in the toolbar to the user. Plugins can access the editor's core via the facade (see below) that defines an interface. The communication between different plugins is realized via an event mechanism.

The following steps must be performed when implementing a plugin:

Create a Plugin File

Let us first create the plugin file to get to know the general structure of a plugin. I will use the undo/redo plugin as an example. All plugins can be found in trunk/editor/client/scripts/Plugins. You have to add your own plugin to this directory. The undo/redo plugin file is called undo.js. Let us have a look at the file:

if (!ORYX.Plugins) 
    ORYX.Plugins = new Object();

ORYX.Plugins.Undo = Clazz.extend({
	
  // Defines the facade
  facade		: undefined,
    
  // Defines the undo/redo Stack
  undoStack	: [],
  redoStack	: [],
	
  // Constructor 
  construct: function(facade){
    
    this.facade = facade;     
		
    // Offers the functionality of undo                
    this.facade.offer({
      name		: ORYX.I18N.Undo.undo,
      description	: ORYX.I18N.Undo.undoDesc,
      icon		: ORYX.PATH + "images/arrow_undo.png",
      functionality	: this.doUndo.bind(this),
      group		: ORYX.I18N.Undo.group,
      isEnabled		: function(){ return this.undoStack.length > 0 }.bind(this),
			   index			: 0
		          }); 

    // Offers the functionality of redo
    this.facade.offer({
      name		: ORYX.I18N.Undo.redo,
      description	: ORYX.I18N.Undo.redoDesc,
      icon		: ORYX.PATH + "images/arrow_redo.png",
      functionality	: this.doRedo.bind(this),
      group		: ORYX.I18N.Undo.group,
      isEnabled		: function(){ return this.redoStack.length > 0 }.bind(this),
			    index			: 1
		          }); 
		
    // Register on event for executing commands-->store all commands in a stack		 
    this.facade.registerOnEvent(ORYX.CONFIG.EVENT_EXECUTE_COMMANDS,
      this.handleExecuteCommands.bind(this) );
    	
  },
	
  handleExecuteCommands: function( evt ){
		
    //...
		
  },
	
  doUndo: function(){
	
    //...
	
  },
	
  doRedo: function(){
		
    //...
  }
	
});

The Undo class is part of the namespace ORYX.Plugins. It extends the Clazz object that is used throughout the whole project as the base class. For example, it adds a constructor (function construct) that is automatically called when a new Object of that type is created. The constructor has a single parameter and that is a reference to the editor's facade.

Let us now have a look at the constructor. This plugin has two features: undo and redo. Both features must be registered with the facade's offer method. Other plugins like the toolbar will get a notification when new features are registered and make it available to the user. If you want to create your own UI component, you have to implement an Ext component and add it to the UI with the facade's addToRegion method. To learn more about Ext development, please go here. Note that the current Ext version we use is 2.0.2.

The undo/redo plugin also registers a callback on an event. Whenever the event ORYX.CONFIG.EVENT_EXECUTE_COMMANDS is fired, the callback will be executed. The callback's parameters are event specific. If you cannot find information about the parameters in the config.js, search in other plugins for the event to find out the parameters on your own.

The rest of the methods in the plugin are the callbacks of the registered features and for the event. You can add any number of methods to the plugin object and perform any operation you like.

The server communication must implemented with Ajax requests. You can use the Ajax object of the Prototype library or the Ajax object of Ext.

Define Events

If you want to define your own event, you can do so by adding a constant for the event to the config.js. Please provide some information about the event and its parameters.

Define Strings in Translation Files

Please go here to learn more about internationalization in Oryx.

Configure a Plugin

To make a plugin available in the editor you have to register it in the plugins configuration file (trunk/editor/client/scripts/Plugins/plugins.xml). For our example, you have to add the following line to the file:

<plugin source="undo.js" name="ORYX.Plugins.Undo" />

The attribute source is the name of the Javascript file, the attribute name specifies the name of the plugin's class.

Three configuration options are available. First you can define properties for a plugin that are passed to the plugins constructor. For example, the shapemenu plugin has the following properties:

<plugin source="shapemenu.js" name="ORYX.Plugins.ShapeMenuPlugin">			
  <property group="Z-Order" align="Oryx_Top" />
  <property group="Alignment" align="Oryx_Top" />
  <property group="Grouping" align="Oryx_Top" />
  <property group="Edit" align="Oryx_Left" />					
</plugin>

Second, you can reference a stencil set via its namespace and define it as required. For example, the epcSupport plugin implements features that only makes sense for EPC models. Therefore, it requires the EPC stencil set:

<plugin source="epcSupport.js" name="ORYX.Plugins.EPCSupport">
  <requires namespace="http://b3mn.org/stencilset/epc#"/>	
</plugin>

Third, you can explicitly exclude a stencil set:

<plugin source="file.js" name="ORYX.Plugins.Save">
  <notUsesIn namespace="http://b3mn.org/stencilset/xforms#"/>
</plugin>

The Facade

The facade is the interface to access the editor. The interface object is one of the parameters of a plugin's constructor. The following methods are defined in the interface:

offer(pluginData: Object): void

getStencilSets(): Hash
getRules(): ORYX.Core.StencilSet.Rules
loadStencilSet(source:URL): void

createShape(option:Object): ORYX.Core.Shape
deleteShape(shape:ORYX.Core.Shape): void
getSelection(): ORYX.Core.Shape[]
setSelection(elements:ORYX.Core.Shape[], subSelectionElements:ORYX.Core.Shape[]): void
updateSelection(): void
getCanvas(): ORYX.Core.Canvas

importJSON(jsonObject: JSON, noSelectionAfterImport: boolean): ORYX.Core.Shape[]
importERDF(erdfDOM: XMLDocument): ORYX.Core.Shape[]
getERDF(): string

executeCommands(commands: ORYX.Core.Command[]): void
registerOnEvent(eventType: string, callback: function): void
unregisterOnEvent(eventType: string, callback: function): void
raiseEvent(event: Object, uiObj: ORYX.Core.!UIObject): void
enableEvent(eventType: string): void
disableEvent(eventType: string): void
eventCoordinates(event: Event): !SVGPoint

addToRegion(region: string, component: Ext.Component, title: string): Ext.Component

offer

offer(pluginData): void

Parameters:

Description:

A plugin must register each of its features with this method. This method shall be called in the constructor of the plugin. Once registered, the features are available in the toolbar or any other plugin that offers a UI for accessing other plugins' features.

getStencilSets

getStencilSets(): Hash

Returns:

A hash object with the stencil sets' namespaces of all available stencil sets as keys and the stencil set objects (ORYX.Core.StencilSet.StencilSet) as values.

Description:

This method is used for accessing the loaded stencil sets.

getRules

getRules(): ORYX.Core.StencilSet.Rules

Returns:

An object of type ORYX.Core.StencilSet.Rules that enables you to check if two shapes can be connected or contain each other.

loadStencilSet

loadStencilSet(source:URL): void

Parameters:

Description:

Calling this method loads a stencil set and fires a stencilSetLoaded event.

createShape

createShape(option:Object): ORYX.Core.Shape

Parameters:

Returns:

The created shape object.

Description:

This method will soon be reimplemented, because it was initially designed for a specific case. If you need it, check the code where the method is used.

deleteShape

deleteShape(shape:ORYX.Core.Shape): void

Parameters:

getSelection

getSelection(): ORYX.Core.Shape[]

Returns:

An array of shape objects that are selected.

setSelection

setSelection(elements:ORYX.Core.Shape[], subSelectionElements:ORYX.Core.Shape[]): void

Parameters:

  • elements: ORYX.Core.Shape
    • Shape objects to select.
  • subSelectionElements: ORYX.Core.Shape
    • A sub set of the selected objects for sub selection.

Description:

Set the selection of shape objects with this method. The method also fires a "selectionChanged" event.

updateSelection

updateSelection(): void

Description:

Fires a "selectionChanged" event.

getCanvas

getCanvas(): ORYX.Core.Canvas

Returns:

The editor's canvas object.

importJSON

importJSON(jsonObject: JSON, noSelectionAfterImport: boolean): ORYX.Core.Shape[]

Parameters:

Returns:

An array of all created shapes.

importERDF

importERDF(erdfDOM: XMLDocument): ORYX.Core.Shape[]

Parameters:

Returns:

An array of all created shapes.

getERDF

getERDF(): string

Returns:

A string that represents the current model in eRDF format.

executeCommands

executeCommands(commands: ORYX.Core.Command[]): void

Parameters:

  • commands: ORYX.Core.Command
    • Array of Command objects. The Command class is abstract and must be extended by a sub class. The Command class defines the methods execute and rollback.

Description:

If your feature needs undo/redo support, you have to implement it as a sub class of ORX.Core.Command and execute it with this method.

registerOnEvent

registerOnEvent(eventType: string, callback: function): void

Parameters:

Description:

Use this method to react on event occurrence.

unregisterOnEvent

unregisterOnEvent(eventType: string, callback: function): void

Parameters:

Description:

Use this method to stop reacting on an event occurrence.

raiseEvent

raiseEvent(event: Object, uiObj: ORYX.Core.UIObject): void

Parameters:

Description:

Use this method to fire an event. For event.type use one of the constants defined in config.js.

enableEvent

enableEvent(eventType: string): void

Parameters:

disableEvent

disableEvent(eventType: string): void

Parameters:

eventCoordinates(event: Event): SVGPoint

eventCoordinates(event: Event): SVGPoint

Parameters:

Returns:

An SVGPoint that is the mouse position on the canvas.

Description:

Mouse events define the mouse position relative to the origin of the page. To find out the mouse position relative to the canvas, you can use this method.

addToRegion

addToRegion(region: string, component: Ext.Component, title: string): Ext.Component

Parameters:

Returns:

The added Ext.Component object.

Description:

Use this method to add a new UI component to the editor's UI.



Sign in to add a comment
Hosted by Google Code