<commit_before>dojo.provide("dojox.form.FileUploader");
dojo.experimental("dojox.form.FileUploader");
var swfPath = dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/uploader.swf");

dojo.require("dojox.embed.Flash");
dojo.require("dojo.io.iframe");
dojo.require("dojox.html.styles");

dojo.declare("dojox.form.FileUploader", null, {
	// summary: 
	// 		Handles File Uploading to a server (PHP script included for testing)
	//		Does *NOT* create a button, it transforms a button into an uploader. 
	//		This can be used for toolbar buttons for example.
	//
	// 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 now works with Flash 10, but it comes with consequences.
	//		Instead of calling to open the browse dialog with script, we HAVE to
	//		click a Flash button. Therefore, we are floating a SWF over the 'fake'
	//		button just like we do with the fileInput. As a result, the Flash 
	//		uploader will have the same CSS problems as the fileInput.
	//
	//	NEW FEATURES - 
	//		You can now pass in POST data that will be posted to the server along
	//		with the Flash uploaded files. Also, you can now specify the field name
	//		that the server expects the files to be in.
	//
	//	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 -
	//		Because of the nature of this "hack" - floating a zero-opacity fileInput
	//		over a "fake" button - this won't work in all circumstances. For instance
	//		you couldn't put a fileInput in a scrolling div. Some complicated CSS can 
	//		mess up the placement - or for that matter, some simple, but not expected
	//		CSS can mess up the placement. Being near the botton of a complex document
	//		can throw off the positioning. The positioning methods have been exposed
	//		for over-writing in these cases.
	//
	//	OPERA USERS -
	//		Not much love from Opera on FileInput hacks. Should still work with 
	//		the Flash 10 hack though.
	//
	//	ALSO - 
	//		Only works programmatically. Does not work in markup. Use the other
	//		other FileInput files for markup solutions.
	//
	//	example:
	//		|	var f1 = new dojox.form.FileUploader({
	//		|		id:"upload_1",
	//		|		devMode:false,
	//		|		isDebug:false,
	//		|		button:dijit.byId("btn1"), 
	//		|		uploadUrl:"www.absolutelUrl.com/upload.php", 
	//		|		uploadOnChange:true
	//		|	});
	//		|	dojo.connect(f1, "onChange", "handleChange");
	//		|	dojo.connect(f1, "onComplete", "onComplete");
	//
	// arguments:
	//
	// degradable: REMOVED
	//
	//	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.
	//		If true, gives a red overlay to the Flash button and the HTML fileInput button's
	//		opcaity is set to 1.0. Since this code uses some crazy CSS to get the uploaders 
	//		to hover over the 'fake' button, there is no garuantee that it will work in all 
	//		cases. Set this param to true to see if the button is properly positioned.
	//		Methods may be called over over-written to help in this case.
	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:"",
	//
	//	uploadUrl: String
	// 		REQUIRED: The Url to where the file will be uploaded
	uploadUrl: "",
	//
	//	button: dijit.form.Button or a domNode
	// 		REQUIRED: The button that when clicked, launches the upload dialog
	button: null,
	//
	//	uploadOnChange: Boolean
	//		If true, uploads imeediately 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: [],
	//
	//	force: String
	//			options:
	//				"flash" forces Flash Uploader
	//				"html" forces HTML fileInput
	//				"" checks availability of the proper Flash player
	force:"",
	//
	//	postData: Object
	//		FLASH ONLY - In HTML, append the vars to the uploadUrl
	//		Sends data via POST to the server along with the uploaded
	//		files.
	//	NEW:
	//		You can also pass postData in the upload method
	//		which can be different with each upload
	postData:null,
	//
	//	swfPath: String
	// 		optional: pass in a path to your own SWF file uploader. defaults to the one in dojox.
	//		CDN USERS NOTE: For the Flash Uploader to work via CDN, the SWF must be from the 
	//		same server as the HTML page. Pass the link to that file here.
	swfPath: swfPath,
	//
	//	minFlashVersion: Number
	//		Internal. Version of Flash Player to check for. Thi may be over-written
	//		for testing.
	minFlashVersion: 9,
	//
	//	uploaderType: String
	//		Internal.
	uploaderType:"",
	//
	//	flashObject: dojox.embed.Flash 
	//		The object that creates the SWF embed object. Mostly Internal.
	flashObject: null,
	//
	//	flashMovie: Function
	//		The SWF. Mostly Internal.
	flashMovie: null,
	//
	//	flashDiv: HTMLNode
	//		The div that holds the SWF. While mostly internal, ccould be accessed 
	//		for advanced positioning.
	flashDiv: null,
	//
	//	domNode: HTMLNode
	//either flash div or fileInput, depending on type
	domNode:null, 
	
	constructor: function(options){
		// summary:
		//		Calling init function instead of doing operations in 
		//		constructor, to allow for patches and over-writes.
		//
		this.init(options);
	},
	
	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.apply(console, arguments);
		}
	},
	
	init: function(options){
		//	summary:
		//		Determine which uploader to use and initialize it.
		//
		dojo.mixin(this, options);
		//this.isDebug = true;
		console.info("isdebug:", this.isDebug, options.isDebug, this.id)
		this.id = this.id || dijit.getUniqueId("uploader");
		dijit.registry.add(this);
		this.log("init Flash:", (dojox.embed.Flash.available >= this.minFlashVersion || this.force=="flash"), dojox.embed.Flash.available >= this.minFlashVersion, this.force=="flash")
		
		this.fileList = [];
		this._subs = [];
		this._cons = [];
		
		if((dojox.embed.Flash.available >= this.minFlashVersion || this.force=="flash") && this.force!="html"){
			this.uploaderType = "flash";
			this.createFlashUploader();
		}else{
			this.uploaderType = "html";
			
			this.fileInputs = [];
			this.fileCount = 0;
			
			if (dojo.isIE && dojo.isIE<7) {
				// if we are create more than one FileInputOverlay,
				// IE6 needs a breather or it locks up
				setTimeout(dojo.hitch(this, "createHtmlUploader"), 1);
			}
			else {
				this.createHtmlUploader();
			}
		}
	},
	
	onMouseDown: function(evt){
		// summary:
		//		Fired when upload button is down
		//		Stub to which user can connect
	},
	
	onMouseUp: function(evt){
		// summary:
		//		Fired when upload button is up
		//		Stub to which user can connect
	},
	
	onMouseOver: function(evt){
		// summary:
		//		Fired when upload button is over
		// 		Can be connected to for manipulating hover state
		if (this.button.domNode) {
			dojo.addClass(this.button.domNode, "dijitButtonHover dijitHover");
		}
	},
	
	onMouseOut: function(evt){
		// summary:
		//		Fired when upload button is off
		// Can be connected to for manipulating hover state
		if (this.button.domNode) {
			dojo.removeClass(this.button.domNode, "dijitButtonHover dijitHover");
		}
	},
	/*onClick: function(){
		// summary:
		//		Fired when upload button is up
		//		Stub to which user can connect
	},*/
	
	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
		this.log("Upload Canceled")
	},
	
	onError: function(evtObject){
		console.warn("FLASH/ERROR " + evtObject.type.toUpperCase() + ":", evtObject);
	},
	
	upload: function(/*Object ? */data){
		// summary:
		// 		When called, begins file upload
		//	data: Object
		//		postData to be sent to server
		if(data){
			this.postData = data;
		}
		this.log("upload type:", this.uploaderType, " - postData:", this.postData);
		
		if (this.uploaderType == "flash") {
			try{
				this.flashMovie.doUpload(this.postData);	
			}catch(err){
				throw new Error("Sorry, the SWF failed to initialize properly. The page will have to be refreshed. ERROR:" + err)
			}
			
		}else{
			//this.log("POST FORM")
			//this.log("FORM:", this._formNode)
			//this.log("FILE:")
			dojo.io.iframe.send({
				url: this.uploadUrl,
				form: this._formNode,
				handleAs: "json",
				handle: dojo.hitch(this, function(data, ioArgs, widgetRef){
					this._complete([data]);
					//this._complete(this.selectMultipleFiles ? data : [data]);
				})
			});
		}
	},
	
	setPosition: function(){
		//	summary:
		//		Positions the upload button over the 'fake' button.
		//		This method is called on init, and may be called 
		//		for various other reasons, for example, when the browser 
		//		window is resized. Also, this code detects if the 
		//		upload button is within a Dijit Dialog, and calls
		//		this method when the Dialog is dragged. Whenever the 
		//		DOM has been redrawn, you should call this method.
		if (this.uploaderType == "flash") {
			this.setFlashPosition();
		}else{
			this.setHtmlPosition();
		}
	},

	hide: function(){
		//	summary:
		//		Hides the upload button. This is called
		//		when within a dialog.
		dojo.style(this.domNode, "display", "none");
	},
	
	show: function(){
		//	summary:
		//		Shows the upload button. This is called
		//		when within a dialog.
		dojo.style(this.domNode, "display", "");
	},
	
	disable: function(/*Boolean*/disabled){
		// summary:
		//	This method is connected to the "fake" dijit
		//	button, and hides and shows on the disabling.
		//	If the "fake" button is a dom node, this method
		//	would need to be called directly.
		if(disabled){
			this.hide();
		}else{
			this.show();
		}
	},
	destroyAll: function(){
		//	summary:
		// 		Destroys everything including 'fake' button
		if (this.button.destroy) {
			this.button.destroy();
		}else{
			dojo.destroy(this.button);
		}
		this.destroy();
	},
	
	destroy: function(){
		//	summary:
		//		Destroys flash
		//		TODO: This doesn't look complete. HTML?
		if (this.uploaderType == "flash" && !this.flashMovie) {
			this._cons.push(dojo.connect(this, "onLoad", this, "destroy"));
			return;
		}
		dojo.forEach(this._subs, function(s){
			dojo.unsubscribe(s);
		});
		dojo.forEach(this._cons, function(c){
			dojo.disconnect(c);
		});
		
		if (this.uploaderType == "flash") {
			this.flashObject.destroy();
			dojo.destroy(this.flashDiv);
		}
	},
	
	
	
	
	createFlashUploader: function(){
		//	summary
		//		Create embedded SWF
		this.log("FLASH")
		var uurl = this.uploadUrl.toLowerCase();
		if(uurl.indexOf("http")<0 && uurl.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.log("Fix Relative url:", this.uploadUrl);
			this.uploadUrl = loc+this.uploadUrl;
			//this.log("SWF Fixed - Relative loc:", loc, " abs loc:", this.uploadUrl);
		}else{
			//this.log("SWF did not fix upload URL");
		}
		
		
		var dim = this.getFakeButtonSize();
		
		// the size of the embedded SWF, not it's containing DIV 
		var w = "100%";
		var h = "100%";
		var args = {
			path: this.swfPath.uri || this.swfPath,
			width: w,
			height: h,
				allowScriptAccess:"always",
				allowNetworking:"all",
			// only pass in simple variables - no deep objects
			vars: {
				uploadDataFieldName: this.flashFieldName,
				uploadUrl: this.uploadUrl,
				uploadOnSelect: this.uploadOnChange,
				selectMultipleFiles: this.selectMultipleFiles,
				id: this.id,
				//width:w, ///   width and height mess up the embed query string. very strange.
				//height:h,
				isDebug: this.isDebug,
				devMode:this.devMode
			},
			params: {
				wmode:"transparent"
			}
		};
		if(args.vars.isDebug && window.console && window.console.dir){
			
			window.passthrough = function(){
				console.log.apply(console, arguments);
			}
			window.passthrough("Flash trace enabled.")
		}else{
			window.passthrough = function(){}
		}
		//this.log("ARG VARS:", args.vars)
		this.flashDiv = dojo.doc.createElement("div");
		this.domNode = this.flashDiv;
		dojo.body().appendChild(this.flashDiv);
		
		this._connectFlash();
		
		// Flash 10 BUG
		// Must set the position before creating the embed object
		//	or it will get created twice - seems okay after
		this.setPosition();
		
		this.flashObject = new dojox.embed.Flash(args, this.flashDiv);
		this.flashObject.onLoad = dojo.hitch(this, function(mov){
			this.log("ONLOAD", mov)
			this.flashMovie = mov;
			this.setFlashVars();
		});
		
		
	},
	
	setFlashVars: function(){
		
		this.flashMovie.setFileMask(this.fileMask);
		this.flashMovie.setPostData(this.postData);
		console.log("setFlashVars / postData --------> ", this.postData);
		return;
		try{	
			this.flashMovie.setFileMask(this.fileMask);
			if(this.postData){
				this.flashMovie.setPostData(this.postData);
			}
		}catch(e){
			if(this.setvarTries===undefined) this.setvarTries = 0;
			this.setvarTries++<commit_msg>Added onError if Flash doesn't install.<commit_after>dojo.provide("dojox.form.FileUploader");
dojo.experimental("dojox.form.FileUploader");
var swfPath = dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/uploader.swf");

dojo.require("dojox.embed.Flash");
dojo.require("dojo.io.iframe");
dojo.require("dojox.html.styles");

dojo.declare("dojox.form.FileUploader", null, {
	// summary: 
	// 		Handles File Uploading to a server (PHP script included for testing)
	//		Does *NOT* create a button, it transforms a button into an uploader. 
	//		This can be used for toolbar buttons for example.
	//
	// 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 now works with Flash 10, but it comes with consequences.
	//		Instead of calling to open the browse dialog with script, we HAVE to
	//		click a Flash button. Therefore, we are floating a SWF over the 'fake'
	//		button just like we do with the fileInput. As a result, the Flash 
	//		uploader will have the same CSS problems as the fileInput.
	//
	//	NEW FEATURES - 
	//		You can now pass in POST data that will be posted to the server along
	//		with the Flash uploaded files. Also, you can now specify the field name
	//		that the server expects the files to be in.
	//
	//	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 -
	//		Because of the nature of this "hack" - floating a zero-opacity fileInput
	//		over a "fake" button - this won't work in all circumstances. For instance
	//		you couldn't put a fileInput in a scrolling div. Some complicated CSS can 
	//		mess up the placement - or for that matter, some simple, but not expected
	//		CSS can mess up the placement. Being near the botton of a complex document
	//		can throw off the positioning. The positioning methods have been exposed
	//		for over-writing in these cases.
	//
	//	OPERA USERS -
	//		Not much love from Opera on FileInput hacks. Should still work with 
	//		the Flash 10 hack though.
	//
	//	ALSO - 
	//		Only works programmatically. Does not work in markup. Use the other
	//		other FileInput files for markup solutions.
	//
	//	example:
	//		|	var f1 = new dojox.form.FileUploader({
	//		|		id:"upload_1",
	//		|		devMode:false,
	//		|		isDebug:false,
	//		|		button:dijit.byId("btn1"), 
	//		|		uploadUrl:"www.absolutelUrl.com/upload.php", 
	//		|		uploadOnChange:true
	//		|	});
	//		|	dojo.connect(f1, "onChange", "handleChange");
	//		|	dojo.connect(f1, "onComplete", "onComplete");
	//
	// arguments:
	//
	// degradable: REMOVED
	//
	//	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.
	//		If true, gives a red overlay to the Flash button and the HTML fileInput button's
	//		opcaity is set to 1.0. Since this code uses some crazy CSS to get the uploaders 
	//		to hover over the 'fake' button, there is no garuantee that it will work in all 
	//		cases. Set this param to true to see if the button is properly positioned.
	//		Methods may be called over over-written to help in this case.
	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:"",
	//
	//	uploadUrl: String
	// 		REQUIRED: The Url to where the file will be uploaded
	uploadUrl: "",
	//
	//	button: dijit.form.Button or a domNode
	// 		REQUIRED: The button that when clicked, launches the upload dialog
	button: null,
	//
	//	uploadOnChange: Boolean
	//		If true, uploads imeediately 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: [],
	//
	//	force: String
	//			options:
	//				"flash" forces Flash Uploader
	//				"html" forces HTML fileInput
	//				"" checks availability of the proper Flash player
	force:"",
	//
	//	postData: Object
	//		FLASH ONLY - In HTML, append the vars to the uploadUrl
	//		Sends data via POST to the server along with the uploaded
	//		files.
	//	NEW:
	//		You can also pass postData in the upload method
	//		which can be different with each upload
	postData:null,
	//
	//	swfPath: String
	// 		optional: pass in a path to your own SWF file uploader. defaults to the one in dojox.
	//		CDN USERS NOTE: For the Flash Uploader to work via CDN, the SWF must be from the 
	//		same server as the HTML page. Pass the link to that file here.
	swfPath: swfPath,
	//
	//	minFlashVersion: Number
	//		Internal. Version of Flash Player to check for. Thi may be over-written
	//		for testing.
	minFlashVersion: 9,
	//
	//	uploaderType: String
	//		Internal.
	uploaderType:"",
	//
	//	flashObject: dojox.embed.Flash 
	//		The object that creates the SWF embed object. Mostly Internal.
	flashObject: null,
	//
	//	flashMovie: Function
	//		The SWF. Mostly Internal.
	flashMovie: null,
	//
	//	flashDiv: HTMLNode
	//		The div that holds the SWF. While mostly internal, ccould be accessed 
	//		for advanced positioning.
	flashDiv: null,
	//
	//	domNode: HTMLNode
	//either flash div or fileInput, depending on type
	domNode:null, 
	
	constructor: function(options){
		// summary:
		//		Calling init function instead of doing operations in 
		//		constructor, to allow for patches and over-writes.
		//
		this.init(options);
	},
	
	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.apply(console, arguments);
		}
	},
	
	init: function(options){
		//	summary:
		//		Determine which uploader to use and initialize it.
		//
		dojo.mixin(this, options);
		//this.isDebug = true;
		console.info("isdebug:", this.isDebug, options.isDebug, this.id)
		this.id = this.id || dijit.getUniqueId("uploader");
		dijit.registry.add(this);
		this.log("init Flash:", (dojox.embed.Flash.available >= this.minFlashVersion || this.force=="flash"), dojox.embed.Flash.available >= this.minFlashVersion, this.force=="flash")
		
		this.fileList = [];
		this._subs = [];
		this._cons = [];
		
		if((dojox.embed.Flash.available >= this.minFlashVersion || this.force=="flash") && this.force!="html"){
			this.uploaderType = "flash";
			this.createFlashUploader();
		}else{
			this.uploaderType = "html";
			
			this.fileInputs = [];
			this.fileCount = 0;
			
			if (dojo.isIE && dojo.isIE<7) {
				// if we are create more than one FileInputOverlay,
				// IE6 needs a breather or it locks up
				setTimeout(dojo.hitch(this, "createHtmlUploader"), 1);
			}
			else {
				this.createHtmlUploader();
			}
		}
	},
	
	onMouseDown: function(evt){
		// summary:
		//		Fired when upload button is down
		//		Stub to which user can connect
	},
	
	onMouseUp: function(evt){
		// summary:
		//		Fired when upload button is up
		//		Stub to which user can connect
	},
	
	onMouseOver: function(evt){
		// summary:
		//		Fired when upload button is over
		// 		Can be connected to for manipulating hover state
		if (this.button.domNode) {
			dojo.addClass(this.button.domNode, "dijitButtonHover dijitHover");
		}
	},
	
	onMouseOut: function(evt){
		// summary:
		//		Fired when upload button is off
		// Can be connected to for manipulating hover state
		if (this.button.domNode) {
			dojo.removeClass(this.button.domNode, "dijitButtonHover dijitHover");
		}
	},
	/*onClick: function(){
		// summary:
		//		Fired when upload button is up
		//		Stub to which user can connect
	},*/
	
	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
		this.log("Upload Canceled")
	},
	
	onError: function(evtObject){
		console.warn("FLASH/ERROR " + evtObject.type.toUpperCase() + ":", evtObject);
	},
	
	upload: function(/*Object ? */data){
		// summary:
		// 		When called, begins file upload
		//	data: Object
		//		postData to be sent to server
		if(data){
			this.postData = data;
		}
		this.log("upload type:", this.uploaderType, " - postData:", this.postData);
		
		if (this.uploaderType == "flash") {
			try{
				this.flashMovie.doUpload(this.postData);	
			}catch(err){
				throw new Error("Sorry, the SWF failed to initialize properly. The page will have to be refreshed. ERROR:" + err)
			}
			
		}else{
			//this.log("POST FORM")
			//this.log("FORM:", this._formNode)
			//this.log("FILE:")
			dojo.io.iframe.send({
				url: this.uploadUrl,
				form: this._formNode,
				handleAs: "json",
				handle: dojo.hitch(this, function(data, ioArgs, widgetRef){
					this._complete([data]);
					//this._complete(this.selectMultipleFiles ? data : [data]);
				})
			});
		}
	},
	
	setPosition: function(){
		//	summary:
		//		Positions the upload button over the 'fake' button.
		//		This method is called on init, and may be called 
		//		for various other reasons, for example, when the browser 
		//		window is resized. Also, this code detects if the 
		//		upload button is within a Dijit Dialog, and calls
		//		this method when the Dialog is dragged. Whenever the 
		//		DOM has been redrawn, you should call this method.
		if (this.uploaderType == "flash") {
			this.setFlashPosition();
		}else{
			this.setHtmlPosition();
		}
	},

	hide: function(){
		//	summary:
		//		Hides the upload button. This is called
		//		when within a dialog.
		dojo.style(this.domNode, "display", "none");
	},
	
	show: function(){
		//	summary:
		//		Shows the upload button. This is called
		//		when within a dialog.
		dojo.style(this.domNode, "display", "");
	},
	
	disable: function(/*Boolean*/disabled){
		// summary:
		//	This method is connected to the "fake" dijit
		//	button, and hides and shows on the disabling.
		//	If the "fake" button is a dom node, this method
		//	would need to be called directly.
		if(disabled){
			this.hide();
		}else{
			this.show();
		}
	},
	destroyAll: function(){
		//	summary:
		// 		Destroys everything including 'fake' button
		if (this.button.destroy) {
			this.button.destroy();
		}else{
			dojo.destroy(this.button);
		}
		this.destroy();
	},
	
	destroy: function(){
		//	summary:
		//		Destroys flash
		//		TODO: This doesn't look complete. HTML?
		if (this.uploaderType == "flash" && !this.flashMovie) {
			this._cons.push(dojo.connect(this, "onLoad", this, "destroy"));
			return;
		}
		dojo.forEach(this._subs, function(s){
			dojo.unsubscribe(s);
		});
		dojo.forEach(this._cons, function(c){
			dojo.disconnect(c);
		});
		
		if (this.uploaderType == "flash") {
			this.flashObject.destroy();
			dojo.destroy(this.flashDiv);
		}
	},
	
	
	
	
	createFlashUploader: function(){
		//	summary
		//		Create embedded SWF
		this.log("FLASH")
		var uurl = this.uploadUrl.toLowerCase();
		if(uurl.indexOf("http")<0 && uurl.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.log("Fix Relative url:", this.uploadUrl);
			this.uploadUrl = loc+this.uploadUrl;
			//this.log("SWF Fixed - Relative loc:", loc, " abs loc:", this.uploadUrl);
		}else{
			//this.log("SWF did not fix upload URL");
		}
		
		
		var dim = this.getFakeButtonSize();
		
		// the size of the embedded SWF, not it's containing DIV 
		var w = "100%";
		var h = "100%";
		var args = {
			expressInstall:true,
			path: this.swfPath.uri || this.swfPath,
			width: w,
			height: h,
				allowScriptAccess:"always",
				allowNetworking:"all",
			// only pass in simple variables - no deep objects
			vars: {
				uploadDataFieldName: this.flashFieldName,
				uploadUrl: this.uploadUrl,
				uploadOnSelect: this.uploadOnChange,
				selectMultipleFiles: this.selectMultipleFiles,
				id: this.id,
				//width:w, ///   width and height mess up the embed query string. very strange.
				//height:h,
				isDebug: this.isDebug,
				devMode:this.devMode
			},
			params: {
				wmode:"transparent"
			}
		};
		if(args.vars.isDebug && window.console && window.console.dir){
			
			window.passthrough = function(){
				console.log.apply(console, arguments);
			}
			window.passthrough("Flash trace enabled.")
		}else{
			window.passthrough = function(){}
		}
		//this.log("ARG VARS:", args.vars)
		this.flashDiv = dojo.doc.createElement("div");
		this.domNode = this.flashDiv;
		dojo.body().appendChild(this.flashDiv);
		
		this._connectFlash();
		
		// Flash 10 BUG
		// Must set the position before creating the embed object
		//	or it will get created twice - seems okay after
		this.setPosition();
		
		this.flashObject = new dojox.embed.Flash(args, this.flashDiv);
		this.flashObject.onError = function(msg){
			console.warn("Flash Error:", msg);
		}
		this.flashObject.onLoad = dojo.hitch(this, function(mov){
			this.log("ONLOAD", mov)
			this.flashMovie = mov;
			this.setFlashVars();
		});
		
		
	},
	
	setFlashVars: function(){
		
		this.flashMovie.setFileMask(this.fileMask);
		this.flashMovie.setPostData(this.postData);
		console.log("setFlashVars / postData --------> ", this.postData);
		return;
		try{	
			this.flashMovie.setFileMask(this.fileMask);
			if(this.postData){
				this.flashMovie.setPostData(this.postData);
			}
		}catch(e){
			if(this.setvarTries===undefined) this.setvarTries = 0;
			this.setvarTries++
{'fraction_non_alphanumeric': 0.12900236467054388, 'fraction_numerical': 0.0020451204703777082, 'mean_word_length': 2.8370524767042666, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2930350', 'n_tokens_mistral': 11703, 'n_tokens_neox': 10500, 'n_words': 3358}