fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"]
or
fileMask = [
["Jpeg File", "*.jpg;*.jpeg"],
["GIF File", "*.gif"],
["PNG File", "*.png"],
["All Images", "*.jpg;*.jpeg;*.gif;*.png"],
]
NOTE: MacType is not supported, as it does not work very well.
fileMask will work on a Mac, but differently than
Windows.
The url targeted for upload. An absolute URL is preferred. Relative URLs are
changed to absolute.
dojox.form.FileUploader.isDebug
type
Boolean
summary
If true, outputs traces from the SWF to console. What exactly gets passed
is very relative, and depends upon what traces have been left in the DEFT SWF.
dojox.form.FileUploader.devMode
type
Boolean.
summary
Re-implemented. devMode increases the logging, adding style tracing from the SWF.
id: String
The object id, just like any other widget in Dojo. However, this id
is also used as a reference for the SWF
id: "",
dojox.form.FileUploader.baseClass
type
String
summary
The name of the class that will style the button in a "normal" state.
If baseClass is not defined, 'class' will be used.
NOTE: By default the uploader will be styled like a dijit buttons and
adhere to the the themes. Tundra, Soria, and Nihilo are supported.
You can cascade the existing style by using 'class' or 'style'. If you
overwrite baseClass, you should overwrite the remaing state classes
that follow) as well.
dojox.form.FileUploader.hoverClass
type
String
summary
The name of the class that will style the button in a "hover" state. A specific
class should be made to do this. Do not rely on a target like button:hover{...}
dojox.form.FileUploader.activeClass
type
String
summary
The name of the class that will style the button in a "press" state. A specific
class should be made to do this. Do not rely on a target like button:active{...}
dojox.form.FileUploader.disabledClass
type
String
summary
The name of the class that will style the button when its disabled.
dojox.form.FileUploader.force
type
String
summary
Use "flash" to always use Flash (and hopefully force the user to download the plugin
if they don't have it). Use "html" to always use the HTML uploader. An empty string
(default) will check for the right version of Flash and use HTML if not available.
dojox.form.FileUploader.uploaderType
tags: readonly
type
String
summary
Internal. What type of uploader is being used: "flash" or "html"
dojox.form.FileUploader.flashObject
tags: readonly
type
dojox.embed.Flash
summary
The object that creates the SWF embed object. Mostly Internal.
dojox.form.FileUploader.flashMovie
tags: readonly
type
Function
summary
The SWF. Mostly Internal.
dojox.form.FileUploader.insideNode
tags: readonly
type
HTMLNode
summary
The div that holds the SWF and form/fileInput
dojox.form.FileUploader.deferredUploading
type
Number
summary
(1 - X)
(Flash only) throttles the upload to a certain amount of files at a time.
By default, Flash uploads file one at a time to the server, but in parallel.
Firefox will try to queue all files at once, leading to problems. Set this
to the amount to upload in parallel at a time.
Generally, 1 should work fine, but you can experiment with queuing more than
one at a time.
This is of course ignored if selectMultipleFiles equals false.
dojox.form.FileUploader.fileListId
type
String
summary
The id of a dom node to be used as a container for the pending file list.
dojox.form.FileUploader.uploadOnChange
type
Boolean
summary
If true, uploads imediately after a file has been selected. If false,
waits for upload() to be called.
dojox.form.FileUploader.selectMultipleFiles
type
Boolean
summary
If true and flash mode, multiple files may be selected from the dialog.
If html mode, files are not uploaded until upload() is called. The references
to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc.
dojox.form.FileUploader.htmlFieldName
type
String
summary
The name of the field of the fileInput that the server is expecting
dojox.form.FileUploader.flashFieldName
type
String
summary
The name of the field of the flash uploaded files that the server is expecting
dojox.form.FileUploader.fileMask
type
Array
summary
Array[Description, FileTypes], Array[...]...]
(an array, or an array of arrays)
Restrict file selection to certain file types
Empty array defaults to "All Files"
dojox.form.FileUploader.minFlashVersion
type
Number
summary
The minimum of version of Flash player to target. 0 would always install Flash, 100
would never install it. The Flash Player has supported multiple uploads since
version 8, so it could go as low as that safely.
dojox.form.FileUploader.tabIndex
type
Number|String
summary
The tab order in the DOM. Only supported by Flash. HTML Uploaders have security
protection to prevent you from tabbing to the uploader. Stupid.
dojox.form.FileUploader.showProgress
type
Boolean
summary
If true, the button changes to a progress bar during upload.
dojox.form.FileUploader.progressMessage
type
String
summary
The message shown while the button is changed to a progress bar
dojox.form.FileUploader.progressBackgroundUrl
type
String|Uri
summary
The background image to use for the button-progress
dojox.form.FileUploader.progressBackgroundColor
type
String|Number
summary
The background color to use for the button-progress
dojox.form.FileUploader.progressWidgetId
type
String
summary
The widget id of a Dijit Progress bar. The Uploader will bind to it and update it
automatically.
dojox.form.FileUploader.skipServerCheck
type
Boolean
summary
If true, will not verify that the server was sent the correct format.
This can be safely set to true. The purpose of the server side check
is mainly to show the dev if they've implemented the different returns
correctly.
dojox.form.FileUploader.serverTimeout
type
Number
summary
(milliseconds)
The amount of time given to the uploaded file
to wait for a server response. After this amount
of time, the onComplete is fired but with a 'server timeout'
error in the returned item.
Due to the excessive logging necessary to make this code happen,
It's easier to turn it on and off here in one place.
Also helpful if there are multiple uploaders on one page.
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy);
var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null;
summary
Internal.
If a parent widget has an onShow event, it is assumed
that it is hidden and the parsing of the uploader is
delayed until onShow fires. Note that the widget must
fire onShow even if it is defaulted to showing/selected.
this seems to work for Tabs (the primary fix).
if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden;
summary
Internal.
If a parent node is styled as display:none,
returns that node. This node will be temporarilly
changed to display:block. Note if the node is in
a widget that has an onShow event, this is
overridden.
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); }
summary
Internal.
Set up internal dom nodes for button construction.
// summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything.
summary
Stub to connect
Fires as progress returns from SWF
Event is an array of all files uploading
Can be connected to for HTML uploader,
but will not return anything.
// summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with.
summary
Stub - Fired when dojox.embed.Flash has created the
Flash object, but it has not necessarilly finished
downloading, and is ready to be communicated with.
var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); }
summary
Removes a file from the pending file list.
Removes pending data from the Flash movie
and fileInputes from the HTML uploader.
If a file container node is bound, the file
will also be removed.
this._displayProgress(true); var _uploadDone = false; var c = dojo.connect(this, "_complete", function(){ dojo.disconnect(c); _uploadDone = true; }); var w = 0; var interval = setInterval(dojo.hitch(this, function(){ w+=5; if(w>this.fhtml.nr.w){ w = 0; _uploadDone = true; } this._displayProgress(w/this.fhtml.nr.w);
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
Internal only. If there is a file list, adds a file to it.
If you need to use a function such as this, connect to
onChange and update outside of this widget.
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
summary
Internal. Handles tasks after files have finished uploading
Internal. You could use this, but you should use upload() or submit();
which can also handle the post data.
NOTE on deferredUploading:
This is not enabled for HTML. Workaround would be to force
singleFile uploads.
TODO:
Investigate removing fileInputs and resending form
multiple times adding each fileInput
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
if(this._fileInput){ this._disconnect(); // FIXME: // Just hiding it which works, but we lose // reference to it and can't remove it from // the upload list. this._fileInput.id = this._fileInput.id + this.fileCount; dojo.style(this._fileInput, "display", "none"); } this._fileInput = document.createElement('input'); this.fileInputs.push(this._fileInput); // server will need to know this variable: var nm = this.htmlFieldName; var _id = this.id; if(this.selectMultipleFiles){ nm += this.fileCount; _id += this.fileCount; this.fileCount++; }
this.uploadUrl = this.uploadUrl.toString(); if(this.uploadUrl){ if(this.uploadUrl.toLowerCase().indexOf("http")<0 && this.uploadUrl.indexOf("/")!=0){ // Appears to be a relative path. Attempt to // convert it to absolute, so it will better //target the SWF. // var loc = window.location.href.split("/"); loc.pop(); loc = loc.join("/")+"/"; this.uploadUrl = loc+this.uploadUrl; this.log("SWF Fixed - Relative loc:", loc, " abs loc:", this.uploadUrl); }else{ this.log("SWF URL unmodified:", this.uploadUrl) } }else{ console.warn("Warning: no uploadUrl provided."); }
this.connect(this.domNode, "focus", function(){ // TODO: some kind of indicator that the Flash button // is in focus this.flashMovie.focus(); this.flashMovie.doFocus(); }); if(this.tabIndex>=0){ dojo.attr(this.domNode, "tabIndex", this.tabIndex); }
summary
Subscribing to published topics coming from the
Flash uploader.
description
Sacrificing some readbilty for compactness. this.id
will be on the beginning of the topic, so more than
one uploader can be on a page and can have unique calls.
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
_addToFileList: function(){ // summary: // Internal only. If there is a file list, adds a file to it. // If you need to use a function such as this, connect to // onChange and update outside of this widget. // if(this.fileListId){ var str = ''; dojo.forEach(this.fileList, function(d){ // have to use tables because of IE. Grumble. str += '
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
},
_progress: function(dataObject){ // summary: // Internal. Calculate progress var total = 0; var loaded = 0; for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; if(f.name == dataObject.name){ f.bytesLoaded = dataObject.bytesLoaded; f.bytesTotal = dataObject.bytesTotal; f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100); this.log(f.name, "percent:", f.percent) } loaded += Math.ceil(.001 * f.bytesLoaded); total += Math.ceil(.001 * f.bytesTotal); } var percent = Math.ceil(loaded / total * 100); if(this.progressWidgetId){ dijit.byId(this.progressWidgetId).update({progress:percent+"%"}); } if(this.showProgress){ this._displayProgress(percent * .01); } this.onProgress(this.fileList);
}, _getDisabledAttr: function(){ // summary: // Internal. To get disabled use: widget.get("disabled"); return this._disabled; },
_setDisabledAttr: function(disabled){ // summary: // Internal. To set disabled use: widget.set("disabled", true | false); if(this._disabled == disabled){ return; }
_onFlashBlur: function(){ // summary: // Internal. Detects when Flash movies reliquishes focus. // We have to find all the tabIndexes in the doc and figure // out whom to give focus to next. this.flashMovie.blur(); if(!this.nextFocusObject && this.tabIndex){ var nodes = dojo.query("[tabIndex]"); for(var i = 0; i if(nodes[i].tabIndex >= Number(this.tabIndex)+1){ this.nextFocusObject = nodes[i]; break; } } } this.nextFocusObject.focus(); }, _disconnect: function(){ // summary: // Internal. Disconnects fileInput in favor of new one. dojo.forEach(this._cons, dojo.disconnect, dojo); },
/************************* * HTML * *************************/ uploadHTML: function(){ // summary: // Internal. You could use this, but you should use upload() or submit(); // which can also handle the post data. // // NOTE on deferredUploading: // This is not enabled for HTML. Workaround would be to force // singleFile uploads. // TODO: // Investigate removing fileInputs and resending form // multiple times adding each fileInput // if(this.selectMultipleFiles){ dojo.destroy(this._fileInput); } this._setHtmlPostData(); if(this.showProgress){ this._animateProgress(); } var dfd = dojo.io.iframe.send({ url: this.uploadUrl.toString(), form: this._formNode, handleAs: "json", error: dojo.hitch(this, function(err){ this._error("HTML Upload Error:" + err.message); }), load: dojo.hitch(this, function(data, ioArgs, widgetRef){ this._complete(data); }) }); },
createHtmlUploader: function(){ // summary: // Internal. Fires of methods to build HTML Uploader. this._buildForm(); this._setFormStyle(); this._buildFileInput(); this._connectInput(); this._styleContent(); dojo.style(this.insideNode, "visibility", "visible"); this.onReady(); },
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
}, _resetHTML: function(){ // summary: // Internal. After upload, this is called to clear the form and build a new // fileInput. if(this.uploaderType == "html" && this._formNode){ this.fileInputs = []; dojo.query("*", this._formNode).forEach(function(n){ dojo.destroy(n); }); this.fileCount = 0; this._buildFileInput(); this._connectInput(); } }, _buildForm: function(){ // summary: // Build the form that holds the fileInput //
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
_addToFileList: function(){ // summary: // Internal only. If there is a file list, adds a file to it. // If you need to use a function such as this, connect to // onChange and update outside of this widget. // if(this.fileListId){ var str = ''; dojo.forEach(this.fileList, function(d){ // have to use tables because of IE. Grumble. str += '
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
},
_progress: function(dataObject){ // summary: // Internal. Calculate progress var total = 0; var loaded = 0; for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; if(f.name == dataObject.name){ f.bytesLoaded = dataObject.bytesLoaded; f.bytesTotal = dataObject.bytesTotal; f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100); this.log(f.name, "percent:", f.percent) } loaded += Math.ceil(.001 * f.bytesLoaded); total += Math.ceil(.001 * f.bytesTotal); } var percent = Math.ceil(loaded / total * 100); if(this.progressWidgetId){ dijit.byId(this.progressWidgetId).update({progress:percent+"%"}); } if(this.showProgress){ this._displayProgress(percent * .01); } this.onProgress(this.fileList);
}, _getDisabledAttr: function(){ // summary: // Internal. To get disabled use: widget.get("disabled"); return this._disabled; },
_setDisabledAttr: function(disabled){ // summary: // Internal. To set disabled use: widget.set("disabled", true | false); if(this._disabled == disabled){ return; }
_onFlashBlur: function(){ // summary: // Internal. Detects when Flash movies reliquishes focus. // We have to find all the tabIndexes in the doc and figure // out whom to give focus to next. this.flashMovie.blur(); if(!this.nextFocusObject && this.tabIndex){ var nodes = dojo.query("[tabIndex]"); for(var i = 0; i if(nodes[i].tabIndex >= Number(this.tabIndex)+1){ this.nextFocusObject = nodes[i]; break; } } } this.nextFocusObject.focus(); }, _disconnect: function(){ // summary: // Internal. Disconnects fileInput in favor of new one. dojo.forEach(this._cons, dojo.disconnect, dojo); },
/************************* * HTML * *************************/ uploadHTML: function(){ // summary: // Internal. You could use this, but you should use upload() or submit(); // which can also handle the post data. // // NOTE on deferredUploading: // This is not enabled for HTML. Workaround would be to force // singleFile uploads. // TODO: // Investigate removing fileInputs and resending form // multiple times adding each fileInput // if(this.selectMultipleFiles){ dojo.destroy(this._fileInput); } this._setHtmlPostData(); if(this.showProgress){ this._animateProgress(); } var dfd = dojo.io.iframe.send({ url: this.uploadUrl.toString(), form: this._formNode, handleAs: "json", error: dojo.hitch(this, function(err){ this._error("HTML Upload Error:" + err.message); }), load: dojo.hitch(this, function(data, ioArgs, widgetRef){ this._complete(data); }) }); },
createHtmlUploader: function(){ // summary: // Internal. Fires of methods to build HTML Uploader. this._buildForm(); this._setFormStyle(); this._buildFileInput(); this._connectInput(); this._styleContent(); dojo.style(this.insideNode, "visibility", "visible"); this.onReady(); },
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
}, _resetHTML: function(){ // summary: // Internal. After upload, this is called to clear the form and build a new // fileInput. if(this.uploaderType == "html" && this._formNode){ this.fileInputs = []; dojo.query("*", this._formNode).forEach(function(n){ dojo.destroy(n); }); this.fileCount = 0; this._buildFileInput(); this._connectInput(); } }, _buildForm: function(){ // summary: // Build the form that holds the fileInput //
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
_addToFileList: function(){ // summary: // Internal only. If there is a file list, adds a file to it. // If you need to use a function such as this, connect to // onChange and update outside of this widget. // if(this.fileListId){ var str = ''; dojo.forEach(this.fileList, function(d){ // have to use tables because of IE. Grumble. str += '
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
},
_progress: function(dataObject){ // summary: // Internal. Calculate progress var total = 0; var loaded = 0; for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; if(f.name == dataObject.name){ f.bytesLoaded = dataObject.bytesLoaded; f.bytesTotal = dataObject.bytesTotal; f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100); this.log(f.name, "percent:", f.percent) } loaded += Math.ceil(.001 * f.bytesLoaded); total += Math.ceil(.001 * f.bytesTotal); } var percent = Math.ceil(loaded / total * 100); if(this.progressWidgetId){ dijit.byId(this.progressWidgetId).update({progress:percent+"%"}); } if(this.showProgress){ this._displayProgress(percent * .01); } this.onProgress(this.fileList);
}, _getDisabledAttr: function(){ // summary: // Internal. To get disabled use: widget.get("disabled"); return this._disabled; },
_setDisabledAttr: function(disabled){ // summary: // Internal. To set disabled use: widget.set("disabled", true | false); if(this._disabled == disabled){ return; }
_onFlashBlur: function(){ // summary: // Internal. Detects when Flash movies reliquishes focus. // We have to find all the tabIndexes in the doc and figure // out whom to give focus to next. this.flashMovie.blur(); if(!this.nextFocusObject && this.tabIndex){ var nodes = dojo.query("[tabIndex]"); for(var i = 0; i if(nodes[i].tabIndex >= Number(this.tabIndex)+1){ this.nextFocusObject = nodes[i]; break; } } } this.nextFocusObject.focus(); }, _disconnect: function(){ // summary: // Internal. Disconnects fileInput in favor of new one. dojo.forEach(this._cons, dojo.disconnect, dojo); },
/************************* * HTML * *************************/ uploadHTML: function(){ // summary: // Internal. You could use this, but you should use upload() or submit(); // which can also handle the post data. // // NOTE on deferredUploading: // This is not enabled for HTML. Workaround would be to force // singleFile uploads. // TODO: // Investigate removing fileInputs and resending form // multiple times adding each fileInput // if(this.selectMultipleFiles){ dojo.destroy(this._fileInput); } this._setHtmlPostData(); if(this.showProgress){ this._animateProgress(); } var dfd = dojo.io.iframe.send({ url: this.uploadUrl.toString(), form: this._formNode, handleAs: "json", error: dojo.hitch(this, function(err){ this._error("HTML Upload Error:" + err.message); }), load: dojo.hitch(this, function(data, ioArgs, widgetRef){ this._complete(data); }) }); },
createHtmlUploader: function(){ // summary: // Internal. Fires of methods to build HTML Uploader. this._buildForm(); this._setFormStyle(); this._buildFileInput(); this._connectInput(); this._styleContent(); dojo.style(this.insideNode, "visibility", "visible"); this.onReady(); },
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
}, _resetHTML: function(){ // summary: // Internal. After upload, this is called to clear the form and build a new // fileInput. if(this.uploaderType == "html" && this._formNode){ this.fileInputs = []; dojo.query("*", this._formNode).forEach(function(n){ dojo.destroy(n); }); this.fileCount = 0; this._buildFileInput(); this._connectInput(); } }, _buildForm: function(){ // summary: // Build the form that holds the fileInput //
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
_addToFileList: function(){ // summary: // Internal only. If there is a file list, adds a file to it. // If you need to use a function such as this, connect to // onChange and update outside of this widget. // if(this.fileListId){ var str = ''; dojo.forEach(this.fileList, function(d){ // have to use tables because of IE. Grumble. str += '
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
},
_progress: function(dataObject){ // summary: // Internal. Calculate progress var total = 0; var loaded = 0; for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; if(f.name == dataObject.name){ f.bytesLoaded = dataObject.bytesLoaded; f.bytesTotal = dataObject.bytesTotal; f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100); this.log(f.name, "percent:", f.percent) } loaded += Math.ceil(.001 * f.bytesLoaded); total += Math.ceil(.001 * f.bytesTotal); } var percent = Math.ceil(loaded / total * 100); if(this.progressWidgetId){ dijit.byId(this.progressWidgetId).update({progress:percent+"%"}); } if(this.showProgress){ this._displayProgress(percent * .01); } this.onProgress(this.fileList);
}, _getDisabledAttr: function(){ // summary: // Internal. To get disabled use: widget.get("disabled"); return this._disabled; },
_setDisabledAttr: function(disabled){ // summary: // Internal. To set disabled use: widget.set("disabled", true | false); if(this._disabled == disabled){ return; }
_onFlashBlur: function(){ // summary: // Internal. Detects when Flash movies reliquishes focus. // We have to find all the tabIndexes in the doc and figure // out whom to give focus to next. this.flashMovie.blur(); if(!this.nextFocusObject && this.tabIndex){ var nodes = dojo.query("[tabIndex]"); for(var i = 0; i if(nodes[i].tabIndex >= Number(this.tabIndex)+1){ this.nextFocusObject = nodes[i]; break; } } } this.nextFocusObject.focus(); }, _disconnect: function(){ // summary: // Internal. Disconnects fileInput in favor of new one. dojo.forEach(this._cons, dojo.disconnect, dojo); },
/************************* * HTML * *************************/ uploadHTML: function(){ // summary: // Internal. You could use this, but you should use upload() or submit(); // which can also handle the post data. // // NOTE on deferredUploading: // This is not enabled for HTML. Workaround would be to force // singleFile uploads. // TODO: // Investigate removing fileInputs and resending form // multiple times adding each fileInput // if(this.selectMultipleFiles){ dojo.destroy(this._fileInput); } this._setHtmlPostData(); if(this.showProgress){ this._animateProgress(); } var dfd = dojo.io.iframe.send({ url: this.uploadUrl.toString(), form: this._formNode, handleAs: "json", error: dojo.hitch(this, function(err){ this._error("HTML Upload Error:" + err.message); }), load: dojo.hitch(this, function(data, ioArgs, widgetRef){ this._complete(data); }) }); },
createHtmlUploader: function(){ // summary: // Internal. Fires of methods to build HTML Uploader. this._buildForm(); this._setFormStyle(); this._buildFileInput(); this._connectInput(); this._styleContent(); dojo.style(this.insideNode, "visibility", "visible"); this.onReady(); },
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
}, _resetHTML: function(){ // summary: // Internal. After upload, this is called to clear the form and build a new // fileInput. if(this.uploaderType == "html" && this._formNode){ this.fileInputs = []; dojo.query("*", this._formNode).forEach(function(n){ dojo.destroy(n); }); this.fileCount = 0; this._buildFileInput(); this._connectInput(); } }, _buildForm: function(){ // summary: // Build the form that holds the fileInput //
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
_addToFileList: function(){ // summary: // Internal only. If there is a file list, adds a file to it. // If you need to use a function such as this, connect to // onChange and update outside of this widget. // if(this.fileListId){ var str = ''; dojo.forEach(this.fileList, function(d){ // have to use tables because of IE. Grumble. str += '
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
},
_progress: function(dataObject){ // summary: // Internal. Calculate progress var total = 0; var loaded = 0; for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; if(f.name == dataObject.name){ f.bytesLoaded = dataObject.bytesLoaded; f.bytesTotal = dataObject.bytesTotal; f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100); this.log(f.name, "percent:", f.percent) } loaded += Math.ceil(.001 * f.bytesLoaded); total += Math.ceil(.001 * f.bytesTotal); } var percent = Math.ceil(loaded / total * 100); if(this.progressWidgetId){ dijit.byId(this.progressWidgetId).update({progress:percent+"%"}); } if(this.showProgress){ this._displayProgress(percent * .01); } this.onProgress(this.fileList);
}, _getDisabledAttr: function(){ // summary: // Internal. To get disabled use: widget.get("disabled"); return this._disabled; },
_setDisabledAttr: function(disabled){ // summary: // Internal. To set disabled use: widget.set("disabled", true | false); if(this._disabled == disabled){ return; }
_onFlashBlur: function(){ // summary: // Internal. Detects when Flash movies reliquishes focus. // We have to find all the tabIndexes in the doc and figure // out whom to give focus to next. this.flashMovie.blur(); if(!this.nextFocusObject && this.tabIndex){ var nodes = dojo.query("[tabIndex]"); for(var i = 0; i if(nodes[i].tabIndex >= Number(this.tabIndex)+1){ this.nextFocusObject = nodes[i]; break; } } } this.nextFocusObject.focus(); }, _disconnect: function(){ // summary: // Internal. Disconnects fileInput in favor of new one. dojo.forEach(this._cons, dojo.disconnect, dojo); },
/************************* * HTML * *************************/ uploadHTML: function(){ // summary: // Internal. You could use this, but you should use upload() or submit(); // which can also handle the post data. // // NOTE on deferredUploading: // This is not enabled for HTML. Workaround would be to force // singleFile uploads. // TODO: // Investigate removing fileInputs and resending form // multiple times adding each fileInput // if(this.selectMultipleFiles){ dojo.destroy(this._fileInput); } this._setHtmlPostData(); if(this.showProgress){ this._animateProgress(); } var dfd = dojo.io.iframe.send({ url: this.uploadUrl.toString(), form: this._formNode, handleAs: "json", error: dojo.hitch(this, function(err){ this._error("HTML Upload Error:" + err.message); }), load: dojo.hitch(this, function(data, ioArgs, widgetRef){ this._complete(data); }) }); },
createHtmlUploader: function(){ // summary: // Internal. Fires of methods to build HTML Uploader. this._buildForm(); this._setFormStyle(); this._buildFileInput(); this._connectInput(); this._styleContent(); dojo.style(this.insideNode, "visibility", "visible"); this.onReady(); },
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
}, _resetHTML: function(){ // summary: // Internal. After upload, this is called to clear the form and build a new // fileInput. if(this.uploaderType == "html" && this._formNode){ this.fileInputs = []; dojo.query("*", this._formNode).forEach(function(n){ dojo.destroy(n); }); this.fileCount = 0; this._buildFileInput(); this._connectInput(); } }, _buildForm: function(){ // summary: // Build the form that holds the fileInput //
console.warn("DEPRECATED: dojox.form.FileUploader is no longer supported and will be removed in 2.0. Suggested that you use dojox.form.Uploader instead.");
// Usage Notes: // To center text vertically, use vertical-align:middle; // which emulates a boxModel button. Using line-height to center text // can cause height problems in IE6
dojo.declare("dojox.form.FileUploader", [dijit._Widget, dijit._Templated, dijit._Contained], { // version: // 1.5 (deprecated) // summary: // Handles File Uploading to a server (PHP script included for testing) // // FileUploader is now a WIDGET. You do not have to pass a button // in. Passing a button is still supported until version 1.5 to maintain // backwards compatibility, but it is not reccomended. Just create your // uploader like any other widget. // // description: // If the correct version of Flash Player is available (> 9.0) , a SWF // is used. If Flash Player is not installed or is outdated, a typical // html fileInput is used. This process can be overridden with // force:"flash" or force:"html". // // FileUploader works with Flash 10. // // The button styles are now recreated in Flash, so there is no longer // using an invisible Flash movie with wmode=transparent. This way the Flash button // is actually placed inline with the DOM, not floating above it and constantly // resetting its position. The "Windows Firefox clickable bug" should be fixed (and // hopefully some Linux problems). // // The HTML button is created in a new way and it is now inline as is the // FLash button. Styling is much easier and more versatile. // // Dependencies: // FileUploader no longer uses FileInput.css. It now uses FileUploader.css // See requires for JavaScript dependencies. // // NEW FEATURES - // There are a ton of features and fixes in this version. // Disabled: Can be toggled with widget.attr("disable", true|false) // Submit: A convenience method has been added for if the uploader is in a form. // Instead of submitting the form, call uploader.submit(theForm), and the // Uploader will handle all of the form values and post the data. // Selected List: If passing the ID of a container, the Uploaders will populate it // with the selected files. // Deleting Files: You can now delete pending files. // Progress Built in: showProgress:true will change the button to a progress // bar on upload. // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress // widget. If the Progress widget is initially hidden, it will change to // visible and then restored after upload. // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due // to browser limtations) // Deferred Uploading: (Flash only) throttles the upload to one file at a time // // // CDN USERS - // FileUpload now works with the CDN but with limitations. The SWF must // be from the same domain as the HTML page. 'swfPath' has been exposed // so that you may link to that file (could of course be the same SWF in // dojox resource folder). The SWF will *NOT* work from the // CDN server. This would require a special XML file that would allow // access to your server, and the logistics to that is impossible. // // LIMITATIONS // - This is not designed to be a part of a form, it contains its own. (See submit()) // - Currently does not in a Dialog box or a Tab where it is not initially visible, // - The default style inherits font sizes - but a parent container should have a font size // set somewhere of the results could be inconsistent. // // OPERA USERS - // It works better than the 1.3 version. fileInputs apperantly can't have opacity // set to zero. The Flash uploader works but files are auto-uploaded. Must be a // flashVar problem. // // Safari Bug note: // The bug is in the way Safari handles the connection: // https://bugs.webkit.org/show_bug.cgi?id=5760 // I added this to the virtual host in the Apache conf file, and now it // works like a charm: // BrowserMatch Safari nokeepalive // swfPath: dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/fileuploader.swf"),
templateString:'
',
// uploadUrl: String // The url targeted for upload. An absolute URL is preferred. Relative URLs are // changed to absolute. uploadUrl: "", // // isDebug: Boolean // If true, outputs traces from the SWF to console. What exactly gets passed // is very relative, and depends upon what traces have been left in the DEFT SWF. isDebug:false, // // devMode: Boolean. // Re-implemented. devMode increases the logging, adding style tracing from the SWF. devMode:false, // // id: String // The object id, just like any other widget in Dojo. However, this id // is also used as a reference for the SWF // id: "", // // baseClass: String // The name of the class that will style the button in a "normal" state. // If baseClass is not defined, 'class' will be used. // NOTE: By default the uploader will be styled like a dijit buttons and // adhere to the the themes. Tundra, Soria, and Nihilo are supported. // You can cascade the existing style by using 'class' or 'style'. If you // overwrite baseClass, you should overwrite the remaing state classes // that follow) as well. baseClass:"dojoxUploaderNorm", // // hoverClass: String // The name of the class that will style the button in a "hover" state. A specific // class should be made to do this. Do not rely on a target like button:hover{...} hoverClass:"dojoxUploaderHover", // // activeClass: String // The name of the class that will style the button in a "press" state. A specific // class should be made to do this. Do not rely on a target like button:active{...} activeClass:"dojoxUploaderActive", // // disabledClass: String // The name of the class that will style the button when its disabled. disabledClass:"dojoxUploaderDisabled", // // force: String // Use "flash" to always use Flash (and hopefully force the user to download the plugin // if they don't have it). Use "html" to always use the HTML uploader. An empty string // (default) will check for the right version of Flash and use HTML if not available. force:"", // // uploaderType: [readonly] String // Internal. What type of uploader is being used: "flash" or "html" uploaderType:"", // // flashObject: [readonly] dojox.embed.Flash // The object that creates the SWF embed object. Mostly Internal. flashObject: null, // // flashMovie: [readonly] Function // The SWF. Mostly Internal. flashMovie: null, // // insideNode: [readonly] HTMLNode // The div that holds the SWF and form/fileInput insideNode: null, // // deferredUploading: Number (1 - X) // (Flash only) throttles the upload to a certain amount of files at a time. // By default, Flash uploads file one at a time to the server, but in parallel. // Firefox will try to queue all files at once, leading to problems. Set this // to the amount to upload in parallel at a time. // Generally, 1 should work fine, but you can experiment with queuing more than // one at a time. // This is of course ignored if selectMultipleFiles equals false. deferredUploading:1, // // fileListId: String // The id of a dom node to be used as a container for the pending file list. fileListId:"", // // uploadOnChange: Boolean // If true, uploads imediately after a file has been selected. If false, // waits for upload() to be called. uploadOnChange: false, // // selectMultipleFiles: Boolean // If true and flash mode, multiple files may be selected from the dialog. // If html mode, files are not uploaded until upload() is called. The references // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc. selectMultipleFiles: true, // // htmlFieldName: String // The name of the field of the fileInput that the server is expecting htmlFieldName:"uploadedfile", // // flashFieldName: String // The name of the field of the flash uploaded files that the server is expecting flashFieldName:"flashUploadFiles", // // fileMask: Array[ Array[Description, FileTypes], Array[...]...] // (an array, or an array of arrays) // Restrict file selection to certain file types // Empty array defaults to "All Files" // example: // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"] // or // fileMask = [ // ["Jpeg File", "*.jpg;*.jpeg"], // ["GIF File", "*.gif"], // ["PNG File", "*.png"], // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"], // ] // NOTE: MacType is not supported, as it does not work very well. // fileMask will work on a Mac, but differently than // Windows. fileMask: null, // // minFlashVersion: Number // The minimum of version of Flash player to target. 0 would always install Flash, 100 // would never install it. The Flash Player has supported multiple uploads since // version 8, so it could go as low as that safely. minFlashVersion:9, // // tabIndex: Number|String // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security // protection to prevent you from tabbing to the uploader. Stupid. tabIndex:-1, // // showProgress: Boolean // If true, the button changes to a progress bar during upload. showProgress:false, // // progressMessage: String // The message shown while the button is changed to a progress bar progressMessage:"Loading", // // progressBackgroundUrl: String|Uri // The background image to use for the button-progress progressBackgroundUrl:dojo.moduleUrl("dijit", "themes/tundra/images/buttonActive.png"), // // progressBackgroundColor: String|Number // The background color to use for the button-progress progressBackgroundColor:"#ededed", // // progressWidgetId:String // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it // automatically. progressWidgetId:"", // // skipServerCheck: Boolean // If true, will not verify that the server was sent the correct format. // This can be safely set to true. The purpose of the server side check // is mainly to show the dev if they've implemented the different returns // correctly. skipServerCheck:false, // // serverTimeout:Number (milliseconds) // The amount of time given to the uploaded file // to wait for a server response. After this amount // of time, the onComplete is fired but with a 'server timeout' // error in the returned item. serverTimeout: 5000,
log: function(){ // summary: // Due to the excessive logging necessary to make this code happen, // It's easier to turn it on and off here in one place. // Also helpful if there are multiple uploaders on one page. if(this.isDebug){ console["log"](Array.prototype.slice.call(arguments).join(" ")); } },
if(this.fileListId){ this.connect(dojo.byId(this.fileListId), "click", function(evt){ var p = evt.target.parentNode.parentNode.parentNode; // in a table if(p.id && p.id.indexOf("file_")>-1){ this.removeFile(p.id.split("file_")[1]); } }); }
// cleaning up solves memory leak issues in the HTML version dojo.addOnUnload(this, this.destroy); },
getHiddenWidget: function(){ // summary: // Internal. // If a parent widget has an onShow event, it is assumed // that it is hidden and the parsing of the uploader is // delayed until onShow fires. Note that the widget must // fire onShow even if it is defaulted to showing/selected. // this seems to work for Tabs (the primary fix). // var node = this.domNode.parentNode; while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id && dijit.byId(id).onShow){ return dijit.byId(id); } node = node.parentNode; } return null; },
getHiddenNode: function(/*DomNode*/ node){ // summary: // Internal. // If a parent node is styled as display:none, // returns that node. This node will be temporarilly // changed to display:block. Note if the node is in // a widget that has an onShow event, this is // overridden. // if(!node){ return null; } var hidden = null; var p = node.parentNode; while(p && p.tagName.toLowerCase() != "body"){ var d = dojo.style(p, "display"); if(d == "none"){ hidden = p; break; } p = p.parentNode; } return hidden; },
getButtonStyle: function(){ // summary: // Internal. // Get necessary style information from srcRefNode and // assigned styles //
// TODO: // To call this from postCreate.... // could do the style stuff initially, but if hidden they will be bad sizes // could then redo the sizes // alt is to create a genuine button and copy THAT instead of how doing now
try{ this.insideNode.innerHTML = this.fhtml.cn; }catch(e){ // You have got to be kidding me. IE does us he favor of checking that // we aren't inserting the improper type of content with innerHTML into // an inline element. Alert us with an "Unknown Runtime Error". You can't // MAKE this stuff up. // if(this.uploaderType == "flash"){ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); dojo.body().appendChild(this.insideNode); this.insideNode.innerHTML = this.fhtml.cn; var c = dojo.connect(this, "onReady", this, function(){ dojo.disconnect(c); this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode); this.domNode.appendChild(this.insideNode); }); }else{ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn)); } } if(this._hiddenNode){ dojo.style(this._hiddenNode, "display", "none"); } },
/************************* * Public Events * *************************/
// The following events are inherited from _Widget and still may be connected: // onClick // onMouseUp // onMouseDown // onMouseOver // onMouseOut
onChange: function(dataArray){ // summary: // stub to connect // Fires when files are selected // Event is an array of last files selected },
onProgress: function(dataArray){ // summary: // Stub to connect // Fires as progress returns from SWF // Event is an array of all files uploading // Can be connected to for HTML uploader, // but will not return anything. },
onComplete: function(dataArray){ // summary: // stub to connect // Fires when all files have uploaded // Event is an array of all files },
onCancel: function(){ // summary: // Stub to connect // Fires when dialog box has been closed // without a file selection },
onError: function(/* Object or String */evtObject){ // summary: // Fires on errors // //FIXME: Unsure of a standard form for receiving errors },
onReady: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - Fired when dojox.embed.Flash has created the // Flash object, but it has not necessarilly finished // downloading, and is ready to be communicated with. },
onLoad: function(/* dojox.form.FileUploader */ uploader){ // summary: // Stub - SWF has been downloaded 100%. },
/************************* * Public Methods * *************************/ submit: function(/* form node ? */form){ // summary: // If FileUploader is in a form, and other data should be sent // along with the files, use this instead of form submit. // var data = form ? dojo.formToObject(form) : null; this.upload(data); return false; // Boolean }, upload: function(/*Object ? */data){ // summary: // When called, begins file upload // data: Object // postData to be sent to server // if(!this.fileList.length){ return false; } if(!this.uploadUrl){ console.warn("uploadUrl not provided. Aborting."); return false; } if(!this.showProgress){ this.set("disabled", true); }
for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; f.bytesLoaded = 0; f.bytesTotal = f.size || 100000; f.percent = 0; } if(this.uploaderType == "flash"){ this.uploadFlash(); }else{ this.uploadHTML(); } // prevent form submit return false; }, removeFile: function(/*String*/name, /*Boolean*/noListEdit){ // summary: // Removes a file from the pending file list. // Removes pending data from the Flash movie // and fileInputes from the HTML uploader. // If a file container node is bound, the file // will also be removed. // name:String // The name of the file to be removed. Typically the file name, // such as: picture01.png // noListEdit:Boolean // Internal. If true don't remove files from list. // var i; for(i = 0; i < this.fileList.length; i++){ if(this.fileList[i].name == name){ if(!noListEdit){ // if onComplete, don't do this this.fileList.splice(i,1); } break; } } if(this.uploaderType == "flash"){ this.flashMovie.removeFile(name); }else if(!noListEdit){ dojo.destroy(this.fileInputs[i]); this.fileInputs.splice(i,1); this._renumberInputs(); } if(this.fileListId){ dojo.destroy("file_"+name); } },
_addToFileList: function(){ // summary: // Internal only. If there is a file list, adds a file to it. // If you need to use a function such as this, connect to // onChange and update outside of this widget. // if(this.fileListId){ var str = ''; dojo.forEach(this.fileList, function(d){ // have to use tables because of IE. Grumble. str += '
// Yes. Yes I do have to do three loops here. ugh. // // Check if one of the files had an error dojo.forEach(dataArray, function(f){ if(f.ERROR){ this._error(f.ERROR); } }, this);
// Have to be set them all too 100%, because // onProgress does not always fire dojo.forEach(this.fileList, function(f){ f.bytesLoaded = 1; f.bytesTotal = 1; f.percent = 100; this._progress(f); }, this); // we're done. remove files. dojo.forEach(this.fileList, function(f){ this.removeFile(f.name, true); }, this);
if(this.restoreProgDisplay){ // using timeout so prog shows on screen for at least a short time setTimeout(dojo.hitch(this, function(){ dojo.style(dijit.byId(this.progressWidgetId).domNode, this.restoreProgDisplay == "none" ? "display" : "visibility", this.restoreProgDisplay ); }), 500); }
},
_progress: function(dataObject){ // summary: // Internal. Calculate progress var total = 0; var loaded = 0; for (var i = 0; i < this.fileList.length; i++){ var f = this.fileList[i]; if(f.name == dataObject.name){ f.bytesLoaded = dataObject.bytesLoaded; f.bytesTotal = dataObject.bytesTotal; f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100); this.log(f.name, "percent:", f.percent) } loaded += Math.ceil(.001 * f.bytesLoaded); total += Math.ceil(.001 * f.bytesTotal); } var percent = Math.ceil(loaded / total * 100); if(this.progressWidgetId){ dijit.byId(this.progressWidgetId).update({progress:percent+"%"}); } if(this.showProgress){ this._displayProgress(percent * .01); } this.onProgress(this.fileList);
}, _getDisabledAttr: function(){ // summary: // Internal. To get disabled use: widget.get("disabled"); return this._disabled; },
_setDisabledAttr: function(disabled){ // summary: // Internal. To set disabled use: widget.set("disabled", true | false); if(this._disabled == disabled){ return; }
_onFlashBlur: function(){ // summary: // Internal. Detects when Flash movies reliquishes focus. // We have to find all the tabIndexes in the doc and figure // out whom to give focus to next. this.flashMovie.blur(); if(!this.nextFocusObject && this.tabIndex){ var nodes = dojo.query("[tabIndex]"); for(var i = 0; i if(nodes[i].tabIndex >= Number(this.tabIndex)+1){ this.nextFocusObject = nodes[i]; break; } } } this.nextFocusObject.focus(); }, _disconnect: function(){ // summary: // Internal. Disconnects fileInput in favor of new one. dojo.forEach(this._cons, dojo.disconnect, dojo); },
/************************* * HTML * *************************/ uploadHTML: function(){ // summary: // Internal. You could use this, but you should use upload() or submit(); // which can also handle the post data. // // NOTE on deferredUploading: // This is not enabled for HTML. Workaround would be to force // singleFile uploads. // TODO: // Investigate removing fileInputs and resending form // multiple times adding each fileInput // if(this.selectMultipleFiles){ dojo.destroy(this._fileInput); } this._setHtmlPostData(); if(this.showProgress){ this._animateProgress(); } var dfd = dojo.io.iframe.send({ url: this.uploadUrl.toString(), form: this._formNode, handleAs: "json", error: dojo.hitch(this, function(err){ this._error("HTML Upload Error:" + err.message); }), load: dojo.hitch(this, function(data, ioArgs, widgetRef){ this._complete(data); }) }); },
createHtmlUploader: function(){ // summary: // Internal. Fires of methods to build HTML Uploader. this._buildForm(); this._setFormStyle(); this._buildFileInput(); this._connectInput(); this._styleContent(); dojo.style(this.insideNode, "visibility", "visible"); this.onReady(); },
try{ dojo.style(this.insideNode, "lineHeight", "inherit"); }catch(e){ // There are certain cases where IE refuses to set lineHeight. // For the life of me I cannot figure out the combination of // styles that IE doesn't like. Steaming... Pile... }
}, _resetHTML: function(){ // summary: // Internal. After upload, this is called to clear the form and build a new // fileInput. if(this.uploaderType == "html" && this._formNode){ this.fileInputs = []; dojo.query("*", this._formNode).forEach(function(n){ dojo.destroy(n); }); this.fileCount = 0; this._buildFileInput(); this._connectInput(); } }, _buildForm: function(){ // summary: // Build the form that holds the fileInput //