|
HowToDevelopAnEditorPlugin
Guideline on how to develop a plugin
IntroductionOryx 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 PluginServer 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 FileLet 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 EventsIf 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 FilesPlease go here to learn more about internationalization in Oryx. Configure a PluginTo 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 FacadeThe 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 offeroffer(pluginData): void Parameters:
keyCodes: [{
metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
keyCode: 67,
keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
}]
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. getStencilSetsgetStencilSets(): 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. getRulesgetRules(): 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. loadStencilSetloadStencilSet(source:URL): void Parameters:
Description: Calling this method loads a stencil set and fires a stencilSetLoaded event. createShapecreateShape(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. deleteShapedeleteShape(shape:ORYX.Core.Shape): void Parameters:
getSelectiongetSelection(): ORYX.Core.Shape[] Returns: An array of shape objects that are selected. setSelectionsetSelection(elements:ORYX.Core.Shape[], subSelectionElements:ORYX.Core.Shape[]): void Parameters:
Description: Set the selection of shape objects with this method. The method also fires a "selectionChanged" event. updateSelectionupdateSelection(): void Description: Fires a "selectionChanged" event. getCanvasgetCanvas(): ORYX.Core.Canvas Returns: The editor's canvas object. importJSONimportJSON(jsonObject: JSON, noSelectionAfterImport: boolean): ORYX.Core.Shape[] Parameters:
Returns: An array of all created shapes. importERDFimportERDF(erdfDOM: XMLDocument): ORYX.Core.Shape[] Parameters:
Returns: An array of all created shapes. getERDFgetERDF(): string Returns: A string that represents the current model in eRDF format. executeCommandsexecuteCommands(commands: ORYX.Core.Command[]): void Parameters:
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. registerOnEventregisterOnEvent(eventType: string, callback: function): void Parameters:
Description: Use this method to react on event occurrence. unregisterOnEventunregisterOnEvent(eventType: string, callback: function): void Parameters:
Description: Use this method to stop reacting on an event occurrence. raiseEventraiseEvent(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. enableEventenableEvent(eventType: string): void Parameters:
disableEventdisableEvent(eventType: string): void Parameters:
eventCoordinates(event: Event): SVGPointeventCoordinates(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. addToRegionaddToRegion(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