As your Mango Plugins get more complex, you will find yourself needing to include a JavaScript file on pages, or access images, css, or
other resources. With some work, you can programatically find the path to your plugin's folder inside the components/plugins/… folder,
but that's a bad idea.
Well, it breaks convention… so it's sort-of bad.
One of the folders in the root of every Mango install is the assets folder. Inside are two more folders: plugins and
content. The content folder is the default place that files are stored when you use the File Explorer in your Mango admin
to upload files. The plugins folder is intended to house files that a reader will need remote access to.
Convention dictates that when your plugin is activated, it should place any files that will be accessed remotely (ajax, css, images, js,
etc) into [mango]/assets/plugins/[plugin name]/. For instance, my Lightbox2 plugin
copies a dozen or so css, js, and image files to its asset folder; and then the plugin itself injects HTML onto pages that access the files
in this location.
Convention also dictates that when the files are no longer needed — when your plugin is de-activated — you should remove them. Clutter
is bad, mmkay?
I wouldn't say the code to accomplish this is necessarily overly complex, but it's certainly going to be frequently repeated, which
means it's a good case for some encapsulation.
Here are two methods I've written that will copy the contents of [mango]/components/plugins/user/[plugin name]/assets/ to
[mango]/assets/plugins/[plugin name]/, and delete them.
<cffunction name="copyAssets" access="private" output="false" returntype="void"
hint="I'm used during plugin activation to copy files to a public location">
<cfset var local = structNew()/>
<cfset local.src = getCurrentTemplatePath() />
<cfset local.src = listAppend(listDeleteAt(local.src, listLen(local.src, "\/"), "\/"), "assets", "/")/>
<cfset local.dest = expandPath('#variables.blogManager.getBlog().getBasePath()#/assets/plugins/#variables.name#')/>
<cfif not directoryExists(local.dest)>
<cfdirectory action="create" directory="#local.dest#"/>
</cfif>
<!--- copy our assets to the root/assets/plugins/RelatedEntries folder so that they are web-accessible --->
<cfdirectory action="list" directory="#local.src#" name="local.assets"/>
<cfloop query="local.assets">
<cffile action="copy" source="#local.assets.directory#/#local.assets.name#"
destination="#local.dest#/#local.assets.name#"/>
</cfloop>
</cffunction>
<cffunction name="clearAssets" access="private" output="false" returntype="void"
hint="I'm used during plugin de-activation to remove public files">
<cfset var local = StructNew()/>
<cfset local.dir = expandPath('../assets/plugins/#variables.name#')/>
<cfdirectory action="delete" directory="#local.dir#" recurse="yes"/>
</cffunction>
To use them, simply add <cfset copyAssets() /> to your setup function, and <cfset clearAssets() /> to your
unsetup function. The copyAssets funtion is not recursive, which means you can't use sub-folders. It would be simple enough to
convert to recursive, so I won't include that here.
This methodology also facilitates really keeping your plugin architecture simple. Again, using my Lightbox2 plugin as an example, here
are the contents of the plugin folder:

And the contents of the assets folder:

Pretty straight-forward, right?
So now that you're copying your resource files to the appropriate folder for remote access, how do you get that URL?
I'm glad you asked…
Similar to finding out what DBMS the current Mango install is using,
you can use Mango's API to find its base path and then build on it. Remember: not all users will install Mango to the root of their site.
It could be in /blog, /some/other/folder, or anything else. This practice will make sure your plugin works no matter where Mango is
installed.
The method that will return the blog base path is getBasePath() and it belongs to the blog object, so you get its value like so:
variables.blogManager.getBlog().getBasePath()
Remember that variables.blogManager is a variable passed into and
saved from the plugin's init function.
If Mango is installed at the root of the site, this method will return "/". If installed at /blog, it will return "/blog/" — it always
has the trailing slash.
From there, add "assets/plugins/[plugin name]/" and your files are ready and waiting.
What, you want an example of that too? Ok, here's some code from my Lightbox2 plugin that adds the css and JavaScript files to a
page:
<cfset data = arguments.event.outputData />
<cfset data = data & '#chr(13)##chr(10)#<link rel="stylesheet"
href="#variables.blogManager.getBlog().getBasePath()#assets/plugins/#variables.name#/lightbox.css" type="text/css" media="screen" />'/>
<cfset data = data & '#chr(13)##chr(10)#<xscript
src="#variables.blogManager.getBlog().getBasePath()#assets/plugins/#variables.name#/prototype.js" type="text/javascript"></xscript>'/>
...
<cfset arguments.event.outputData = data />
Note that I had to replace "script" tags with "xscript" tags for them to be displayed here, just drop the X.