Author: ivaynberg
Date: Wed Feb 28 22:13:52 2007
New Revision: 513161
URL: http://svn.apache.org/viewvc?view=rev&rev=513161
Log:
bah, checking in missing files
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.html
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.java
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.js
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.properties
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.html
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.html?view=auto&rev=513161
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.html
(added)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.html
Wed Feb 28 22:13:52 2007
@@ -0,0 +1,6 @@
+<wicket:panel>
+<input wicket:id="upload" type="file" class="wicket-mfu-field"/>
+<div wicket:id="container" class="wicket-mfu-container">
+<div wicket:id="caption" class="wicket-mfu-caption"></div>
+</div>
+</wicket:panel>
\ No newline at end of file
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.java
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.java?view=auto&rev=513161
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.java
(added)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.java
Wed Feb 28 22:13:52 2007
@@ -0,0 +1,374 @@
+package wicket.markup.html.form.upload;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import wicket.Component;
+import wicket.Request;
+import wicket.ResourceReference;
+import wicket.markup.ComponentTag;
+import wicket.markup.html.IHeaderContributor;
+import wicket.markup.html.IHeaderResponse;
+import wicket.markup.html.WebComponent;
+import wicket.markup.html.WebMarkupContainer;
+import wicket.markup.html.basic.Label;
+import wicket.markup.html.form.Form;
+import wicket.markup.html.form.FormComponentPanel;
+import wicket.markup.html.form.upload.FileUpload;
+import wicket.markup.html.resources.JavascriptResourceReference;
+import wicket.model.AbstractReadOnlyModel;
+import wicket.model.IModel;
+import wicket.model.Model;
+import wicket.protocol.http.IMultipartWebRequest;
+import wicket.util.convert.ConversionException;
+import wicket.util.string.Strings;
+import wicket.util.upload.FileItem;
+
+/**
+ * Form component that allows the user to select multiple files to upload via a
+ * single <input type="file"/> field.
+ *
+ * Notice that this component clears its model at the end of the request, so
the
+ * uploaded files MUST be processed within the request they were uploaded.
+ *
+ * Uses javascript implementation from
+ *
http://the-stickman.com/web-development/javascript/upload-multiple-files-with-a-single-file-element/
+ *
+ * For customizing caption text see [EMAIL PROTECTED] #RESOURCE_LIMITED} and
+ * [EMAIL PROTECTED] #RESOURCE_UNLIMITED}
+ *
+ * For an example of styling using CSS see the upload example in
wicket-examples
+ *
+ * @author Igor Vaynberg (ivaynberg)
+ */
+public class MultiFileUploadField extends FormComponentPanel implements
IHeaderContributor
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * Represents an unlimited max count of uploads
+ */
+ public static final int UNLIMITED = 1;
+
+ /**
+ * Resource key used to retrieve caption message for when a limit on the
+ * number of uploads is specfied. The limit is represented via ${max}
+ * variable.
+ *
+ * Example: wicket.mfu.caption.limited=Files (maximum ${max}):
+ */
+ public static final String RESOURCE_LIMITED =
"wicket.mfu.caption.limited";
+
+ /**
+ * Resource key used to retrieve caption message for when no limit on
the
+ * number of uploads is specfied.
+ *
+ * Example: wicket.mfu.caption.unlimited=Files:
+ */
+ public static final String RESOURCE_UNLIMITED =
"wicket.mfu.caption.unlimited";
+
+
+ private static final String NAME_ATTR = "name";
+
+ private static final String MAGIC_SEPARATOR = "_mf_";
+
+
+ private static final ResourceReference JS = new
JavascriptResourceReference(
+ MultiFileUploadField.class, "MultiFileUploadField.js");
+
+
+ private final WebComponent upload;
+ private final WebMarkupContainer container;
+
+ private final int max;
+
+ private transient String[] inputArrayCache = null;
+
+ /**
+ * Constructor
+ *
+ * @param id
+ * @param model
+ */
+ public MultiFileUploadField(String id)
+ {
+ this(id, null, -1);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param id
+ * @param model
+ * @param max
+ * max number of files a user can upload
+ */
+ public MultiFileUploadField(String id, int max)
+ {
+ this(id, null, max);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param id
+ * @param model
+ */
+ public MultiFileUploadField(String id, IModel model)
+ {
+ this(id, model, UNLIMITED);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param id
+ * @param model
+ * @param max
+ * max number of files a user can upload
+ *
+ */
+ public MultiFileUploadField(String id, IModel model, int max)
+ {
+ super(id, model);
+
+ this.max = max;
+
+ upload = new WebComponent("upload");
+ upload.setOutputMarkupId(true);
+ add(upload);
+
+ container = new WebMarkupContainer("container");
+ container.setOutputMarkupId(true);
+ add(container);
+
+ container.add(new Label("caption", new CaptionModel()));
+ }
+
+ /**
+ * @see
wicket.markup.html.form.FormComponentPanel#onComponentTag(wicket.markup.ComponentTag)
+ */
+ protected void onComponentTag(ComponentTag tag)
+ {
+ super.onComponentTag(tag);
+ // remove the name attribute added by the FormComponent
+ if (tag.getAttributes().containsKey(NAME_ATTR))
+ {
+ tag.getAttributes().remove(NAME_ATTR);
+ }
+ }
+
+ /**
+ * @see wicket.Component#internalOnAttach()
+ */
+ protected void internalOnAttach()
+ {
+ super.internalOnAttach();
+
+ // auto toggle form's multipart property
+ Form form = (Form)findParent(Form.class);
+ if (form == null)
+ {
+ // woops
+ throw new IllegalStateException("Component " +
getClass().getName() + " must have a "
+ + Form.class.getName() + " component
above in the hierarchy");
+ }
+ form.setMultiPart(true);
+ }
+
+
+ /**
+ * @see
wicket.markup.html.IHeaderContributor#renderHead(wicket.markup.html.IHeaderResponse)
+ */
+ public void renderHead(IHeaderResponse response)
+ {
+ // initialize the javascript library
+ response.renderJavascriptReference(JS);
+ response.renderOnDomReadyJavascript("new MultiSelector('" +
getInputName()
+ + "', document.getElementById('" +
container.getMarkupId() + "'), " + max
+ + ").addElement(document.getElementById('" +
upload.getMarkupId() + "'));");
+ }
+
+ /**
+ * @see wicket.markup.html.form.FormComponent#getInputAsArray()
+ */
+ public String[] getInputAsArray()
+ {
+ // fake the input array as if it contained an array of all
uploaded file
+ // names
+
+ if (inputArrayCache == null)
+ {
+ // this array will aggregate all input names
+ ArrayList names = null;
+
+ final Request request = getRequest();
+ if (request instanceof IMultipartWebRequest)
+ {
+ // retrieve the filename->FileItem map from
request
+ final Map itemNameToItem =
((IMultipartWebRequest)request).getFiles();
+ Iterator it =
itemNameToItem.entrySet().iterator();
+ while (it.hasNext())
+ {
+ // iterate over the map and build the
list of filenames
+
+ final Entry entry = (Entry)it.next();
+ final String name =
(String)entry.getKey();
+ final FileItem item =
(FileItem)entry.getValue();
+
+ if (!Strings.isEmpty(name) &&
name.startsWith(getInputName() + MAGIC_SEPARATOR)
+ &&
!Strings.isEmpty(item.getName()))
+ {
+
+ // make sure the fileitem
belongs to this component and
+ // is not empty
+
+ names = (names != null) ? names
: new ArrayList();
+ names.add(name);
+ }
+ }
+ }
+
+ if (names != null)
+ {
+ inputArrayCache = (String[])names.toArray(new
String[names.size()]);
+ }
+ }
+ return inputArrayCache;
+
+ }
+
+ /**
+ * @see
wicket.markup.html.form.FormComponent#convertValue(java.lang.String[])
+ */
+ protected Object convertValue(String[] value) throws ConversionException
+ {
+ // convert the array of filenames into a collection of FileItems
+
+ Collection uploads = null;
+
+ final String[] filenames = getInputAsArray();
+
+ if (filenames != null)
+ {
+ final IMultipartWebRequest request =
(IMultipartWebRequest)getRequest();
+
+ uploads = new ArrayList(filenames.length);
+
+ for (int i = 0; i < filenames.length; i++)
+ {
+ uploads.add(new
FileUpload(request.getFile(filenames[i])));
+ }
+ }
+
+ return uploads;
+
+ }
+
+ /**
+ * @see wicket.markup.html.form.FormComponent#updateModel()
+ */
+ public void updateModel()
+ {
+ final Object object = getModelObject();
+
+ // figure out if there is an existing model object collection
for us to
+ // reuse
+ if (object == null)
+ {
+ // no existing collection, push the one we created
+ setModelObject(getConvertedInput());
+ }
+ else
+ {
+ if (!(object instanceof Collection))
+ {
+ // fail early if there is something interesting
in the model
+ throw new IllegalStateException("Model object
of " + getClass().getName()
+ + " component must be of type
`" + Collection.class.getName() + "<"
+ + FileUpload.class.getName() +
">` but is of type `"
+ + object.getClass().getName() +
"`");
+ }
+ else
+ {
+ // refresh the existing collection
+ Collection collection = (Collection)object;
+ collection.clear();
+ if (getConvertedInput() != null)
+ {
+
collection.addAll((Collection)getConvertedInput());
+ }
+
+ // push the collection in case the model is
listening to
+ // setobject calls
+ setModelObject(collection);
+ }
+ }
+ }
+
+ /**
+ * @see wicket.Component#internalOnDetach()
+ */
+ protected void internalOnDetach()
+ {
+ // cleanup any opened filestreams
+ Collection uploads = (Collection)getConvertedInput();
+ if (uploads != null)
+ {
+ Iterator it = uploads.iterator();
+ while (it.hasNext())
+ {
+ final FileUpload upload = (FileUpload)it.next();
+ upload.closeStreams();
+ }
+ }
+
+ // cleanup any caches
+ inputArrayCache = null;
+
+ // clean up the model because we dont want FileUpload objects
in session
+ Object modelObject = getModelObject();
+ if (modelObject != null && (modelObject instanceof Collection))
+ {
+ ((Collection)modelObject).clear();
+ }
+
+ super.internalOnDetach();
+ }
+
+ /**
+ * Model that will construct the caption string
+ *
+ * @author ivaynberg
+ */
+ private class CaptionModel extends AbstractReadOnlyModel
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @see
wicket.model.AbstractReadOnlyModel#getObject(wicket.Component)
+ */
+ public Object getObject(Component component)
+ {
+ if (max == UNLIMITED)
+ {
+ return getString(RESOURCE_UNLIMITED);
+ }
+ else
+ {
+ return getString(RESOURCE_LIMITED,
Model.valueOf(Collections.singletonMap("max",
+ Long.valueOf(max))));
+ }
+ }
+
+ }
+}
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.js
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.js?view=auto&rev=513161
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.js
(added)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.js
Wed Feb 28 22:13:52 2007
@@ -0,0 +1,158 @@
+/**
+ * Convert a single file-input element into a 'multiple' input list
+ *
+ * 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 multi_selector = new MultiSelector( document.getElementById(
'files_list' ), 3 );
+ *
+ * 4. Add the first element
+ * eg. multi_selector.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
+ * with thanks to:
+ * [for Safari fixes]
+ * Luis Torrefranca -- http://www.law.pitt.edu
+ * and
+ * Shawn Parker & John Pennypacker -- http://www.fuzzycoconut.com
+ * [for duplicate name bug]
+ * 'neal'
+ */
+function MultiSelector( eprefix, list_target,max ){
+
+ // Where to write the list
+ this.list_target = list_target;
+ // How many elements?
+ this.count = 0;
+ // How many elements?
+ this.id = 0;
+ // Is there a maximum?
+ if( max ){
+ this.max = max;
+ } else {
+ this.max = -1;
+ };
+
+ this.element_name_prefix=eprefix;
+
+ /**
+ * Add a new file input element
+ */
+ this.addElement = function( element ){
+
+ // Make sure it's a file input element
+ if( element.tagName == 'INPUT' && element.type == 'file' ){
+
+ // Element name -- what number am I?
+ element.name = this.element_name_prefix +
"_mf_"+this.id++;
+
+ // Add reference to this object
+ element.multi_selector = this;
+
+ // What to do when a file is selected
+ element.onchange = function(){
+
+ // New file input
+ var new_element = document.createElement(
'input' );
+ new_element.type = 'file';
+
+ // Add new element
+ this.parentNode.insertBefore( new_element, this
);
+
+ // Apply 'update' to element
+ this.multi_selector.addElement( new_element );
+
+ // Update list
+ this.multi_selector.addListRow( this );
+
+ // Hide this: we can't use display:none because
Safari doesn't like it
+ this.style.position = 'absolute';
+ this.style.left = '-1000px';
+
+ };
+ // If we've reached maximum number, disable input
element
+ if( this.max != -1 && this.count >= this.max ){
+ element.disabled = true;
+ };
+
+ // File element counter
+ this.count++;
+ // Most recent element
+ this.current_element = element;
+
+ } else {
+ // This can only be applied to file input elements!
+ alert( 'Error: not a file input element' );
+ };
+
+ };
+
+ /**
+ * Add a new row to the list of files
+ */
+ this.addListRow = function( element ){
+
+ // Row div
+ var new_row = document.createElement( 'div' );
+
+ // Delete button
+ var new_row_button = document.createElement( 'input' );
+ new_row_button.type = 'button';
+ new_row_button.value = 'Delete';
+
+ // References
+ new_row.element = element;
+
+ // Delete function
+ new_row_button.onclick= function(){
+
+ // Remove element from form
+ this.parentNode.element.parentNode.removeChild(
this.parentNode.element );
+
+ // Remove this row from the list
+ this.parentNode.parentNode.removeChild( this.parentNode
);
+
+ // Decrement counter
+ this.parentNode.element.multi_selector.count--;
+
+ // Re-enable input element (if it's disabled)
+
this.parentNode.element.multi_selector.current_element.disabled = false;
+
+ // Appease Safari
+ // without it Safari wants to reload the browser
window
+ // which nixes your already queued uploads
+ return false;
+ };
+
+ // Set row value
+ new_row.innerHTML = element.value;
+
+ // Add button
+ new_row.appendChild( new_row_button );
+
+ // Add it to the list
+ this.list_target.appendChild( new_row );
+
+ };
+
+};
\ No newline at end of file
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.properties
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.properties?view=auto&rev=513161
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.properties
(added)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/upload/MultiFileUploadField.properties
Wed Feb 28 22:13:52 2007
@@ -0,0 +1,2 @@
+wicket.mfu.caption.unlimited=Files:
+wicket.mfu.caption.limited=Files (maximum ${max}):
\ No newline at end of file