/* *********************************************************************** */
/*
** Convert a single file-input element into a 'multiple' input list.
**
** This function defines a class that will be instantiated as a global
** variable on the HTML document. The class wraps a collection of file input
** elements, with the newest one active and earlier ones displayed in a list
** with accompanying delete buttons.
**
** Usage:
** 1. Create a file input element (no name)
** eg. <input type="file" id="first_file_element">
** 2. Create a DIV for the output to be written to
** eg. <div id="files_list"></div>
** 3. Instantiate a MultiSelector object, passing in the DIV and an (optional) maximum number of files
** eg. var MS_Attachments = new MultiSelector( document.getElementById( 'files_list' ), 3 );
** 4. Add the first element
** eg. MS_Attachments.addElement( document.getElementById( 'first_file_element' ) );
** 5. That's it.
**
** You might (will) want to play around with the addListRow() method to make the output prettier.
**
** You might also want to change the line 
** element.name = 'file_' + this.count;
** ...to a naming convention that makes more sense to you.
**
** Licence:
** Use this however/wherever you like, just don't blame me if it breaks anything.
**
** Credit:
** If you're nice, you'll leave this bit:
**
** Class by Stickman -- http://www.the-stickman.com */
/* ----------------------------------------------------------------------- */
function MultiSelector( de_AttachmentTable )
{ 
this.de_AttachmentTable = de_AttachmentTable // Table that lists attachments
this.de_CurrentFileInput; 		// Allows us to re-enable if delete returns us below limit
this.s__FileInputName = ''; 		// 2008-Jan-31 EBM: Have to re-use name generated by Domino Designer
this.i__FileInputsCount = 0; 		// Count of file-input elements
this.i__FileInputsMaximum = -1; 	// Maximum file-input elements allowed; -1 for unlimited
// --------------------------------------------------------------------------
// Add a new file-input element.
// --------------------------------------------------------------------------
this.addFileInputElement = function( de_FileInput )
{ var de_NextInput;
// ---------------------------------------------------------------------
// Ensure the new element is a file-input.
// ---------------------------------------------------------------------
if( de_FileInput.tagName.toLowerCase() == 'input' && de_FileInput.type.toLowerCase() == 'file' )
// --------------------------------------------------------------
// Give the file input element a unique ID.
// 2008-Jan-31 EBM: We must use the name generated for the File
// Upload control by Domino Designer *for all subsequent
// file-input elements* or else the subsequent file attachments
// will not be saved. The unique ID must be handled via the "ID"
// attribute.
// --------------------------------------------------------------
{ if( this.s__FileInputName == '' )
this.s__FileInputName = de_FileInput.name;
else
de_FileInput.name = this.s__FileInputName;
de_FileInput.id = 'FileInput_' + (this.i__FileInputsCount < 10 ? '0' : '') + this.i__FileInputsCount;
// --------------------------------------------------------------
// Add a property to the file-input element to store a reference
// to the HTML document's instance of MultiSelector. This allows
// the event handler we're going to add to the element to access
// its Attachments table, and its addFileInputElement and
// addListRow functions.
// --------------------------------------------------------------
de_FileInput.MS_Attachments = this;
// --------------------------------------------------------------
// Also add a handler to the file-input element for the onchange
// event. In the handler, 'this' refers to the handler's owner -
// the file-input element.
// The event handler first looks to see if the attachment is
// already in the table, clearing itself if the attachment is
// found.
// --------------------------------------------------------------
de_FileInput.onchange = function()
{ for( var i = 0; i < this.MS_Attachments.de_AttachmentTable.rows.length; i++ )
{ if( this.value.toLowerCase() == this.MS_Attachments.de_AttachmentTable.rows(i).cells(1).innerHTML.toLowerCase() )
{ // Cannot find a way to erase the displayed text.
return;
}
}
// --------------------------------------------------------
// Create the next file-input element and insert it ahead
// of this file-input element (within whatever HTML element
// this file-input element resides).
// --------------------------------------------------------
de_NextInput = document.createElement( 'Input' );
de_NextInput.type = 'file';
de_NextInput.style.fontFamily = 'Arial';
de_NextInput.style.fontSize = '8pt';
this.parentNode.insertBefore( de_NextInput, this );
// --------------------------------------------------------
// Using the file-input element's reference to the HTML
// document's instance of MultiSelector, call the method to
// set up and display the next file-input element.
// --------------------------------------------------------
this.MS_Attachments.addFileInputElement( de_NextInput );
// --------------------------------------------------------
// Using the file-input element's reference to the global
// instance of MultiSelector, "move" the current file-input
// element to the dislay list.
// --------------------------------------------------------
this.MS_Attachments.addListRow( this );
this.style.display = 'none';
}
// --------------------------------------------------------------
// If we've decided to limit the number of attachments and have
// reached maximum, disable de_FileInput.
// --------------------------------------------------------------
if( this.i__FileInputsMaximum != -1 && this.i__FileInputsCount >= this.i__FileInputsMaximum )
de_FileInput.disabled = true;
// --------------------------------------------------------------
// File-input element counter (for upper-limit checking only)
// --------------------------------------------------------------
this.i__FileInputsCount++;
// --------------------------------------------------------------
// A reference to the most recent element, should the Delete
// button need to re-enable the element because we've returned
// below the limit.
// --------------------------------------------------------------
this.de_CurrentFileInput = de_FileInput;
}
}
// --------------------------------------------------------------------------
// Add a new row to the table of file attachments.
// --------------------------------------------------------------------------
this.addListRow = function( de_FileInput )
{ var de_DeleteIcon;
var de_TableRow;
var de_TableCell;
// --------------------------------------------------------------------
// Create a TR element to display the file-input element.
// --------------------------------------------------------------------
de_TableRow = this.de_AttachmentTable.insertRow();
// --------------------------------------------------------------------
// Create a Delete icon that may be used to delete the attachment. Add
// two properties to the icon to store references to the file-input
// element and the table-row element. This gives us easy access to
// both if we need to delete the attachment.
// --------------------------------------------------------------------
de_DeleteIcon = document.createElement( 'Img' );
de_DeleteIcon.src = '/icons/vwicn038.gif';
de_DeleteIcon.de_FileInput = de_FileInput;
de_DeleteIcon.de_TableRow = de_TableRow;
// --------------------------------------------------------------------
// Also add a handler to the Delete icon for the onclick event. In the
// handler, 'this' refers to the handler's owner - the Delete icon.
// --------------------------------------------------------------------
de_DeleteIcon.onclick = function()
{ 
// --------------------------------------------------------------
// Remove the file-input element (and any children that we may
// have forgotten about) from the HTML document.
// --------------------------------------------------------------
this.de_FileInput.removeNode( true );
// --------------------------------------------------------------
// Remove the table-row element (and its cells, and their
// contents) from the attachments table.
// --------------------------------------------------------------
this.de_TableRow.removeNode( true );
// --------------------------------------------------------------
// Using the Delete icon's reference to the file-input element,
// use the file-input element's reference to the HTML document's
// instance of MultiSelector to decrement the count of file-input
// elements.
// --------------------------------------------------------------
this.de_FileInput.MS_Attachments.i__FileInputsCount--;
// --------------------------------------------------------------
// Using the property we added when creating the Delete icon,
// retrieve the file-input element. Then use the property we
// added to the file-input element to retrieve the HTML
// document's instance of MultiSelector and re-enable the current
// file input element (in case it was disabled due to a maximum).
// --------------------------------------------------------------
this.de_FileInput.MS_Attachments.de_CurrentFileInput.disabled = false;
}
// --------------------------------------------------------------------
// Add the Delete icon and the file-input element's display value to
// the table row.
// --------------------------------------------------------------------
de_TableCell = de_TableRow.insertCell();
de_TableCell.style.width = 20;
de_TableCell.appendChild( de_DeleteIcon );
de_TableCell = de_TableRow.insertCell();
de_TableCell.innerHTML = de_FileInput.value;
}
}

