Writing ASP.NET Plugins

This website contains links to software which is either no longer maintained or will be supported only until the end of 2019 (CKFinder 2). For the latest documentation about current CKSource projects, including software like CKEditor 4/CKEditor 5, CKFinder 3, Cloud Services, Letters, Accessibility Checker, please visit the new documentation website.

If you look for an information about very old versions of CKEditor, FCKeditor and CKFinder check also the CKEditor forum, which was closed in 2015. If not, please head to StackOverflow for support.

 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{CKFinder 2.x Writing Plugins Introduction}}
+
__TOC__{{CKFinder 2.x Writing Plugins Introduction}}
 
== Creating a plugin ==
 
== Creating a plugin ==
  
Line 17: Line 17:
 
==== Step4: Enable plugin ====
 
==== Step4: Enable plugin ====
  
In config.ascx add your plugin to the Plugins list:
+
* Copy .dll file with a plugin to the "bin" folder of your application
 +
* In config.ascx add your plugin to the Plugins list:
  
 
<source lang="asp">
 
<source lang="asp">
Line 63: Line 64:
 
{{CKFinder_2.x Sample Plugin Introduction|ext=aspx}}
 
{{CKFinder_2.x Sample Plugin Introduction|ext=aspx}}
  
==== Creating project ====
+
==== The project ====
Let's create a .dll file now.
+
Let's create a C# project now to generate a .dll file.
  
 
* Create a new C# project (Class Library).
 
* Create a new C# project (Class Library).
Line 71: Line 72:
 
* Rename the default file created by VS (Class1.cs) into FileSize.cs.
 
* Rename the default file created by VS (Class1.cs) into FileSize.cs.
  
The whole plugins will be in a single file (FileSize.cs).
+
The whole code will be in a single file (FileSize.cs).
 
For the sake of simplicity, let's take a look at '''Filesize.cs''' that just does exactly what we need:
 
For the sake of simplicity, let's take a look at '''Filesize.cs''' that just does exactly what we need:
 
<source lang="asp">
 
<source lang="asp">
Line 107: Line 108:
 
     public void Init( CKFinder.Connector.CKFinderEvent CKFinderEvent )
 
     public void Init( CKFinder.Connector.CKFinderEvent CKFinderEvent )
 
     {
 
     {
       // (1) Register our custom BeforeExecuteCommand event handler (MyBeforeExecuteCommandEventHandler function).
+
       // (1) Register our custom BeforeExecuteCommand event listener (MyBeforeExecuteCommandEventHandler function).
 
       CKFinderEvent.BeforeExecuteCommand +=  
 
       CKFinderEvent.BeforeExecuteCommand +=  
 
             new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );
 
             new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );
Line 136: Line 137:
  
 
==== Step1: Register an event handler ====
 
==== Step1: Register an event handler ====
<source lang="php">
+
<source lang="asp">
$config['Hooks']['BeforeExecuteCommand'][] = array($CommandHandler_FileSize, "onBeforeExecuteCommand");
+
CKFinderEvent.BeforeExecuteCommand +=  
 +
      new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );
 
</source>
 
</source>
  
==== Step2: Create a class ====
+
==== Step2: Create an event handler ====
If your plugin returns an XML response, you'll usually just extend the XmlCommandHandlerBase class to reduce the amount of code to write, however it is not a requirement.
+
<source lang="asp">
<source lang="php">
+
protected void MyBeforeExecuteCommandEventHandler( object sender, CKFinder.Connector.CKFinderEventArgs args )
// (2) Include base XML command handler
+
</source>
require_once CKFINDER_CONNECTOR_LIB_DIR . "/CommandHandler/XmlCommandHandlerBase.php";
 
  
// Since we will send a XML response, we'll extend the XmlCommandHandlerBase
+
==== Step3: Register the "FileSize" command ====
class CKFinder_Connector_CommandHandler_FileSize extends CKFinder_Connector_CommandHandler_XmlCommandHandlerBase
+
The <code>BeforeExecuteCommand</code> hook is used to define your own server side command
 +
<source lang="asp">
 +
if ( command == "FileSize" )
 +
// ...
 
</source>
 
</source>
  
==== Step3: Create an event handler ====
+
==== Step4: Create a class to send the XML response ====
Our event handler defined in (1) is called "onBeforeExecuteCommand", so let's define such function.
+
If your plugin returns an XML response, you'll usually just extend the XmlCommandHandlerBase class to reduce the amount of code to write, however it is not a requirement.
<source lang="php">
+
 
function onBeforeExecuteCommand( &$command )
+
<source lang="asp">
// ...
+
public class FileSizeCommandHandler : XmlCommandHandlerBase
 
</source>
 
</source>
  
==== Step4: Create the buildXml method ====
+
==== Step5: Create the buildXml method ====
In the <code>onBeforeExecuteCommand</code> method we have called <code>sendResponse</code>. The <code>sendResponse method is defined</code> in XmlCommandHandlerBase class, it creates a basic XML response and calls the <code>buildXml</code> method, which we need to define.
+
In the <code>MyBeforeExecuteCommandEventHandler</code> method we have called <code>sendResponse</code>. The <code>sendResponse method is defined</code> in XmlCommandHandlerBase class, it creates a basic XML response and calls the <code>buildXml</code> method, which we need to define.
<source lang="php">
+
<source lang="asp">
function buildXml()
+
protected override void BuildXml()
 
// ...
 
// ...
 
</source>
 
</source>
  
==== Step5: Construct the XML response ====
+
==== Step6: Construct the XML response ====
 
The main task of the buildXml method is to construct an XML response, so we're doing it below:  
 
The main task of the buildXml method is to construct an XML response, so we're doing it below:  
<source lang="php">
+
<source lang="asp">
$oNode = new Ckfinder_Connector_Utils_XmlNode("FileSize");
+
XmlNode oFileSize = XmlUtil.AppendElement( this.ConnectorNode, "FileSize" );
$oNode->addAttribute("size", $size);
+
XmlUtil.SetAttribute( oFileSize, "size", fileSize.ToString() );
$this->_connectorNode->addChild($oNode);
 
 
</source>
 
</source>
 +
 +
==== Step7: Build solution ====
 +
Build solution and copy generated .dll file to the "bin" folder as explained in [[CKFinder_2.x/Developers_Guide/ASP.NET/Plugins|Enabling ASP.NET Plugins]] and adjust the configuration file.
  
 
==== Full source code ====
 
==== Full source code ====
===== plugin.php =====
+
===== FileSize.cs =====
The full source code of a plugin with all necessary security checks: (save the code as '''plugin.php''' in "plugins/myplugin" folder)
+
The full source code of a plugin with all necessary security checks: (save the code as '''FileSize.cs''' in your C# project)
  
<source lang="php">
+
<source lang="asp">
<?php
+
using System;
 +
using System.Collections.Generic;
 +
using System.Linq;
 +
using System.Text;
 +
using System.Xml;
 +
using System.Web;
 +
using System.Web.UI;
 +
using CKFinder;
  
// A simple protection against calling this file directly.
+
namespace CKFinder.Connector.CommandHandlers
if (!defined('IN_CKFINDER')) exit;
+
{
 +
// Since we will send a XML response, we'll extend the XmlCommandHandlerBase class
 +
public class FileSizeCommandHandler : XmlCommandHandlerBase
 +
{
 +
public FileSizeCommandHandler() : base(){}
  
// Include base XML command handler
+
// (5) The buildXml method is used to construct an XML response
require_once CKFINDER_CONNECTOR_LIB_DIR . "/CommandHandler/XmlCommandHandlerBase.php";
+
protected override void BuildXml()
 +
{
 +
if ( !this.CurrentFolder.CheckAcl( AccessControlRules.FileView ) )
 +
{
 +
ConnectorException.Throw( Errors.Unauthorized );
 +
}
  
// Since we will send a XML response, we'll reuse the XmlCommandHandler
+
string fileName = Request["FileName"];
class CKFinder_Connector_CommandHandler_FileSize extends CKFinder_Connector_CommandHandler_XmlCommandHandlerBase
+
 
{
+
if ( !Connector.CheckFileName( fileName ) || Config.Current.CheckIsHiddenFile( fileName ) )
    // The buildXml method is used to construct an XML response
+
{
    function buildXml()
+
ConnectorException.Throw( Errors.InvalidRequest );
    {
+
return;
        // A "must have", checking whether the connector is enabled and the basic parameters (like current folder) are safe.
+
}
        $this->checkConnector();
 
        $this->checkRequest();
 
  
        // Checking ACL permissions, we're just getting an information about a file, so FILE_VIEW permission seems to be ok.
+
if ( !this.CurrentFolder.ResourceTypeInfo.CheckExtension( System.IO.Path.GetExtension( fileName ) ) )
        if (!$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_VIEW)) {
+
{
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED);
+
ConnectorException.Throw( Errors.InvalidRequest );
        }
+
return;
 +
}
  
        // Make sure we actually received a file name
+
string filePath = System.IO.Path.Combine( this.CurrentFolder.ServerPath, fileName );
        if (!isset($_GET["fileName"])) {
 
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_NAME);
 
        }
 
  
        $fileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($_GET["fileName"]);
+
if ( !System.IO.File.Exists( filePath ) )
        $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig();
+
ConnectorException.Throw( Errors.FileNotFound );
  
        // Use the resource type configuration object to check whether the extension of a file to check is really allowed.
+
try
        if (!$resourceTypeInfo->checkExtension($fileName)) {
+
{
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION);
+
long fileSize = new System.IO.FileInfo( filePath ).Length;
        }
 
  
        // Make sure that the file name is really ok and has not been sent by a hacker
+
// (6) Adding a <FileSize> element to the XML response.
        if (!CKFinder_Connector_Utils_FileSystem::checkFileName($fileName) || $resourceTypeInfo->checkIsHiddenFile($fileName)) {
+
XmlNode oFileSize = XmlUtil.AppendElement( this.ConnectorNode, "FileSize" );
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
+
XmlUtil.SetAttribute( oFileSize, "size", fileSize.ToString() );
        }
+
}
 +
catch ( OutOfMemoryException )
 +
{
 +
ConnectorException.Throw( Errors.InvalidName );
 +
}
 +
catch ( System.UnauthorizedAccessException )
 +
{
 +
ConnectorException.Throw( Errors.AccessDenied );
 +
}
 +
catch ( System.Security.SecurityException )
 +
{
 +
ConnectorException.Throw( Errors.AccessDenied );
 +
}
 +
catch ( System.ArgumentException )
 +
{
 +
ConnectorException.Throw( Errors.FileNotFound );
 +
}
 +
catch ( System.IO.PathTooLongException )
 +
{
 +
ConnectorException.Throw( Errors.FileNotFound );
 +
}
 +
catch ( Exception )
 +
{
 +
ConnectorException.Throw( Errors.Unknown );
 +
}
 +
}
 +
}
 +
}
  
        $filePath = CKFinder_Connector_Utils_FileSystem::combinePaths($this->_currentFolder->getServerPath(), $fileName);
+
namespace CKFinder.Plugins
 +
{
 +
public class FileSize : CKFinder.CKFinderPlugin
 +
{
 +
// (Optional) Register a javascript plugin named "myplugin"
 +
public string JavascriptPlugins
 +
{
 +
get { return "myplugin"; }
 +
}
  
        if (!file_exists($filePath) || !is_file($filePath)) {
+
public void Init( CKFinder.Connector.CKFinderEvent CKFinderEvent )
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND);
+
{
        }
+
// (1) Register our custom BeforeExecuteCommand event
 +
                        //    listener (MyBeforeExecuteCommandEventHandler function).
 +
CKFinderEvent.BeforeExecuteCommand +=
 +
                            new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );
 +
}
  
        $size = filesize($filePath);
+
// (2) Our event listener
 +
protected void MyBeforeExecuteCommandEventHandler( object sender, CKFinder.Connector.CKFinderEventArgs args )
 +
{
 +
String command = (String)args.data[0];
  
        // *** The main part of this plugin ****
+
// (3) Register the "FileSize" command
        // Adding a <FileSize> element to the XML response.
+
if ( command == "FileSize" )
        $oNode = new Ckfinder_Connector_Utils_XmlNode("FileSize");
+
{
        $oNode->addAttribute("size", $size);
+
HttpResponse Response = (HttpResponse)args.data[1];
        $this->_connectorNode->addChild($oNode);
 
    }
 
  
    // Register the "FileSize" command
+
// (4) Our custom class (FileSizeCommandHandler) will do the rest
    function onBeforeExecuteCommand( &$command )
+
CKFinder.Connector.CommandHandlers.CommandHandlerBase commandHandler =
    {
+
new CKFinder.Connector.CommandHandlers.FileSizeCommandHandler();
        if ( $command == 'FileSize' )
 
        {
 
            // The sendResponse method is defined in XmlCommandHandlerBase, it creates
 
            // a basic XML response and calls the buildXml()method
 
            $this->sendResponse();
 
            // false = stop further execution.
 
            return false;
 
        }
 
  
        return true ;
+
// The sendResponse method is defined in XmlCommandHandlerBase, it creates
    }
+
// a basic XML response and calls the buildXml()method
 +
commandHandler.SendResponse( Response );
 +
}
 +
}
 +
}
 
}
 
}
 
$CommandHandler_FileSize = new CKFinder_Connector_CommandHandler_FileSize();
 
// Register the onBeforeExecuteCommand method to be called by the BeforeExecuteCommand hook.
 
$config['Hooks']['BeforeExecuteCommand'][] = array($CommandHandler_FileSize, "onBeforeExecuteCommand");
 
// (Optional) Register a javascript plugin named "myplugin"
 
$config['Plugins'][] = 'myplugin';
 
 
</source>
 
</source>
  
 
{{CKFinder_2.x myplugin code}}
 
{{CKFinder_2.x myplugin code}}
 
{{#CUSTOMTITLE:Writing ASP.NET Plugins}}
 
{{#CUSTOMTITLE:Writing ASP.NET Plugins}}

Latest revision as of 08:09, 26 May 2010

CKFinder functionality can be extended with server-side plugins. Although the full source code of the CKFinder server connector is available and can be modified in any way desired, a much better way of enhancing the CKFinder connector is to create a plugin.

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 and imageresize plugin).
  • Working with uploaded files (i.e. watermark plugin).
  • Extending information returned by the Init command (i.e. imageresize plugin).

Creating a plugin

Step1: Create plugin folder

Create a directory for your plugin inside of the "plugins" directory (by default CKFinder comes with three plugins: dummy, fileeditor, imagreresize). Let's use "myplugin" as the plugin name and use the same name for our new folder.

Step2: Create JavaScript plugin

Inside of your plugin's folder ("myplugin") create an empty file named plugin.js.
(If your plugin is a pure server side plugin, you may skip that step)

Step3: Create .dll file with your plugin

// Let's skip that step for now

Step4: Enable plugin

  • Copy .dll file with a plugin to the "bin" folder of your application
  • In config.ascx add your plugin to the Plugins list:
Plugins = new string[] {
	// class name, assembly name
	"CKFinder.Plugins.FileSize, CKFinder_FileSize"
};

ASP.NET plugin system

Hooks

CKFinder provides several hooks that can be used to extend the functionality of the CKFinder application. Assigning a function (also known as an event handler) to a hook will cause that function to be called at the appropriate point in the main CKFinder code, to perform whatever additional task(s) the developer thinks would be useful at that point. Each hook can have multiple handlers assigned to it, in which case it will call the functions in the order that they are assigned.

Registering an event handler to a hook is very simple:

// MyBeforeExecuteCommandEventHandler is our custom event handler (method)
CKFinderEvent.BeforeExecuteCommand += 
       new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );

Available hooks (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.

Enabling JavaScript plugin

Sometimes a server side plugin might come with a client side (JavaScript) plugin, that should be automatically enabled when the server side plugin is enabled.
The JavascriptPlugins property is a special variable that does that.

To enable a plugin, simply define it's name (to add multiple plugins, separate their names with a comma).

public string JavascriptPlugins
{
	get { return "myplugin"; }
}

This code is virtually equal to specyfying in config.js:

config.extraPlugins = 'myplugin';

but the advantage of defining it in a plugin is that it will be enabled only when the server side plugin is also enabled.

Sample plugin: FileSize (adding new server side command - complete example)

Introduction

Probably the best way to learn new things is to write a code, so let's write a plugin that adds a new server side command to the connector. We'll create a command that returns a size of a given file.

If you're unfamiliar with CKFinder architecture, please take a look at Server Side Integration documentation. Alternatively, just bear in mind that CKFinder is an AJAX application and that the connection between the user interface running in a browser and the server connector is simply made of AJAX calls to the connector. Check AJAX calls in Firebug to better understand CKFinder.

The FileSize plugin should provide a new command named "FileSize", in other words, calling:

/ckfinder/core/connector/aspx/connector.aspx?command=FileSize&type=Files&currentFolder=%2F&fileName=foobar.jpg

(assuming that foobar.jpg exists) should return a valid XML response:

<Connector resourceType="Files">
<Error number="0"/>
<CurrentFolder path="/" url="/ckfinder/userfiles/files/" acl="255"/>
<FileSize size="5647"/>
</Connector>

The project

Let's create a C# project now to generate a .dll file.

  • Create a new C# project (Class Library).
  • Add reference to CKFinder.dll (right-click "References" in the "Solution Explorer", use "Browse" to select CKFinder.dll from the directory you have saved it).
  • In Project Properties change Assembly name to CKFinder_FileSize and Default namespace to CKFinder.Plugins
  • Rename the default file created by VS (Class1.cs) into FileSize.cs.

The whole code will be in a single file (FileSize.cs). For the sake of simplicity, let's take a look at Filesize.cs that just does exactly what we need:

namespace CKFinder.Connector.CommandHandlers
{
  // Since we want to send a XML response, we'll extend the XmlCommandHandlerBase class
  public class FileSizeCommandHandler : XmlCommandHandlerBase
  {
    public FileSizeCommandHandler() : base() {}

    // (5) The buildXml method is used to construct an XML response
    protected override void BuildXml()
    {
      string fileName = Request["FileName"];
      string filePath = System.IO.Path.Combine( this.CurrentFolder.ServerPath, fileName );

      long fileSize = new System.IO.FileInfo( filePath ).Length;

      // (6) Adding a <FileSize> element to the XML response.
      XmlNode oFileSize = XmlUtil.AppendElement( this.ConnectorNode, "FileSize" );
      XmlUtil.SetAttribute( oFileSize, "size", fileSize.ToString() );
    }
  }
}

namespace CKFinder.Plugins
{
  public class FileSize : CKFinder.CKFinderPlugin
  {
    public string JavascriptPlugins
    {
      get { return "myplugin"; }
    }

    public void Init( CKFinder.Connector.CKFinderEvent CKFinderEvent )
    {
      // (1) Register our custom BeforeExecuteCommand event listener (MyBeforeExecuteCommandEventHandler function).
      CKFinderEvent.BeforeExecuteCommand += 
            new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );
    }

    // (2) Our event handler
    protected void MyBeforeExecuteCommandEventHandler( object sender, CKFinder.Connector.CKFinderEventArgs args )
    {
      String command = (String)args.data[0];

      // (3) Register the "FileSize" command
      if ( command == "FileSize" )
      {
        HttpResponse Response = (HttpResponse)args.data[1];

        // (4) Our custom class (FileSizeCommandHandler) will do the rest
        CKFinder.Connector.CommandHandlers.CommandHandlerBase commandHandler =
          new CKFinder.Connector.CommandHandlers.FileSizeCommandHandler();

        // The sendResponse method is defined in XmlCommandHandlerBase, it creates 
        // a basic XML response and calls the buildXml()method 
        commandHandler.SendResponse( Response );
      }
    }
  }
}

Step1: Register an event handler

CKFinderEvent.BeforeExecuteCommand += 
       new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );

Step2: Create an event handler

protected void MyBeforeExecuteCommandEventHandler( object sender, CKFinder.Connector.CKFinderEventArgs args )

Step3: Register the "FileSize" command

The BeforeExecuteCommand hook is used to define your own server side command

if ( command == "FileSize" )
// ...

Step4: Create a class to send the XML response

If your plugin returns an XML response, you'll usually just extend the XmlCommandHandlerBase class to reduce the amount of code to write, however it is not a requirement.

public class FileSizeCommandHandler : XmlCommandHandlerBase

Step5: Create the buildXml method

In the MyBeforeExecuteCommandEventHandler method we have called sendResponse. The sendResponse method is defined in XmlCommandHandlerBase class, it creates a basic XML response and calls the buildXml method, which we need to define.

protected override void BuildXml()
// ...

Step6: Construct the XML response

The main task of the buildXml method is to construct an XML response, so we're doing it below:

XmlNode oFileSize = XmlUtil.AppendElement( this.ConnectorNode, "FileSize" );
XmlUtil.SetAttribute( oFileSize, "size", fileSize.ToString() );

Step7: Build solution

Build solution and copy generated .dll file to the "bin" folder as explained in Enabling ASP.NET Plugins and adjust the configuration file.

Full source code

FileSize.cs

The full source code of a plugin with all necessary security checks: (save the code as FileSize.cs in your C# project)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Web;
using System.Web.UI;
using CKFinder;

namespace CKFinder.Connector.CommandHandlers
{
	// Since we will send a XML response, we'll extend the XmlCommandHandlerBase class
	public class FileSizeCommandHandler : XmlCommandHandlerBase
	{
		public FileSizeCommandHandler() : base(){}

		// (5) The buildXml method is used to construct an XML response
		protected override void BuildXml()
		{
			if ( !this.CurrentFolder.CheckAcl( AccessControlRules.FileView ) )
			{
				ConnectorException.Throw( Errors.Unauthorized );
			}

			string fileName = Request["FileName"];

			if ( !Connector.CheckFileName( fileName ) || Config.Current.CheckIsHiddenFile( fileName ) )
			{
				ConnectorException.Throw( Errors.InvalidRequest );
				return;
			}

			if ( !this.CurrentFolder.ResourceTypeInfo.CheckExtension( System.IO.Path.GetExtension( fileName ) ) )
			{
				ConnectorException.Throw( Errors.InvalidRequest );
				return;
			}

			string filePath = System.IO.Path.Combine( this.CurrentFolder.ServerPath, fileName );

			if ( !System.IO.File.Exists( filePath ) )
				ConnectorException.Throw( Errors.FileNotFound );

			try
			{
				long fileSize = new System.IO.FileInfo( filePath ).Length;

				// (6) Adding a <FileSize> element to the XML response.
				XmlNode oFileSize = XmlUtil.AppendElement( this.ConnectorNode, "FileSize" );
				XmlUtil.SetAttribute( oFileSize, "size", fileSize.ToString() );
			}
			catch ( OutOfMemoryException )
			{
				ConnectorException.Throw( Errors.InvalidName );
			}
			catch ( System.UnauthorizedAccessException )
			{
				ConnectorException.Throw( Errors.AccessDenied );
			}
			catch ( System.Security.SecurityException )
			{
				ConnectorException.Throw( Errors.AccessDenied );
			}
			catch ( System.ArgumentException )
			{
				ConnectorException.Throw( Errors.FileNotFound );
			}
			catch ( System.IO.PathTooLongException )
			{
				ConnectorException.Throw( Errors.FileNotFound );
			}
			catch ( Exception )
			{
				ConnectorException.Throw( Errors.Unknown );
			}
		}
	}
}

namespace CKFinder.Plugins
{
	public class FileSize : CKFinder.CKFinderPlugin
	{
		// (Optional) Register a javascript plugin named "myplugin"
		public string JavascriptPlugins
		{
			get { return "myplugin"; }
		}

		public void Init( CKFinder.Connector.CKFinderEvent CKFinderEvent )
		{
			// (1) Register our custom BeforeExecuteCommand event 
                        //     listener (MyBeforeExecuteCommandEventHandler function).
			CKFinderEvent.BeforeExecuteCommand += 
                             new CKFinder.Connector.CKFinderEvent.Hook( this.MyBeforeExecuteCommandEventHandler );
		}

		// (2) Our event listener
		protected void MyBeforeExecuteCommandEventHandler( object sender, CKFinder.Connector.CKFinderEventArgs args )
		{
			String command = (String)args.data[0];

			// (3) Register the "FileSize" command
			if ( command == "FileSize" )
			{
				HttpResponse Response = (HttpResponse)args.data[1];

				// (4) Our custom class (FileSizeCommandHandler) will do the rest
				CKFinder.Connector.CommandHandlers.CommandHandlerBase commandHandler =
					new CKFinder.Connector.CommandHandlers.FileSizeCommandHandler();

				// The sendResponse method is defined in XmlCommandHandlerBase, it creates 
				// a basic XML response and calls the buildXml()method 
				commandHandler.SendResponse( Response );
			}
		}
	}
}
plugin.js

.. and the client side (JavaScript) plugin that will call the FileSize command: (save the code as plugin.js in "plugins/myplugin" folder)

CKFinder.addPlugin( 'myplugin', function( api ) {
	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");
		} );
	});
});

This page was last edited on 26 May 2010, at 08:09.