gadget-ui.input.FileUploader example

CFML, CLI, JavaScript

I'm going to demonstrate how to use the new gadget-ui.input.FileUploader component in the gadget-ui library. First, we need an HTML page to host the component. This code comes directly from the /test folder in the gadget-ui repo:

fileuploader.htm

<!doctype html>
<html>

<head>
	<title>gadget-ui File Uploader Test</title>
	<script src='../bower_components/modlazy/dist/modlazy.min.js'></script>
	<script>
		modlazy.load(
			[
				"fileuploader.js < ../dist/gadget-ui.js",
				"../dist/gadget-ui.css"
			],
			function() {
				console.log("All files have been loaded");
			}
		);
	</script>

	<style>
		body {
			font-size: 1em;
		}

		input,
		select,
		select option {
			font-size: 1em;
		}

		#fileUploadDiv {
			height: 500px;
			width: 500px;
			text-align: center;
			margin-top: auto;
			margin-bottom: auto;
		}
	</style>

</head>

<body>
	<p>Test the FileUploader control.</p>

	<div id="fileUploadDiv"></div>
</body>

</html>

I am using a small dependency loader called modlazy to load my assets. This page shows a div called fileUploadDiv that will host the component. Let's look at the fileuploader.js file:

fileuploader.js


var options = {
  uploadURI: "/test/fileuploader.upload.cfm",
  tags: "file upload",
  willGenerateThumbnails: true,
  title: "Upload Files",
  showUploadButton: false
};

filedialog = gadgetui.objects.Constructor( gadgetui.input.FileUploader, [ document.querySelector("#fileUploadDiv"), options ]);

The uploadURI specifies a CFML page  that should be compatible with Lucee and Adobe ColdFusion, although I am testing it with Lucee, so there could be bugs in the ACF implementation right now. We'll dig into that page in a minute.

Right now, what I want to show is how the component is being instantiated. Rather than use the new keyword, I have ported all of he gadget-ui code to use the built-in gadgetui.objects.Constructor method, which internally uses Object.create(). I have also included a new option, showUploadButton, so you can either have a drop zone, or have a drop zone and a file upload button.

On drop  or file select, the component cuts the file up into 1MB chunks and uploads the chunks one at a time. Let's have a look at the CFML receiver file:

fileuploader.upload.cfm

<cfscript>
	filePath = "#expandpath("./")#upload\";
	separator = iif(expandpath("./") contains "/",de("/"),de("\"));
	filePath = expandpath("./") & "upload" & separator;
	chunkPath = filePath & "temp" & separator & createUUID();
	inputStream = getPageContext().getRequest().getOriginalRequest().getInputStream();
	ioutil = createObject( "java", "org.apache.commons.io.IOUtils" );
	outputStream = createObject( "java", "java.io.FileOutputStream" ).init( chunkPath );
	ioutil.copy( inputStream, outputStream );

	contentLength = gethttprequestdata().headers['Content-Length'];
	args.id = gethttprequestdata().headers['x-id'];
	args.filename = gethttprequestdata().headers['x-filename'];
	args.filesize = gethttprequestdata().headers['x-filesize'];
	args.part = gethttprequestdata().headers['x-filepart'];
	args.parts = gethttprequestdata().headers['x-parts'];

	if( args.part eq 1 ){
		fileId = createUUID();
	}else{
		fileId = args.id;
	}
	args.temp_file = chunkPath;

	args.id = fileId;
	FilePartDAO = new model.FilePartDAO();
	FileService = new model.FileService( filePath = filePath, FilePartDAO = FilePartDAO );
	file = FileService.upload( argumentcollection = args );

	if( args.part eq args.parts ){
		writeoutput( SerializeJSON( file ) );
	}else{
		pc = getpagecontext();
		pc.setHeader("X-Id", fileId );
	}

</cfscript>

There is a lot going on in this code. Look at the use of Java input and output streams to copy the chunked data. I use Java classes here to guarantee good data coming through from the binary data POST. Note that I am using UUIDs to identify the chunks and store them in a temporary folder on the server, where they stay until they are re-assembled into the original file.

Also see the use of gethttprequestdata() to pull the headers for the chunked data. The x- headers are all custom headers created by the FileUploader component to track the file upload. x-filepart tells the server which part of the file is being uploaded, and x-parts tells the server how many total parts there are.

Next, note that this code takes place in a loop controlled by the FileUploader component. When the end of the loop is reached, the file upload is completed and a response is sent back to the client. 

The real work of the upload is being done in the FileService CFML component. This example uses a baseline implementation that uploads the file(s) to a destination folder on the server. Other implementations may store the file in MongoDB or other NoSQL stores. I will dig into the FileService component next time.


gadget-ui JavaScript library Updated

JavaScript

I have been working on an update of the gadget-ui JavaScript library that includes a new feature - a multi-file upload component called gadgetui.input.FileUploader. The component is based on some earlier work of mine, and originally used jQuery, so the jQuery version was written first and sticks to the original. 

The plain JavaScript version is a port of the jQuery version, and I am moving ahead with development on the plain JS version. The original component instantiated inside a dialog box with a close button, and I have eliminated those features in the plain JS version, opting to allow the developer to instantiate the component wherever needed, and managing its lifecycle as required. You can clone the library from my gadget-ui GitHub repository.


Creating a Blog site with ContentBox on Ubuntu

CFML, CLI, CommandBox, ContentBox, Linux, Ubuntu

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

Shoestring Lab has decided to set up several website for its operations, and you have been tasked with using ContentBox to build the first site, an internal content and blog site.]


Logging into Lucee Admin of a New Instance

CommandBox, Lucee, Web Development

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

Provisioning new web application servers in Lucee requires logging into the Lucee Admin, setting administrator passwords, and updating Lucee.]


Installing CommandBox on Ubuntu 18.04 to manage CFML-based Web app development

CLI, CommandBox, Lucee, Open Source, Ubuntu

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

Part of your job is setting up and managing internal and external web sites for the company. Your task is to install and configure CommandBox to manage the Lucee-based sites you are building.]


Adding People to Groups in OpenLDAP using Apache Directory Studio

OpenLDAP

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

Part of your job is managing user access to various internal computer resources. This task involves adding people to groups in OpenLDAP.]


Creating People in OpenLDAP using Apache Directory Studio

OpenLDAP

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

Part of your job is managing user access to various internal computer resources. Now that you have installed OpenLDAP and Apache Directory Studio, configured access and created some groups, you will need to add people to your new OpenLDAP service.]


Creating Groups in OpenLDAP using Apache Directory Studio

OpenLDAP

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

Part of your job is managing user access to various internal computer resources. This task involves adding groups to OpenLDAP.]


Install Apache Directory Studio in Ubuntu 18.04 to manage OpenLDAP

Open Source, OpenLDAP

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

As the admin for Shoestring Lab, you have installed and configured an OpenLDAP server to manage users and groups for various network services. Now you need a GUI tool to manage OpenLDAP. Enter Apache Directory Studio.]


Install and Configure OpenLDAP on Ubuntu 18.04

CLI, Linux, OpenLDAP, Ubuntu

[ This post is part of my ongoing instructional series on setting up some baseline IT infrastructure for the fictional startup Shoestring Lab. Shoestring has committed to using Open Source wherever possible. Shoestring Lab has standardized on Ubuntu for its server and desktop/laptop computer systems.

Today's lesson

As the admin for Shoestring Lab, you need to install OpenLDAP server to manage users and groups for various network services.]


Categories


Recent Entries

Entries Search