(Plugin Definition & Event Types sections added) |
(Plugin Command Class section added) |
||
Line 104: | Line 104: | ||
</table> | </table> | ||
+ | === Plugin Command Class === | ||
+ | Another obligatory step in the plugin creation process is writing the plugin command class. This class has to implement the <code>com.ckfinder.connector.data.IEventHandler</code> interface which forces us to implement the <code>runEventHandler</code> method. The <code>runEventHandler</code> method is the place where the plugin command is executed. | ||
+ | The class should look like this: | ||
+ | <source lang="java"> | ||
+ | package com.ckfinder.connector.plugins; | ||
+ | import com.ckfinder.connector.configuration.IConfiguration; | ||
+ | import com.ckfinder.connector.data.EventArgs; | ||
+ | import com.ckfinder.connector.data.IEventHandler; | ||
+ | import com.ckfinder.connector.errors.ConnectorException; | ||
+ | public class FileSizeCommand implements IEventHandler { | ||
+ | public boolean runEventHandler(EventArgs args, IConfiguration configuration1) | ||
+ | throws ConnectorException { | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | The <code>runEventHandler</code> method has two parameters: <code>EventArgs</code> and <code>IConfiguration</code>. The <code>IConfiguration</code> object contains all CKFinder configuration options. <code>EventArgs</code> is an abstract class representing one of its implementations. There is one <code>EventArgs</code> implementation class for each event type. | ||
+ | The table below lists the <code>EventArgs</code> implementations for each of the event types. | ||
+ | <table summary="EventArgs Implementations" class="borders"> | ||
+ | <caption>EventArgs Implementations</caption> | ||
+ | <tr> | ||
+ | <th>Event Type</th> | ||
+ | <th>EventArgs Implementation</th> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td><code>EventTypes.AfterFileUpload</code></td> | ||
+ | <td><code>com.ckfinder.connector.data.AfterFileUploadEventArgs</code></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td><code>EventTypes.BeforeExecuteCommand</code></td> | ||
+ | <td><code>com.ckfinder.connector.data.BeforeExecuteCommandEventArgs</code></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td><code>EventTypes.InitCommand</code></td> | ||
+ | <td><code>com.ckfinder.connector.data.InitCommandEventArgs</code></td> | ||
+ | </tr> | ||
+ | </table> | ||
+ | |||
+ | These implementation classes store data gathered from the event caller that are necessary to execute the plugin command. | ||
+ | |||
+ | The FileSizePlugin has to handle a non-standard server command, which means that the <code>BeforeExecuteCommandEventArgs</code> implementation of the <code>EventArgs</code> class will be needed for this example. This information is crucial since one of the first things we should do in the <code>runEventHandler</code> method is to cast <code>EventArgs</code> to its appropriate implementation. See the code below: | ||
+ | <source lang="java"> | ||
+ | public boolean runEventHandler (EventArgs args, IConfiguration configuration1) | ||
+ | throws ConnectorException { | ||
+ | BeforeExecuteCommandEventArgs args1 = (BeforeExecuteCommandEventArgs) args; | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | This method returns a Boolean object which determines whether code execution should be continued after the <code>runEventHandler</code> method was run. For plugins that support the <code>InitCommand</code> and <code>AfterFileUpload</code> events the value that is returned does not matter since no code is executed afterwards. | ||
+ | |||
+ | CKFinder has built-in support for such commands as <code>GetFiles</code>, <code>CreateFolder</code>, or <code>RenameFolder</code>. When adding a new command with a plugin it is necessary to instruct CKFinder that the command has already been handled. You can achieve this by returning <code>false</code> inside the <code>runEventHandler</code> menthod after the non-standard command was executed. | ||
+ | |||
+ | The FileSizePlugin is an example of a <code>BeforeExecuteCommand</code> plugin, so if <code>FileSize</code> is the command that is being sent to the server, the plugin should handle it and then return <code>false</code> to prevent further search. | ||
+ | |||
+ | The code below does just that: | ||
+ | <source lang="java"> | ||
+ | public boolean runEventHandler (EventArgs args, IConfiguration configuration1) | ||
+ | throws ConnectorException { | ||
+ | BeforeExecuteCommandEventArgs args1 = (BeforeExecuteCommandEventArgs) args; | ||
+ | if ("FileSize".equals(args1.getCommand())) { | ||
+ | return false; | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | If <code>FileSize</code> is not the command used inside the <code>runEventHandler</code> method, the method should return <code>true</code> to allow for further search. | ||
+ | |||
+ | It is also worth mentioning that the <code>runEventHandler</code> method of a particular plugin does not have to handle the command sent from the client. As an example, it can be used to just insert something into a database or log information about the user activity. | ||
+ | |||
+ | The client code expects an answer in the form of XML code (see the <code>xml.selectSingleNode( 'Connector/FileSize/@size' );</code> line from the <code>plugin.js</code> file). This means that FileResizePlugin has to return an XML response. We will use the <code>XMLCommand</code> class to achieve this purpose; extending this class in the plugin makes us implement its two methods: | ||
+ | * <code>createXMLChildNodes(int errorCode, Element rootElement)</code> – this method adds all extra XML nodes to the response that will be read by a plugin on the client side. It has two parameters: | ||
+ | ** <code>errorCode</code> – an error number returned from the <code>getDataForXml</code> method; | ||
+ | ** <code>rootElement</code> which represents main XML node <code>Connector</code>. | ||
+ | * <code>getDataForXml()</code> – should perform all validation and execute necessary plugin tasks. If all validations were performed correctly and command tasks were executed without raising an exception, this method should return the <code>CKFINDER_CONNECTOR_ERROR_NONE</code> constant. | ||
+ | |||
+ | <source lang="java"> | ||
+ | @Override | ||
+ | protected int getDataForXml() { | ||
+ | return Constants.Errors.CKFINDER_CONNECTOR_ERROR_NONE ; | ||
+ | } | ||
+ | </source> | ||
Revision as of 12:44, 17 May 2011
Contents
The main advantages of plugins are:
- Upgrades are much easier.
- The plugin code is stored in a single place.
- Plugins can be easily disabled when they are not needed anymore.
Common use cases:
- Adding a new server-side command (i.e.
fileditor
andimageresize
plugin). - Working with uploaded files (i.e.
watermark
plugin). - Extending information returned by the
Init
command (i.e.imageresize
plugin).
Creating CKFinder for Java Plugins
As mentioned in the Using CKFinder Plugins article, the functionality of CKFinder can be extended with code that is delegated to dedicated plugins. This architecture ensures that you do not need to modify CKFinder core to change the behavior of the application — using plugins is much more convenient.
This tutorial shows how to create a CKFinder plugin on the example of a FileSizePlugin which, as the name suggests, returns the size of the file.
In order to create a CKFinder plugin, you will need to follow the steps below:
- Step 1: Create the plugin folder and file.
- Step 2: Add the plugin definition.
- Step 3: Make CKFinder aware of the new plugin.
Please note that for plugins that just add server-side functionality and do not contain any client-side scripts you can skip the first step.
Creating Plugin Folder and File
For a start, you need to create a directory for your plugin inside the /CKFinderJava-X.Y/ckfinder/plugins
directory. Please note that by default CKFinder comes with three client-side plugins: dummy
, fileeditor
, and imagresize
.
Since our plugin is named filesizeplugin
, the same name will be used for its folder. Inside the newly created filesizeplugin
folder we are going to place the plugin.js
file that will contain the plugin logic.
Open the plugin.js
file in an editor and add the following source code:
CKFinder.addPlugin( 'filesizeplugin', function( api ) { // The name of the plugin. api.addFileContextMenuOption( { label : 'File Size', command : "FileSize" } , function( api, file ) { api.connector.sendCommand( 'FileSize', { fileName : api.getSelectedFile().name }, function( xml ) { if ( xml.checkError() ) return; var size = xml.selectSingleNode( 'Connector/FileSize/@size' ); api.openMsgDialog( "", "The exact size of a file is: " + size.value + " bytes"); } ); }); });
Since the purpose of this tutorial is to show how to integrate plugins with CKFinder, we are not going to go into details of the JavaScript code. To sum it up, the plugin code above adds a new menu item to the user interface. This item, when selected, sends the FileSize
command to the server, reads the XML response and displays the size of the queried file in a dialog window.
For more information on how to create JavaScript plugins refer to the Writing JavaScript Plugins article.
Making CKFinder Aware of the Plugin
Fast forward one step, this section describes how to make CKFinder aware that the plugin exists. Open the config.xml
file and add a new plugin
node to the plugins
section.
<plugin> <name>filesizeplugin</name> <class>com.ckfinder.connector.plugins.FileSizePlugin</class> <params></params> </plugin>
A plugin entry contains the following elements:
-
<name>
– the name of the plugin that should be the same as the plugin folder name on the client side. -
<class>
– the plugin class extended fromcom.ckfinder.connector.configuration.Plugin
. -
<params>
– additional plugin parameters. A parameter is added with aparam
node:-
<param name="smallThumb" value="90x90" />
-
Adding the Plugin Definition
When the CKFinder application starts, it reads plugins declared in the XML configuration file and binds their commands to particular event types. In other words, event handlers are registered for plugins.
To make the registration process work, a plugin class has to be created first. This class has to implement the registerEventHandlers
method inside which the plugin command is joined with an appropriate event type. This binding is possible thanks to the application of the addEventHandler
method:
eventHandler.addEventHandler(EventTypes.BeforeExecuteCommand, FileSizeCommand.class);
This method has two parameters: the event type, which determines when the command should be invoked, and Command.class
(FileSizeCommand.class
in this case), which serves as an event handler.
Below is the source code of the FileSizePlugin
:
package com.ckfinder.connector.plugins; import com.ckfinder.connector.configuration.Events; import com.ckfinder.connector.configuration.Events.EventTypes; import com.ckfinder.connector.configuration.Plugin; public class FileSizePlugin extends Plugin { @Override public void registerEventHandlers(Events eventHandler) { eventHandler.addEventHandler(EventTypes.BeforeExecuteCommand, FileSizeCommand.class); } }
Event Types
There are three types of events. You might think of them as flags indicating when the event handlers should be invoked. The table below presents CKFinder event types.
Event Type | Description |
---|---|
EventTypes.AfterFileUpload |
Event handlers registered for this type of event will be executed after a successful file upload. |
EventsTypes.BeforeExecuteCommand |
Event handlers registered for this type of event will be executed before a standard server-side command is executed. |
EventTypes.InitCommand |
Event handlers registered for this type of event will be executed on CKFinder client-side startup, right before sending the result of the Init command. |
Plugin Command Class
Another obligatory step in the plugin creation process is writing the plugin command class. This class has to implement the com.ckfinder.connector.data.IEventHandler
interface which forces us to implement the runEventHandler
method. The runEventHandler
method is the place where the plugin command is executed.
The class should look like this:
package com.ckfinder.connector.plugins; import com.ckfinder.connector.configuration.IConfiguration; import com.ckfinder.connector.data.EventArgs; import com.ckfinder.connector.data.IEventHandler; import com.ckfinder.connector.errors.ConnectorException; public class FileSizeCommand implements IEventHandler { public boolean runEventHandler(EventArgs args, IConfiguration configuration1) throws ConnectorException { return false; } }
The runEventHandler
method has two parameters: EventArgs
and IConfiguration
. The IConfiguration
object contains all CKFinder configuration options. EventArgs
is an abstract class representing one of its implementations. There is one EventArgs
implementation class for each event type.
The table below lists the EventArgs
implementations for each of the event types.
Event Type | EventArgs Implementation |
---|---|
EventTypes.AfterFileUpload |
com.ckfinder.connector.data.AfterFileUploadEventArgs |
EventTypes.BeforeExecuteCommand |
com.ckfinder.connector.data.BeforeExecuteCommandEventArgs |
EventTypes.InitCommand |
com.ckfinder.connector.data.InitCommandEventArgs |
These implementation classes store data gathered from the event caller that are necessary to execute the plugin command.
The FileSizePlugin has to handle a non-standard server command, which means that the BeforeExecuteCommandEventArgs
implementation of the EventArgs
class will be needed for this example. This information is crucial since one of the first things we should do in the runEventHandler
method is to cast EventArgs
to its appropriate implementation. See the code below:
public boolean runEventHandler (EventArgs args, IConfiguration configuration1) throws ConnectorException { BeforeExecuteCommandEventArgs args1 = (BeforeExecuteCommandEventArgs) args; return false; } }
This method returns a Boolean object which determines whether code execution should be continued after the runEventHandler
method was run. For plugins that support the InitCommand
and AfterFileUpload
events the value that is returned does not matter since no code is executed afterwards.
CKFinder has built-in support for such commands as GetFiles
, CreateFolder
, or RenameFolder
. When adding a new command with a plugin it is necessary to instruct CKFinder that the command has already been handled. You can achieve this by returning false
inside the runEventHandler
menthod after the non-standard command was executed.
The FileSizePlugin is an example of a BeforeExecuteCommand
plugin, so if FileSize
is the command that is being sent to the server, the plugin should handle it and then return false
to prevent further search.
The code below does just that:
public boolean runEventHandler (EventArgs args, IConfiguration configuration1) throws ConnectorException { BeforeExecuteCommandEventArgs args1 = (BeforeExecuteCommandEventArgs) args; if ("FileSize".equals(args1.getCommand())) { return false; } return true; }
If FileSize
is not the command used inside the runEventHandler
method, the method should return true
to allow for further search.
It is also worth mentioning that the runEventHandler
method of a particular plugin does not have to handle the command sent from the client. As an example, it can be used to just insert something into a database or log information about the user activity.
The client code expects an answer in the form of XML code (see the xml.selectSingleNode( 'Connector/FileSize/@size' );
line from the plugin.js
file). This means that FileResizePlugin has to return an XML response. We will use the XMLCommand
class to achieve this purpose; extending this class in the plugin makes us implement its two methods:
-
createXMLChildNodes(int errorCode, Element rootElement)
– this method adds all extra XML nodes to the response that will be read by a plugin on the client side. It has two parameters:-
errorCode
– an error number returned from thegetDataForXml
method; -
rootElement
which represents main XML nodeConnector
.
-
-
getDataForXml()
– should perform all validation and execute necessary plugin tasks. If all validations were performed correctly and command tasks were executed without raising an exception, this method should return theCKFINDER_CONNECTOR_ERROR_NONE
constant.
@Override protected int getDataForXml() { return Constants.Errors.CKFINDER_CONNECTOR_ERROR_NONE ; }
Java Plugin System
Events
CKFinder provides several events that can be used to extend the functionality of a CKFinder application. Assigning a class (also known as an event handler) to an event will cause that function to be called at an appropriate point in the main CKFinder code to perform whatever additional task(s) the developer considers useful at that point. Each event can have multiple event listeners assigned to it.
Available Events
Hook | Since | Description |
---|---|---|
AfterFileUpload | 2.0 | Executed after successful file upload. |
BeforeExecuteCommand | 2.0 | Executed before a server side command is executed. |
InitCommand | 2.0 | Executed straight before sending the result of the Init command. |