/*
Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
if(!dojo._hasResource["dojox.form.Uploader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.form.Uploader"] = true;
dojo.provide("dojox.form.Uploader");
dojo.experimental("dojox.form.Uploader");
dojo.require("dojox.form.uploader.Base");
dojo.require("dijit.form.Button");
//
// TODO:
// i18n
// label via innerHTML
// Doc and or test what can be extended.
// Doc custom file events
// Use new FileReader() for thumbnails
// flashFieldName should default to Flash
// get('value'); and set warning
//
dojo.declare("dojox.form.Uploader", [dojox.form.uploader.Base], {
//
// Version: 1.6
//
// summary:
// A widget that creates a stylable file-input button, with optional multi-file selection,
// using only HTML elements. Non-HTML5 browsers have fallback options of Flash or an iframe.
//
// description:
// A bare-bones, stylable file-input button, with optional multi-file selection. The list
// of files is not displayed, that is for you to handle by connecting to the onChange
// event, or use the dojox.form.uploader.FileList.
//
// Uploader without plugins does not have any ability to upload - it is for use in forms
// where you handle the upload either by a standard POST or with Ajax using an iFrame. This
// class is for convenience of multiple files only. No progress events are available.
//
// If the browser supports a file-input with the "multiple" attribute, that will be used.
// If the browser does not support "multiple" (ergo, IE) multiple inputs are used,
// one for each selection.
//
//
// uploadOnSelect: Boolean
// If true, uploads imediately after a file has been selected. If false,
// waits for upload() to be called.
uploadOnSelect:false,
// tabIndex: Number|String
// The tab order in the DOM.
tabIndex:0,
// multiple: Boolean
// If true and flash mode, multiple files may be selected from the dialog.
multiple:false,
//
// label: String
// The text used in the button that when clicked, opens a system Browse Dialog.
label:"Upload...",
//
// url: String
// The url targeted for upload. An absolute URL is preferred. Relative URLs are
// changed to absolute.
url:"",
//
// name: String
// The name attribute needs to end with square brackets: [] as this is the standard way
// of handling an attribute "array". This requires a slightly different technique on the
// server.
name:"uploadedfile",
//
// flashFieldName: String
// If set, this will be the name of the field of the flash uploaded files that the server
// is expecting. If not set, "Flash" is appended to the "name" property.
flashFieldName:"",
//
// uploadType: String [readonly]
// The type of uploader being used. As an alternative to determining the upload type on the
// server based on the fieldName, this property could be sent to the server to help
// determine what type of parsing should be used.
uploadType:"form",
//
_nameIndex:0,
widgetsInTemplate:true,
templateString:'<div class="dojoxFileInput"><div dojoType="dijit.form.Button" dojoAttachPoint="button">${label}</div></div>',
postMixInProperties: function(){
this._inputs = [];
this._getButtonStyle(this.srcNodeRef);
this.inherited(arguments);
},
postCreate: function(){
var restore = false;
var parent = this.domNode.parentNode;
var position = this._getNodePosition(this.domNode);
if(!this.btnSize.w || !this.btnSize.h) {
dojo.body().appendChild(this.domNode);
this._getButtonStyle(this.domNode);
restore = true;
}
this._setButtonStyle();
if(restore){
dojo.place(this.domNode, position.node, position.pos)
}
this.inherited(arguments);
},
/*************************
* Public Events *
*************************/
onChange: function(/* Array */fileArray){
// summary:
// stub to connect
// Fires when files are selected
// Event is an array of last files selected
},
onBegin: function(/* Array */dataArray){
// summary:
// Fires when upload begins
},
onProgress: function(/* Object */customEvent){
// summary:
// Stub to connect
// Fires on upload progress. Event is a normalized object of common properties
// from HTML5 uploaders and the Flash uploader. Will not fire for IFrame.
// customEvent:
// bytesLoaded: Number
// Amount of bytes uploaded so far of entire payload (all files)
// bytesTotal: Number
// Amount of bytes of entire payload (all files)
// type: String
// Type of event (progress or load)
// timeStamp: Number
// Timestamp of when event occurred
},
onComplete: function(/* Object */customEvent){
// summary:
// stub to connect
// Fires when all files have uploaded
// Event is an array of all files
this.reset();
},
onCancel: function(){
// summary:
// Stub to connect
// Fires when dialog box has been closed
// without a file selection
},
onAbort: function(){
// summary:
// Stub to connect
// Fires when upload in progress was canceled
},
onError: function(/* Object or String */evtObject){
// summary:
// Fires on errors
//
//FIXME: Unsure of a standard form of error events
},
/*************************
* Public Methods *
*************************/
upload: function(/*Object ? */formData){
// summary:
// When called, begins file upload. Only supported with plugins.
},
submit: function(/* form Node ? */form){
// summary:
// If Uploader is in a form, and other data should be sent along with the files, use
// this instead of form submit. Only supported with plugins.
},
reset: function(){
// summary
// Resets entire input, clearing all files.
// NOTE:
// Removing individual files is not yet supported, because the HTML5 uploaders can't
// be edited.
// TODO:
// Add this ability by effectively, not uploading them
//
this._disconnectButton();
dojo.forEach(this._inputs, dojo.destroy, dojo);
this._inputs = [];
this._nameIndex = 0;
this._createInput();
},
getFileList: function(){
// summary:
// Returns a list of selected files.
//
var fileArray = [];
if(this.supports("multiple")){
dojo.forEach(this.inputNode.files, function(f, i){
fileArray.push({
index:i,
name:f.name,
size:f.size,
type:f.type
});
}, this);
}else{
dojo.forEach(this._inputs, function(n, i){
fileArray.push({
index:i,
name:n.value.substring(n.value.lastIndexOf("\\")+1),
size:0,
type:n.value.substring(n.value.lastIndexOf(".")+1)
});
}, this)
}
return fileArray; // Array
},
/*********************************************
* Private Property. Get off my lawn. *
*********************************************/
_getValueAttr: function(){
// summary:
// Internal. To get disabled use: uploader.get("disabled");
return this.getFileList();
},
_setValueAttr: function(disabled){
console.error("Uploader value is read only");
},
_getDisabledAttr: function(){
// summary:
// Internal. To get disabled use: uploader.get("disabled");
return this._disabled;
},
_setDisabledAttr: function(disabled){
// summary:
// Internal. To set disabled use: uploader.set("disabled", true);
if(this._disabled == disabled){ return; }
this.button.set('disabled', disabled);
dojo.style(this.inputNode, "display", disabled ? "none" : "block");
},
_getNodePosition: function(node){
if(node.previousSibling){
return {
node:node.previousSibling,
pos:"after"
}
}
return {
node:node.nextSibling,
pos:"before"
}
},
_getButtonStyle: function(node){
if(!node){
// we don't want this to happen. But if it does, try and display *something*.
this.btnSize = {
w:200,
h:25
};
}else{
this.btnSize = dojo.marginBox(node);
}
},
_setButtonStyle: function(){
var hasParent = true;
if(!this.domNode.parentNode || !this.domNode.parentNode.tagName){
document.body.appendChild(this.domNode);
hasParent = false;
}
dojo.style(this.domNode, {
width:this.btnSize.w+"px",
height:(this.btnSize.h+4)+"px",
overflow:"hidden",
position:"relative"
});
this.inputNodeFontSize = Math.max(2, Math.max(Math.ceil(this.btnSize.w / 60), Math.ceil(this.btnSize.h / 15)));
this._createInput();
dojo.style(this.button.domNode, {
margin:"0px",
display:"block",
verticalAlign:"top" // IE fix
});
dojo.style(this.button.domNode.firstChild, {
margin:"0px",
display:"block"
//height:this.btnSize.h+"px"
});
if(!hasParent){
document.body.removeChild(this.domNode);
}
},
_createInput: function(){
if(this._inputs.length){
dojo.style(this.inputNode, {
top:"500px"
});
this._disconnectButton();
this._nameIndex++;
}
var name;
if(this.supports("multiple")){
// FF3.5+, WebKit
name = this.name+"s[]";
}else{
// <=IE8
name = this.name + (this.multiple ? this._nameIndex : "");
}
this.inputNode = dojo.create("input", {type:"file", name:name, className:"dojoxInputNode"}, this.domNode, "first");
if(this.supports("multiple") && this.multiple){
dojo.attr(this.inputNode, "multiple", true);
}
this._inputs.push(this.inputNode);
dojo.style(this.inputNode, {
fontSize:this.inputNodeFontSize+"em"
});
var size = dojo.marginBox(this.inputNode);
dojo.style(this.inputNode, {
position:"absolute",
top:"-2px",
left:"-"+(size.w-this.btnSize.w-2)+"px",
opacity:0
});
this._connectButton();
},
_connectButton: function(){
this._cons = [];
var cs = dojo.hitch(this, function(nm){
this._cons.push(dojo.connect(this.inputNode, nm, this, function(evt){
this.button._cssMouseEvent({type:nm})
}));
});
cs("mouseover");
cs("mouseout");
cs("mousedown");
this._cons.push(dojo.connect(this.inputNode, "change", this, function(evt){
this.onChange(this.getFileList(evt));
if(!this.supports("multiple") && this.multiple) this._createInput();
}));
this.button.set('tabIndex', -1);
if(this.tabIndex > -1){
this.inputNode.tabIndex = this.tabIndex;
var restoreBorderStyle = dojo.style(this.button.domNode.firstChild, "border");
this._cons.push(dojo.connect(this.inputNode, "focus", this, function(){
dojo.style(this.button.domNode.firstChild, "border", "1px dashed #ccc");
}));
this._cons.push(dojo.connect(this.inputNode, "blur", this, function(){
dojo.style(this.button.domNode.firstChild, "border", restoreBorderStyle);
}));
}
},
_disconnectButton: function(){
dojo.forEach(this._cons, dojo.disconnect, dojo);
}
});
(function(){
dojox.form.UploaderOrg = dojox.form.Uploader;
var extensions = [dojox.form.UploaderOrg];
dojox.form.addUploaderPlugin = function(plug){
// summary:
// Handle Uploader plugins. When the dojox.form.addUploaderPlugin() function is called,
// the dojox.form.Uploader is recreated using the new plugin (mixin).
//
extensions.push(plug);
dojo.declare("dojox.form.Uploader", extensions, {});
}
})();
}