Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base: 5eeed7afd1
...
compare: 245b9a2f75
Checking mergeability… Don't worry, you can still create the pull request.
  • 5 commits
  • 5 files changed
  • 0 commit comments
  • 1 contributor
View
14 attachments/model/attachments.cfm
@@ -3,13 +3,13 @@
will allow for file uploads and processing of images
--->
<cffunction name="hasAttachment" access="public" output="false" returntype="void" mixin="model">
- <cfargument name="property" type="string" required="true" />
- <cfargument name="url" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" />
- <cfargument name="path" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" />
+ <cfargument name="property" type="string" required="true" hint="Name of property on the model to store JSON data related to the attached file." />
+ <cfargument name="url" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" hint="Format in which to reference the file as a URL. Use placeholders for `:model`, `:property`, `:id`, `:style`, and `:filename`." />
+ <cfargument name="path" type="string" required="false" default="/files/attachments/:model/:property/:id/:style/:filename" hint="Format in which to store the file in storage. Use placeholders for `:model`, `:property`, `:id`, `:style`, and `:filename`." />
<cfargument name="styles" type="string" required="false" default="" hint="You may pass in multiple styles. The syntax is `nameOfStyle:widthxheight>`. An actual example would be `small:150x150>,medium:300x300>`. The greater than sign at the end means that the attchments plugin should keep the aspect ratio of the photo uploaded. Styles will only be run on images that your ColdFusion server can do processing on." />
<cfargument name="storage" type="string" required="false" default="filesystem" hint="Other options include `s3` and `filesystem,s3`." />
+ <cfargument name="blockExtensions" type="string" required="false" default="cfm,cfml,cfc,dbm,jsp,asp,aspx,exe,php,cgi,shtml" hint="List of file extensions to not allow. This is the default behavior unless overridden by `allowExtensions`. If `allowExtensions` is set, this argument is then ignored." />
<cfargument name="allowExtensions" type="string" required="false" default="" hint="List of file extensions to allow. If this is set, the `blockExtensions` argument is ignored." />
- <cfargument name="blockExtensions" type="string" required="false" default="cfm,cfml,cfc,dbm,jsp,asp,aspx,exe,php,cgi,shtml" hint="List of file extensions to not allow. If `allowExtensions` is set, this argument is ignored." />
<cfscript>
var loc = {};
@@ -50,9 +50,9 @@
variables.wheels.class.callbacks.afterPostProcessing = [];
// set callbacks for this property
- afterDelete(method="$deleteAttachments");
- afterCreate(method="$saveAttachments");
- beforeValidationOnUpdate(method="$saveAttachments");
+ afterDelete("$deleteAttachments");
+ afterCreate("$saveAttachments");
+ beforeValidationOnUpdate("$updateAttachments");
jsonProperty(property=arguments.property, type="struct");
</cfscript>
</cffunction>
View
148 attachments/model/callbacks.cfm
@@ -1,7 +1,7 @@
<cffunction name="$saveAttachments" access="public" output="false" returntype="boolean">
<cfscript>
var loc = { success = true };
-
+
if (!FindNoCase("multipart", cgi.content_type))
return false;
@@ -9,7 +9,7 @@
{
if (!StructKeyExists(variables, "$persistedProperties") || !StructKeyExists(variables.$persistedProperties, ListFirst(primaryKey())))
$updatePersistedProperties();
-
+
// loop over our attachements and upload each one
for (loc.attachment in variables.wheels.class.attachments)
{
@@ -31,6 +31,49 @@
<cfreturn loc.success />
</cffunction>
+<cffunction name="$updateAttachments" access="public" output="false" returntype="boolean">
+ <cfscript>
+ var loc = { success = true };
+
+ if (!FindNoCase("multipart", cgi.content_type))
+ return false;
+
+ if (!StructKeyExists(variables.wheels.instance, "attachmentsSaved"))
+ {
+ if (!StructKeyExists(variables, "$persistedProperties") || !StructKeyExists(variables.$persistedProperties, ListFirst(primaryKey())))
+ $updatePersistedProperties();
+
+ // loop over our attachements and upload each one
+ for (loc.attachment in variables.wheels.class.attachments)
+ {
+ if (StructKeyExists(this, loc.attachment & "$attachment") && Len(form[this[loc.attachment & "$attachment"]]))
+ {
+ loc.attempted = true;
+ loc.saved = $saveAttachment(property=loc.attachment);
+ }
+ else
+ {
+ loc.attempted = false;
+ this[loc.attachment] = this.changedFrom(loc.attachment);
+ loc.saved = false;
+ }
+
+ if (loc.success)
+ loc.success = !loc.attempted || loc.saved;
+ }
+
+ variables.wheels.instance.attachmentsSaved = true;
+
+ if (loc.saved)
+ {
+ this.save();
+ this.reload();
+ }
+ }
+ </cfscript>
+ <cfreturn loc.success />
+</cffunction>
+
<cffunction name="$saveAttachment" access="public" output="false" returntype="boolean">
<cfargument name="property" type="string" required="true" />
<cfscript>
@@ -47,11 +90,13 @@
// check to make sure we don't have a bad file
if ($validateAttachmentFileType(loc.file.ServerFileExt, loc.attachment.blockExtensions, loc.attachment.allowExtensions))
{
- this[loc.attachment.property] = $saveFileToStorage(source=loc.filePath, argumentCollection=loc.attachment);
-
+ this[loc.attachment.property] = $saveFileToStorage(
+ argumentCollection=loc.attachment
+ , source=loc.filePath
+ , fileSize=loc.file.FileSize);
+
if (IsImageFile(loc.filePath) && StructCount(loc.attachment.styles))
{
- // not implemented
for (loc.style in loc.attachment.styles)
this[loc.attachment.property].styles[loc.style] = $saveImageFileWithStyle(source=loc.filePath, argumentCollection=loc.attachment, style=loc.style);
}
@@ -68,13 +113,60 @@
</cffunction>
<cffunction name="$saveImageFileWithStyle" access="public" output="false" returntype="struct">
- <!--- TBD --->
+ <cfargument name="source" type="string" required="true" hint="Source of original image to resize." />
+ <cfargument name="style" type="string" required="true" hint="Name of style to save." />
+ <cfscript>
+ var loc = {};
+ loc.style = arguments.styles[arguments.style];
+ loc.image = ImageRead(ExpandPath(this.file.url));
+ loc.largerDimension = loc.image.height > loc.image.width ? "height" : "width";
+ loc.smallerDimension = loc.largerDimension == "width" ? "height" : "width";
+ loc.resizeArgs = {
+ name=loc.image
+ };
+
+ // If image is larger than resize specifications, resize it
+ if (loc.image.width > loc.style.width || loc.image.height > loc.style.height)
+ {
+ // If we're preserving same aspect ratio
+ if (loc.style.preserveAspect)
+ {
+ // Determine which dimension to use for resize
+ // Note: `ImageScaleToFit` doesn't accept an `argumentCollection` on Railo 3.3, so we need to decide with an `if` block
+ if (loc.largerDimension == "width")
+ ImageScaleToFit(loc.image, loc.style[loc.largerDimension], "");
+ else
+ ImageScaleToFit(loc.image, "", loc.style[loc.largerDimension]);
+ }
+ // If we're not preserving same aspect ratio
+ else
+ {
+ // Determine which dimension to use for resize
+ // Note: See note above about `ImageScaleToFit`
+ if (loc.smallerDimension == "width")
+ ImageScaleToFit(loc.image, loc.style[loc.smallerDimension], "");
+ else
+ ImageScaleToFit(loc.image, "", loc.style[loc.smallerDimension]);
+
+ // Crop excess
+ loc.newWidth = loc.image.width < loc.style.width ? loc.image.width : loc.style.width;
+ loc.newHeight = loc.image.height < loc.style.height ? loc.image.height : loc.style.height;
+ ImageCrop(loc.image, 0, 0, loc.newWidth, loc.newHeight);
+ }
+ }
+
+ // Build path for style file and write file
+ return $saveImageToStorage(
+ argumentCollection=arguments
+ , image=loc.image
+ , style=arguments.style);
+ </cfscript>
</cffunction>
<cffunction name="$saveFileToTempDirectory" access="public" output="false" returntype="struct">
<cfargument name="property" type="string" required="true" />
<cfscript>
- // set the file in a temp location to verify it's not evil
+ // Set the file in a temp location to verify it's not evil
var fileArgs = {
action = "upload"
, fileField = this[arguments.property & "$attachment"]
@@ -92,6 +184,7 @@
<cfargument name="url" type="string" required="true" />
<cfargument name="path" type="string" required="true" />
<cfargument name="storage" type="string" required="true" />
+ <cfargument name="fileSize" type="numeric" required="true" />
<cfscript>
var loc = {};
@@ -99,6 +192,43 @@
arguments.path = $createAttachmentPath(argumentCollection=arguments);
arguments.url = $createAttachmentPath(argumentCollection=arguments);
arguments.storage = ListToArray(ReplaceList(arguments.storage, "filesystem,s3", "FileSystem,S3"));
+ arguments.fileSize = arguments.fileSize;
+
+ for (loc.storageType in arguments.storage)
+ {
+ if (!StructKeyExists(request, "storage") || !StructKeyExists(request.storage, loc.storageType))
+ request.storage[loc.storageType] = $createObjectFromRoot(
+ path = "plugins.attachments.storage"
+ , fileName = loc.storageType
+ , method = "init");
+
+ request.storage[loc.storageType].write(source=arguments.source, path=arguments.path);
+ }
+
+ StructDelete(arguments, "source", false);
+ StructDelete(arguments, "allowExtensions");
+ StructDelete(arguments, "blockExtensions");
+ </cfscript>
+ <cfreturn arguments />
+</cffunction>
+
+<cffunction name="$saveImageToStorage" access="public" output="false" returntype="struct">
+ <cfargument name="image" required="true" hint="Image object to save." />
+ <cfargument name="property" type="string" required="true" hint="Property to store metadata to." />
+ <cfargument name="url" type="string" required="true" hint="URL pattern." />
+ <cfargument name="path" type="string" required="true" hint="Path pattern." />
+ <cfargument name="storage" type="string" required="true" hint="Storage." />
+ <cfargument name="style" type="string" required="true" hint="Style name." />
+ <cfscript>
+ var loc = {};
+
+ arguments.fileName = ListLast(arguments.image.source, "/\");
+ arguments.path = $createAttachmentPath(argumentCollection=arguments);
+ arguments.url = $createAttachmentPath(argumentCollection=arguments);
+ arguments.storage = ListToArray(ReplaceList(arguments.storage, "filesystem,s3", "FileSystem,S3"));
+ arguments.source = GetTempDirectory() & arguments.fileName;
+
+ ImageWrite(arguments.image, arguments.source);
for (loc.storageType in arguments.storage)
{
@@ -112,6 +242,10 @@
}
StructDelete(arguments, "source", false);
+ StructDelete(arguments, "allowExtensions");
+ StructDelete(arguments, "blockExtensions");
+ StructDelete(arguments, "image");
+ StructDelete(arguments, "styles");
</cfscript>
<cfreturn arguments />
</cffunction>
View
2  attachments/model/validations.cfm
@@ -11,7 +11,7 @@
<cfset $registerValidation(methods="$validatesAttachmentPresenceOf", argumentCollection=arguments) />
</cffunction>
-<cffunction name="$validatesAttachmentPresenceOf" access="public" output="false" returntype="void" mixin="model">
+<cffunction name="$validatesAttachmentPresenceOf" access="public" output="false" returntype="boolean" mixin="model">
<cfscript>
var returnValue = false;
// if the property does not exist
View
275 index.cfm
@@ -0,0 +1,275 @@
+<cfsetting enablecfoutputonly="true" />
+
+<cfset attachments = {}>
+<cfset attachments.version = "0.5">
+
+<cfinclude template="stylesheets/doc_styles.cfm" />
+
+<cfoutput>
+
+<h1>Attachments v#attachments.version#</h1>
+
+<p>
+ Add support for uploaded files to your model with the <tt>hasAttachment()</tt> function.
+</p>
+<p>
+ Automatically resize uploaded images to a set of &quot;styles&quot; that you define. (For example, you could automatically
+ resize for thumbnail, small, medium, large, etc.)
+</p>
+<p>
+ Overrides <tt><a href="http://cfwheels.org/docs/function/filefield">fileField()</a></tt> to work better with <tt>&lt;cffile&gt;</tt>
+ and <a href="http://cfwheels.org/docs/chapter/nested-properties">nested properties</a>.
+</p>
+
+<h2>Dependencies</h2>
+<p>You must also install the JSON Properties plugin for the Attachments plugin to work.</p>
+
+<h2>Usage</h2>
+<p>Call the included <tt>hasAttachment()</tt> from a model's <tt>init()</tt> method to bind one or more properties to handle uploaded files.</p>
+<p>
+ The plugin stores data about the uploaded files as serialized JSON data in your model, so you should set the configured property's
+ corresponding database column to a type of <tt>TEXT</tt> or similar.
+</p>
+
+<h3>Arguments</h3>
+<table>
+ <thead>
+ <tr>
+ <th>Argument</th>
+ <th>Type</th>
+ <th>Required</th>
+ <th>Default</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><tt>property</tt></td>
+ <td>string</td>
+ <td><tt>true</tt></td>
+ <td></td>
+ <td>Name of property on the model to store JSON data related to the attached file.</td>
+ </tr>
+ <tr class="highlight">
+ <td><tt>url</tt></td>
+ <td>string</td>
+ <td><tt>false</tt></td>
+ <td><tt>/files/attachments/:model/<br />:property/:id/:style/:filename</tt></td>
+ <td>Format in which to reference the file as a URL. Use placeholders for <tt>:model</tt>, <tt>:property</tt>, <tt>:id</tt>, <tt>:style</tt>, and <tt>:filename</tt>.</td>
+ </tr>
+ <tr>
+ <td><tt>path</tt></td>
+ <td>string</td>
+ <td><tt>false</tt></td>
+ <td><tt>/files/attachments/:model/<br />:property/:id/:style/:filename</tt></td>
+ <td>Format in which to store the file in storage. Use placeholders for <tt>:model</tt>, <tt>:property</tt>, <tt>:id</tt>, <tt>:style</tt>, and <tt>:filename</tt>.</td>
+ </tr>
+ <tr class="highlight">
+ <td><tt>styles</tt></td>
+ <td>string</td>
+ <td><tt>false</tt></td>
+ <td><tt>[empty string]</tt></td>
+ <td>You may pass in multiple styles. The syntax is <tt>nameOfStyle:widthxheight&gt;</tt>. An actual example would be <tt>small:150x150&gt;,medium:300x300></tt>. The greater than sign at the end means that the attchments plugin should keep the aspect ratio of the photo uploaded. Styles will only be run on images that your ColdFusion server can do processing on.</td>
+ </tr>
+ <tr>
+ <td><tt>storage</tt></td>
+ <td>string</td>
+ <td><tt>false</tt></td>
+ <td><tt>filesystem</tt></td>
+ <td>Other options include <tt>s3</tt> and <tt>filesystem,s3</tt></td>
+ </tr>
+ <tr class="highlight">
+ <td><tt>blockExtensions</tt></td>
+ <td>string</td>
+ <td><tt>false</tt></td>
+ <td><tt>cfm,cfml,cfc,dbm,jsp,asp,<br />aspx,exe,php,cgi,shtml</tt></td>
+ <td>List of file extensions to not allow. This is the default behavior unless overridden by <tt>allowExtensions</tt>. If <tt>allowExtensions</tt> is set, this argument is then ignored.</td>
+ </tr>
+ <tr>
+ <td><tt>allowExtensions</tt></td>
+ <td>string</td>
+ <td><tt>false</tt></td>
+ <td><tt>[empty string]</tt></td>
+ <td>List of file extensions to allow. If this is set, the <tt>blockExtensions</tt> argument is ignored.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h3>Callbacks</h3>
+<p>
+ This plugin adds its own callbacks to the model's callback chain.
+</p>
+<ul>
+ <li>
+ <tt><a href="http://cfwheels.org/docs/function/aftercreate">afterCreate</a></tt>:
+ Save attachment info to database and files to file system(s).
+ </li>
+ <li>
+ <tt><a href="http://cfwheels.org/docs/function/beforevalidationonupdate">beforeValidationOnUpdate</a></tt>:
+ Save attachment info to database and files to file system(s).
+ </li>
+ <li>
+ <tt><a href="http://cfwheels.org/docs/function/afterdelete">afterDelete</a></tt>: Delete attachment files.
+ </li>
+</ul>
+<p>
+ Most of the time, this will not matter to you, but if you want for the model to do additional processing on the data after
+ the plugin has done its job, you will want to add your own callback chains using
+ <tt><a href="http://cfwheels.org/docs/function/afterCreate">afterCreate</a></tt> and
+ <tt><a href="http://cfwheels.org/docs/function/afterUpdate">afterUpdate</a></tt>.
+</p>
+
+<h2>Examples</h2>
+
+<h3>Example 1: Simple configuration</h3>
+<p>
+ In its most simple form, let's pretend that you want to save files to a property in the <tt>comment</tt> model called <tt>attachment</tt>:
+</p>
+<pre>
+&lt;--- models/Comment.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Model&quot;&gt;
+ &lt;cffunction name=&quot;init&quot;&gt;
+ &lt;!--- The `attachment` column should be of type `TEXT` ---&gt;
+ &lt;cfset hasAttachment(&quot;attachment&quot;)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;</pre>
+<p>
+ In your form, you can use the <tt>fileField()</tt> helper to allow users to upload the attachment, and the
+ plugin will take care of the rest.
+</p>
+<pre>
+&lt;cfoutput&gt;
+ ##startFormTag(action=&quot;create&quot;)##
+ ##fileField(label=&quot;Upload an Attachment&quot; objectName=&quot;comment&quot;, property=&quot;attachment&quot;)##
+ ##submitTag(value=&quot;Upload&quot;)##
+ ##endFormTag()##
+&lt;/cfoutput&gt;</pre>
+<p>
+ On your application's file system, the file will be saved to
+ <tt>/files/attachments/comment/attachment/197/my_spreadsheet.xlsx</tt> (assuming that the record gets assigned an <tt>id</tt>
+ of <tt>197</tt> and that the file uploaded by the user is named <tt>my_spreadsheet.xlsx</tt>). You will then be able to reference
+ data about the uploaded file in the <tt>attachment</tt> property.
+</p>
+<pre>
+&lt;--- controllers/Comments.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Controller&quot;&gt;
+ &lt;cffunction name=&quot;view&quot;&gt;
+ &lt;cfset comment = model(&quot;comment&quot;).findByKey(197)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;
+
+&lt;--- views/comments/view.cfm ---&gt;
+&lt;cfoutput&gt;
+ &lt;p&gt;&lt;a href=&quot;##comment.attachment.url##&quot;&gt;Download the File&lt;/a&gt;&lt;/p&gt;
+&lt;/cfoutput&gt;</pre>
+
+<h3>Example 2: Saving to a different location</h3>
+<p>
+ If you want to store the file in a different location on the server, you can specify the path using the <tt>:path</tt>
+ argument and the placeholders for <tt>:model</tt>, <tt>:property</tt>, <tt>:id</tt>, <tt>:style</tt> (more on this
+ later), and <tt>:filename</tt>. Note that the <tt>:style</tt> part of the path is only used if you define image
+ styles using the <tt>styles</tt> argument.
+</p>
+<pre>
+&lt;--- models/Comment.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Model&quot;&gt;
+ &lt;cffunction name=&quot;init&quot;&gt;
+ &lt;!--- The `attachment` column should be of type `TEXT` ---&gt;
+ &lt;cfset hasAttachment(property=&quot;attachment&quot;, path=&quot;/files/uploads/:model/:property/:id/:style/:filename&quot;)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;</pre>
+<p>
+ If your server is configured to serve files from different URL than the default, you can also specify that with the <tt>url</tt> argument.
+</p>
+<pre>
+&lt;--- models/Comment.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Model&quot;&gt;
+ &lt;cffunction name=&quot;init&quot;&gt;
+ &lt;cfset hasAttachment(property=&quot;attachment&quot;, path=&quot;/files/uploads/:model/:property/:id/:style/:filename&quot;, url=&quot;http://media.example.com/:model/:property/:id/:style/:filename&quot;)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;</pre>
+
+<h3>Example 3: Styles for images</h3>
+<p>
+ The attachments plugin will also handle the creation of &quot;styles&quot; for image files uploaded to your model.
+ If you choose, you can create any named style that you would like (for example, <tt>thumbnail</tt>).
+</p>
+<p>
+ Let's say that we want to create 2 image styles: a <tt>thumbnail</tt> style at 50 x 50 pixels and a
+ <tt>medium</tt> style at 250 x 250 pixels. You would use the <tt>styles</tt> argument like so:
+</p>
+<pre>
+&lt;--- models/Profile.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Model&quot;&gt;
+ &lt;cffunction name=&quot;init&quot;&gt;
+ &lt;cfset hasAttachment(property=&quot;avatar&quot;, styles=&quot;medium:250x250,thumbnail:50x50&quot;)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;</pre>
+<p>
+ Now when the user uploads an image file supported by your CFML engine and your model passes validation, the
+ Attachments plugin will resize the image into those dimensions (and crop off any excess).
+</p>
+<p>
+ If you'd rather keep an image's aspect ratio the same and define a set of boundaries for the image,
+ you can add a <tt>&gt;</tt> character to the end of any of the styles.
+</p>
+<pre>
+&lt;--- models/Profile.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Model&quot;&gt;
+ &lt;cffunction name=&quot;init&quot;&gt;
+ &lt;cfset hasAttachment(property=&quot;avatar&quot;, styles=&quot;medium:250x250&gt;,thumbnail:50x50&quot;)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;</pre>
+<p>
+ With the styles defined above, let's say that the user uploads an image called <tt>Vacation-in-Switzerland.jpg</tt>
+ that is 400 by 300 pixels. The resulting file structure will look like this after the Attachments plugin does its
+ magic:
+</p>
+<ul>
+ <li>
+ <tt>/files/attachments/profile/avatar/423/medium/Vacation-in-Switzerland.jpg</tt> --&gt; 250 x 188 pixels
+ (long edge resized to 250 pixels, short edge resized proportionately)
+ </li>
+ <li>
+ <tt>/files/attachments/profile/avatar/423/thumbnail/Vacation-in-Switzerland.jpg</tt> --&gt; 50 x 50 pixels
+ (height is set to 50 pixels, width is cropped at 50 pixels)
+ </li>
+ <li>
+ <tt>/files/attachments/profile/avatar/423/Vacation-in-Switzerland.jpg</tt> --&gt; 400 x 300 pixels (original dimensions)
+ </li>
+</ul>
+
+<h3>Example 4: Whitelisting files</h3>
+<p>
+ By default, the Attachments plugin will block a list of potentially malicious files (using a default value for the
+ <tt>blockExtensions</tt> argument). But it is strongly recommended for security reasons that you define a whitelist of
+ what is allowed to be uploaded instead.
+</p>
+<p>
+ Pretending that we only wanted some Microsoft Office formats to be uploaded, we could define something like this using the
+ <tt>allowExtensions</tt> argument:
+</p>
+<pre>
+&lt;--- models/Comment.cfc ---&gt;
+&lt;cfcomponent extends=&quot;Model&quot;&gt;
+ &lt;cffunction name=&quot;init&quot;&gt;
+ &lt;cfset hasAttachment(property=&quot;attachment&quot;, allowExtensions=&quot;doc,docx,xls,xlsx,ppt,pptx,mdb&quot;)&gt;
+ &lt;/cffunction&gt;
+&lt;/cfcomponent&gt;</pre>
+<p>
+ Note that when the <tt>allowExtensions</tt> list is provided, the <tt>blockExtensions</tt> list will be ignored completely.
+</p>
+
+<h2>Uninstallation</h2>
+<p>To uninstall this plugin, simply delete the <tt>/plugins/Attachments-#attachments.version#.zip</tt> file.</p>
+
+<h2>Credits</h2>
+<p>
+ This plugin was created by <a href="http://iamjamesgibson.com/">James Gibson</a> and
+ <a href="http://www.clearcrystalmedia.com/pm/">Chris Peters</a> with support from
+ <a href="http://www.liquifusion.com/">Liquifusion Studios</a>.
+</p>
+
+</cfoutput>
+
+<cfsetting enablecfoutputonly="false" />
View
40 stylesheets/doc_styles.cfm
@@ -0,0 +1,40 @@
+<style type="text/css">
+
+h2 code {
+ color: #B00701;
+}
+
+h3 {
+ color: #B00701;
+ font-size: 15px;
+ margin-top: 10px;
+}
+
+h3 code {
+ color: #B00701;
+}
+
+table {
+ border: 1px solid #ccc;
+ margin-bottom: 20px;
+}
+
+table thead tr th,
+table tbody tr td {
+ padding: 2px 5px;
+}
+
+table tbody tr.highlight {
+ background: #eee;
+}
+
+table thead tr th {
+ border-bottom: 1px solid #ccc;
+}
+
+ins {
+ font-weight: bold;
+ text-decoration: none;
+}
+
+</style>

No commit comments for this range

Something went wrong with that request. Please try again.