Creative Juices Bo. Co.

Satisfy Your Thirst For Something Refreshing!

Guide To Creating Your Own CJ File Browser Handler Engine Plug-in

Create Your Own Handler Engine for CJ File Browser 3.1

One of the main features of CJ File Browser is the capability to use various server technologies besides ColdFusion, to handle all the server calls. In order to do this, you may need to create your own plug-in for the new Handler Engine System. This guide will provide you with the layout, required functions and function responses that are needed in order to do this.

Unfortunately, in order for you to create your own Handler Engine plug-in, you are going to need at least some basic knowledge of programming language. There's just to much going on on the functions to effectively explain it all here. You are going to need to be able to open up one of the existing handler engine plug-ins to get a grasp of what it's doing. If any of this is not making sense, then don't hesitate to ask a question. I'm more than happy to provide any insight into making these!

The Handler Engine

The handler engine is just a collection of functions that handle various aspects of CJ File Browser. It handles things like, reading a directory, uploading a file and grabbing image file thumbnails from the server. For ColdFusion, these functions are located in a ColdFusion Component File (CFC). CJ File Browser uses jQuery to make calls to this file using AJAX. The handler returns it's results as a JSON object, which is used to handle the various user actions.

Security

Another great feature of CJ File Browser is its built in security architecture. In order to ensure that you have a safe deployment, it uses a file called security.xml to verify that the calls from the JavaScript engine are authorized. It will authenticate file actions as well as valid directories. The file structure is fairly straightforward. If you plan on creating your own handler engine then I highly recommend you take the steps necessary to implement this feature. One thing to keep in mind, is that the security settings override any settings that are sent via tinyMCE or in the standalone settings. So even though you may see a file upload button on the browser window, it may throw an error if that action is not allowed in the security file.

Security File Structure
<?xml version="1.0" encoding="UTF-8"?>
<cjFileBrowser version="3.1">
   <actionsAllowed>
      <action>navigateDirectory</action>
      <action>createDirectory</action>
      <action>deleteDirectory</action>
      <action>fileDelete</action>
      <action>fileUpload</action>
      <action>fileSelect</action>
      <action>filePreviews</action>
   </actionsAllowed>
   <directoriesAllowed>
      <directory>/</directory>
   </directoriesAllowed>
   <fileExtsAllowed>
      <fileExt>*</fileExt>
   </fileExtsAllowed>
</cjFileBrowser>

The XML entries are read into the handler before it performs various actions. If the action is not within this file, then we consider it to be unauthorized. CJ File Browser will gracefully inform the user that it is not permitted. Consider the JavaScript file to be an untrusted source. Crafty hackers can read the script and determine what methods are being called within our handler. Because of this, we need to have something that we can trust that verifies each action. Here's a breakdown of the actions.

Actions

  • navigateDirectory - Any action that reads a directory. By default if this action is present, CJ File Browser will allow users to traverse any of the listed directories and any directories within it. By removing this action, then , will not allow this. (Currently there is no option to allow a user to jump from one directory listing to another, they can only traverse the directory that they initiated in.)
  • createDirectory - Allows users to create directories.
  • deleteDirectory - Allows users to delete directories. (This action is recursive, so it will delete directory contents as well)
  • fileDelete - Allows users to delete files.
  • fileUpload - Allows users to upload files.
  • fileSelect - Allows users to select a file. (Only useful in standalone mode)
  • filePreviews - Allows users to use view image thumbnail previews. (Should help with server load, if thats a problem)

Directories

The directories allowed nodes are relative paths (from web root) to any directories that you wish the user to use. In normal environments, you will most likely only have one entry. But in special cases, say a server with multiple tinyMCE or standalone deployments, you may have additional entries. The handler engine needs to confirm that any of these instances adhere to the security rules by validating the path that passed to the function is within one of these directories. The user may opt to supply:

<directory>/</directory>

... which means that CJ File Browser is authorized to view any directory on the server (Even if other directories are listed)

File Extension

The security file also provides a means to authorize valid file extensions to allow users to upload or view. This entry is a simple comma separated list. By default, the settings allow all file typesby using an "*". If you want to create limits, then simply add them like so:

<fileExt>gif,jpg,png</fileExt>

It's fairly straightforward, the only thing to know is that this entry cannot be blank or it will through an error.

The Functions

The following list of functions must be created in your handler file and their results must conform to the examples given. One thing to keep in mind, is that as of this writing, ColdFusion 8 returns JSON objects with upper-case variable names. Since javascript is a case-sensitive language, it's important that you return your results the same way or CJ File Browser may fail.


isHandlerReady

Description

CJ File Browser calls this function during its initial setup. Its main function is to inform the file browser that it's there as well as does some basic format checks on the security.xml file as well as check. It checks the security version number, and the reads in each security setting to ensure that its formatted properly.

Access

Remote

Arguments
NameTypeDescriptionExample
versionSTRINGThe version of cjFileBrowser. Used to ensure that the security.xml version matches the version of cjFileBrowser.3.1
timeOutNUMBERThe amount of time in seconds that the function should timeout in. (Defaults 900)900
Returns

Struct (JSON)

Return Structure
Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGARRAYError messages to display to the browser. (Array allows for multiple error messages)
Sample Result (Good)
{
   "ERROR": false,
   "ERROR_MSG": []
}
Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": 
      [
         "Security.xml version does not match the CJ File Browser version.",
         "Problems checking security.xml authorized directories."
      ]
}
Notes

This function gets called once when CJ File Browser is initializing.


isPathValid

Description

Validates that the given relative path (from web root) is authorized based on the security <directoriesAllowed> settings in the security.xml file.

Arguments
NameTypeDescriptionExample
baseUrlSTRINGA relative path that will be checked against the security.xml file root paths./myroot/myfolder/
exactSTRINGChecks to make sure the passed directory EXACTLY matches any of the directories listed in the security.xml file (prevents moving up and down directories). TRUE=Must match a security directory exactly, FALSE=Can be a directory inside the security directoryTRUE
settingsSTRINGThe authorized directory list (security settings) from a previous call within the same function. This helps server load by preventing multiple reads on the security.xml while geting directory contents./myroot/myfolder/, /myroot/myfolder2/

* The settings example has a space after the comma, this is done to wrap the line. List should not contain spaces!

Access

Private

Returns

Boolean

Notes

This is a private function used internally by other functions.


isActionValid

Description

Validates that the given action is authorized based on the security <actionsAllowed> settings in the security.xml file.

Arguments
NameTypeDescriptionExample
actionSTRINGThe action that will be checked against the security.xml allowed actions.

Current valid actions:
navigateDirectory
createDirectory
deleteDirectory
fileDelete
fileUpload
filePreviews
navigateDirectory
settingsSTRINGThe authorized action list (security settings) from a previous call within the same function. This helps server load by preventing multiple reads on the security.xml while geting directory contents.navigateDirectory,fileUpload
Access

Private

Returns

Boolean

Notes

This is a private function used internally by other functions.


getSecuritySettings

Description

Reads the cjFileBrowser security.xml file and returns the results as a comma separated list. Gets called by various functions to ensure that their operations don't fall outside of these directories.

Arguments
NameTypeDescriptionExample
settingTypeSTRINGTells the function which security setting to return. Must be one of actions, directories, fileExtsactions
Access

Remote

Returns

Struct (JSON) - The list data variable varies depending upon which setting type was requested.

Sample Result (Good actions)
{
   "ERROR": false,
   "ERROR_MSG": "",
   "ACTIONLIST": "navigateDirectory,createDirectory,deleteDirectory,fileDelete,fileUpload,fileSelect,filePreviews"
}
Sample Result (Good directories)
{
   "ERROR": false,
   "ERROR_MSG": "",
   "DIRLIST": "/myroot/myfolder1/,/myroot/myotherfolder/,/myotherroot/myfolder/"
}
Sample Result (Good fileExts)
{
   "ERROR": false,
   "ERROR_MSG": "",
   "EXTLIST": "gif,jpg,png"
}
Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "There are no authorized directories set in the security.xml file. (Cannot be blank)"
}


getDirectoryList

Description

Reads and returns the contents of a given directory.

Arguments
NameTypeDescriptionExample
baseUrlSTRINGThe relative path to the directory in which to create a new directory in./myroot/myfolder/
fileExtsSTRINGThe name of the directory to create./myroot/myfolder/
mimeTypesSTRINGThe name of the directory to create./myroot/myfolder/
showInvBOOLEANDetermines wether to return invisible files. TRUE=Shows all files, FALSE=Hides invisible files (Defaults: False)TRUE
timeOutNUMBERThe amount of time in seconds that the function should timeout in. (Defaults 900)900
Access

Remote

Returns

Struct (JSON)

Return Structure
Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGSTRINGError message to display to the browser.
DIRLISTING (Not returned on error)ARRAYAn array of structs containing the directory contents. If directory contents are empty, then return []. Required if ERROR is FALSE
(See below for format)

* Variable names must be upper-case.

DIRLISTING Structure

The DIRLISTING is an array of structs. The follow table describes the struct format expected

Variable*TypeDescriptionExample
EXTENSIONSTRINGThe file extension (If the entry is a file. It's blank for directories). This value is used as a class name to determine the icon for files. Any values must be returned in UPPER-CASE.GIF
NAMESTRINGThe file extension (If the entry is a file. It's blank for directories).MyImage.gif
WIDTHINTEGERIf this entry is an IMAGE file, then this is the WIDTH of the image in pixels. This value is blank for directories and non-image files.200
ATTRIBUTESSTRINGFor future use. (Not currently used, but expected.)
DATELASTMODIFIEDSTRINGThe date that an entry was last modified. Must be returned as a formated DATETIME string so JavaScript can interpet it.November, 25 2009 11:26:19
DIRECTORYSTRINGThe director path that was passed when initiating the function./MySite/images/
TYPESTRINGDetermines if this entry is a file or directory. Valid responses are FILE or DIRFILE
FULLPATHSTRINGThe absolute path to this file or directory entry./server/webroot/ images/MyImage.gif
HEIGHTINTEGERIf this entry is an IMAGE file, then this is the HEIGHT of the image in pixels. This value is blank for directories and non-image files.110
SIZEINTEGERThe size in BYTES for this entry. Use 0 for directories.10866

* Variable names must be upper-case.

Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "There was a problem creating the directory."
}
Sample Result (Good)
{
   "ERROR":false,
   "ERROR_MSG":"",
   "DIRLISTING":
      [
         {
            "EXTENSION":"GIF",
            "MIME":"image/gif",
            "NAME":"MyImage.gif",
            "WIDTH":130,
            "ATTRIBUTES":"",
            "DATELASTMODIFIED":"November, 25 2009 11:26:19",
            "DIRECTORY":"/MySite/images/",
            "TYPE":"FILE",
            "FULLPATH":"/MyServer/WebRoot/MySite/images/MyImage.gif",
            "HEIGHT":110,
            "SIZE":10866
         },
         {
            "EXTENSION":"",
            "MIME":"",
            "NAME":"My Pictures",
            "WIDTH":"",
            "ATTRIBUTES":"",
            "DATELASTMODIFIED":"April, 13 2010 11:39:23",
            "DIRECTORY":"/MySite/images/",
            "TYPE":"DIR",
            "FULLPATH":"/MyServer/WebRoot/MySite/images/My Pictures",
            "HEIGHT":"",
            "SIZE":0
         }
      ]
}
Notes

Even though it's returning a STRUCT, the javascript engine is requesting and expects a JSON object. ColdFusion functions can be passed the "returnFormat=JSON" argument, which forces the return value to be a JSON object. Keep this in mind when developing your own engines.


getImageThumb

Description

Returns an string that is an <IMG> tag with styling information set. This tag can be used to display an scaled image preview in the browser window. It uses calcScaleInfo to calculate image scale parameters.

The CJ File Browser window contains block items of the directory contents. Within this block is a transparent document icon. Behind this icon, there is a <DIV> block with can be used to display the <IMG>. The styling info is used to center this thumbnail inside this block. (See Fig. 1)

Fig. 1 - CJ File Browser image preview technique.
Fig. 1 - CJ File Browser image preview technique.
(Green used to indicate the <DIV> box. Not actually used.)

The styling information that needs to be supplied is the WIDTH and HEIGHT of the scaled image as well as the TOP and LEFT OFFSET to center the image inside the drawing area. The dimensions of this area is 65 x 88 (W x H) pixels. It's recommended that you do not hard code these values at this time, since eventually CJ File Browser will be them-able and these values will be passed to the handler.

If you are unfamiliar with how to calculate the scaling information, I have a fairly extensive tutorial called Easily Calculate Image Scaling on my blog. Read up on it and you should be able to figure things out.

Arguments
NameTypeDescriptionExample
baseUrlSTRINGThe relative path to the directory in which to create a new directory in./myroot/myfolder/
elemIDSTRINGThe list elements ID passed from the interface. Used to set the element's icon when returning data.browser_ID4
fileNameSTRINGThe name of the image file.myimage.jpg
timeOutNUMBERThe amount of time in seconds that the function should timeout in. (Defaults 900)900
Access

Remote

Returns

Struct (JSON)

Return Structure
Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGSTRINGError message to display to the browser.
ELEMID (Not returned on error)STRINGThe list elements ID passed from the interface. Used to set the element's icon when returning data.
IMGSTR (Not returned on error)STRINGA string with an <IMG> tag. Include <STYLE> info.

* Variable names must be upper-case.

Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "Problems reading image thumbnail. (/myserver/myabsolutepath/myroot/myfolder/myimage.jpg)"
}
Sample Result (Good)
{
   "ERROR": true,
   "ERROR_MSG": "There was a problem creating the directory.",
   "ELEMID": "browser_ID4",
   "IMGSTR": "<img src="/myroot/myfolder/myimage.jpg" border="0" width="20" height="30" style="margin-top:-10px;margin-left:-1px;" />"
}


doFileUpload

Uploads a file to the server (Handles a form POST operation)

Arguments (Passed as FORM variables)
NameTypeDescriptionExample
baseUrlSTRINGThe relative path to the directory in which to upload the file. This argument is passed as a FORM INPUT[TYPE="TEXT"] variable from an html form POST operation./myroot/myfolder/
fileUploadField*STRINGThe image file to upload. This argument is passed as a FORM INPUT[TYPE="FILE"] variable from an html form POST operation.multipart/form-data
maxWidthINTEGERIf the file being uploaded is an image, then the maximum WIDTH in pixels the image can be. If the image exceeds this value, the handler is responsible for scaling the image to fit this value. This argument is passed as a FORM INPUT[TYPE="TEXT"] variable from an html form POST operation.200
maxHeightINTEGERIf the file being uploaded is an image, then the maximum HEIGHT in pixels the image can be. If the image exceeds this value, the handler is responsible for scaling the image to fit this value. This argument is passed as a FORM INPUT[TYPE="TEXT"] variable from an html form POST operation.100
maxSizeINTEGERThe maximum size, in kilobytes, that will be accepted for upload. This argument is passed as a FORM INPUT[TYPE="TEXT"] variable from an html form POST operation.900
fileExtsfSTRINGThe name of the image file. This argument is passed as a FORM INPUT[TYPE="TEXT"] variable from an html form POST operation.myimage.jpg
mimeTypesSTRINGThe name of the image file. This argument is passed as a FORM INPUT[TYPE="TEXT"] variable from an html form POST operation.myimage.jpg
Access

Remote

Returns

Struct (JSON)

Return Structure
Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGSTRINGThere was a problem uploading the file.

* Variable names must be upper-case.

Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "There was a problem uploading the file."
}
Sample Result (Good)
{
   "ERROR": false,
   "ERROR_MSG": ""
}


doDeleteFile

Description

Deletes a given file from the server.

Arguments
NameTypeDescriptionExample
baseUrlSTRINGThe relative path to the directory in which to delete the file./myroot/myfolder/
fileNameSTRINGThe name of the file to delete.myimage.jpg
timeOutNUMBERThe amount of time in seconds that the function should timeout in. (Defaults 900)900
Access

Remote

Returns

Struct (JSON)

Return Structure
Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGSTRINGError message to display to the browser.
Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "There was a problem deleting the file."
}


doDeleteDirectory

Description

Deletes a given directory and its contents from the server. This is a RECURSIVE function so it will delete everything inside the directory!

Arguments
NameTypeDescriptionExample
baseUrlSTRINGThe relative path to the directory in which to delete a directory in./myroot/images/
fileNameSTRINGThe name of the directory to delete.myfolder
timeOutNUMBERThe amount of time in seconds that the function should timeout in. (Defaults 900)900
Access

Remote

Returns

Struct (JSON)

Return Structure
Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGSTRINGError message to display to the browser.
Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "There was a problem deleting the directory."
}


doCreateNewDirectory

Description

Creates a new directory on the server.

Arguments
NameTypeDescriptionExample
baseUrlSTRINGThe relative path to the directory in which to create a new directory in./myroot/images/
fileNameSTRINGThe name of the directory to create.myfolder
timeOutNUMBERThe amount of time in seconds that the function should timeout in. (Defaults 900)900
Access

Remote

Returns

Struct (JSON)

Return Structure

Error

Variable*TypeDescription
ERRORBOOLEANIndicated if an error occurred TRUE=Ok, FALSE=Error
ERROR_MSGSTRINGError message to display to the browser.
Sample Result (Error)
{
   "ERROR": true,
   "ERROR_MSG": "There was a problem creating the directory."
}

That's a A Wrap

This is a lot of information to absorb and there's bound to be mistakes. Before you go pulling your hair out over something, let me know. This document changed about a gazillion times as I was preparing the files for upload. I made a lot of changes on the fly and it's possible I forgot to update something above. Feel free to ask me anything about this!