1. #1
    Sencha User loeppky's Avatar
    Join Date
    May 2007
    Location
    Seattle, WA
    Posts
    230
    Vote Rating
    0
    loeppky is on a distinguished road

      0  

    Default Ext.ux.form.BrowseButton

    Ext.ux.form.BrowseButton


    Note: this extension is no longer supported (by me) because the Ext team have provided their own File Upload field (see http://extjs.com/deploy/dev/examples...le-upload.html). As a result, you'll either need to read the most recent posts where people have posted updated code to support newer browsers and Ext versions or switch to using the Ext provided control.

    I have put work into fixing Ext 3.x's Ext.ux.form.FileUploadField. See http://www.extjs.com/forum/showthread.php?p=402903. It also contains updated code.


    I needed the ability for a user to click an Ext button and for a file browse window to appear. jsakalos has done this in his Ext.ux.UploadForm and MaximGB has done it in his Ext.ux.UploadDialog extension. I preferred MaximGB's implementation because of the slick BrowseButton class he had created to encapsulate the logic. It also maintained all of the original Ext.Button look and feel (e.g. tooltips, hovering). I have taken his original design and improved upon it in the following ways:
    • Doesn't interfere with adjacent buttons.
    • Added a debug mode to easily see how well the overlain input file "Browse" button is being placed.
    • Commented it.

    Updates:
    • 3/11/08 - Fully compatible with both IE6 and IE 7. MaximGB came up with the idea of having a floating div that would follow the mouse cursor, effectively always keeping the input file "Browse" button under the cursor. I have worked from his initial implementation, and the output is great. Try the sample application below with "debug : true" to see how well it's working.
    • 3/12/08 - Removed the destroy method because it had a bug and was unnecessary. The parent class (Ext.Button) destroy method is sufficient to remove the added elements and listeners.
    • 3/12/08 - Updated browser compatibility as I was able to test it on a Mac. There are no issues with Safari 3, and the Firefox 2 cursor issue is same as on Windows.
    • 3/13/08 - Updated browser compatibility as I was able to test on Linux. Also, tested things on Opera. Started keeping a list of known issues at the bottom of the post. Also stated the license (public domain).
    • 3/14/08 - Added tab support for selecting the BrowseButton.
    • 6/5/08 - Fixed a few outstanding issues including the leaking of <em> elements (post #16), clicking browse button in IE not working sometimes (post #24), and transparent mask can be very small (post #30)
    • 6/23/08 - Fixed issues where the browse button looses clicks in IE 6 and 7 as reported in post 57 and 58.
    • 8/24/09 - Added notice that this extension is no longer supported (see beginning of post).

    Code:
    Ext.namespace('Ext.ux.form');
    
    /**
     * @class Ext.ux.form.BrowseButton
     * @extends Ext.Button
     * Ext.Button that provides a customizable file browse button.
     * Clicking this button, pops up a file dialog box for a user to select the file to upload.
     * This is accomplished by having a transparent <input type="file"> box above the Ext.Button.
     * When a user thinks he or she is clicking the Ext.Button, they're actually clicking the hidden input "Browse..." box.
     * Note: this class can be instantiated explicitly or with xtypes anywhere a regular Ext.Button can be except in 2 scenarios:
     * - Panel.addButton method both as an instantiated object or as an xtype config object.
     * - Panel.buttons config object as an xtype config object.
     * These scenarios fail because Ext explicitly creates an Ext.Button in these cases.
     * Browser compatibility:
     * Internet Explorer 6:
     * - no issues
     * Internet Explorer 7:
     * - no issues
     * Firefox 2 - Windows:
     * - pointer cursor doesn't display when hovering over the button.
     * Safari 3 - Windows:
     * - no issues.
     * @author loeppky - based on the work done by MaximGB in Ext.ux.UploadDialog (http://extjs.com/forum/showthread.php?t=21558)
     * The follow the curosr float div idea also came from MaximGB.
     * @see http://extjs.com/forum/showthread.php?t=29032
     * @constructor
     * Create a new BrowseButton.
     * @param {Object} config Configuration options
     */
    Ext.ux.form.BrowseButton = Ext.extend(Ext.Button, {
    	/*
    	 * Config options:
    	 */
    	/**
    	 * @cfg {String} inputFileName
    	 * Name to use for the hidden input file DOM element.  Deaults to "file".
    	 */
    	inputFileName: 'file',
    	/**
    	 * @cfg {Boolean} debug
    	 * Toggle for turning on debug mode.
    	 * Debug mode doesn't make clipEl transparent so that one can see how effectively it covers the Ext.Button.
    	 * In addition, clipEl is given a green background and floatEl a red background to see how well they are positioned.
    	 */
    	debug: false,
    	
    	
    	/*
    	 * Private constants:
    	 */
    	/**
    	 * @property FLOAT_EL_WIDTH
    	 * @type Number
    	 * The width (in pixels) of floatEl.
    	 * It should be less than the width of the IE "Browse" button's width (65 pixels), since IE doesn't let you resize it.
    	 * We define this width so we can quickly center floatEl at the mouse cursor without having to make any function calls.
    	 * @private
    	 */
    	FLOAT_EL_WIDTH: 60,
    	
    	/**
    	 * @property FLOAT_EL_HEIGHT
    	 * @type Number
    	 * The heigh (in pixels) of floatEl.
    	 * It should be less than the height of the "Browse" button's height.
    	 * We define this height so we can quickly center floatEl at the mouse cursor without having to make any function calls.
    	 * @private
    	 */
    	FLOAT_EL_HEIGHT: 18,
    	
    	
    	/*
    	 * Private properties:
    	 */
    	/**
    	 * @property buttonCt
    	 * @type Ext.Element
    	 * Element that contains the actual Button DOM element.
    	 * We store a reference to it, so we can easily grab its size for sizing the clipEl.
    	 * @private
    	 */
    	buttonCt: null,
    	/**
    	 * @property clipEl
    	 * @type Ext.Element
    	 * Element that contains the floatEl.
    	 * This element is positioned to fill the area of Ext.Button and has overflow turned off.
    	 * This keeps floadEl tight to the Ext.Button, and prevents it from masking surrounding elements.
    	 * @private
    	 */
    	clipEl: null,
    	/**
    	 * @property floatEl
    	 * @type Ext.Element
    	 * Element that contains the inputFileEl.
    	 * This element is size to be less than or equal to the size of the input file "Browse" button.
    	 * It is then positioned wherever the user moves the cursor, so that their click always clicks the input file "Browse" button.
    	 * Overflow is turned off to preven inputFileEl from masking surrounding elements.
    	 * @private
    	 */
    	floatEl: null,
    	/**
    	 * @property inputFileEl
    	 * @type Ext.Element
    	 * Element for the hiden file input.
    	 * @private
    	 */
    	inputFileEl: null,
    	/**
    	 * @property originalHandler
    	 * @type Function
    	 * The handler originally defined for the Ext.Button during construction using the "handler" config option.
    	 * We need to null out the "handler" property so that it is only called when a file is selected.
    	 * @private
    	 */
    	originalHandler: null,
    	/**
    	 * @property originalScope
    	 * @type Object
    	 * The scope originally defined for the Ext.Button during construction using the "scope" config option.
    	 * While the "scope" property doesn't need to be nulled, to be consistent with originalHandler, we do.
    	 * @private
    	 */
    	originalScope: null,
    	
    	
    	/*
    	 * Protected Ext.Button overrides
    	 */
    	/**
    	 * @see Ext.Button.initComponent
    	 */
    	initComponent: function(){
    		Ext.ux.form.BrowseButton.superclass.initComponent.call(this);
    		// Store references to the original handler and scope before nulling them.
    		// This is done so that this class can control when the handler is called.
    		// There are some cases where the hidden file input browse button doesn't completely cover the Ext.Button.
    		// The handler shouldn't be called in these cases.  It should only be called if a new file is selected on the file system.  
    		this.originalHandler = this.handler;
    		this.originalScope = this.scope;
    		this.handler = null;
    		this.scope = null;
    	},
    	
    	/**
    	 * @see Ext.Button.onRender
    	 */
    	onRender: function(ct, position){
    		Ext.ux.form.BrowseButton.superclass.onRender.call(this, ct, position); // render the Ext.Button
    		this.buttonCt = this.el.child('.x-btn-center em');
    		this.buttonCt.position('relative'); // this is important!
    		var styleCfg = {
    			position: 'absolute',
    			overflow: 'hidden',
    			top: '0px', // default
    			left: '0px' // default
    		};
    		// browser specifics for better overlay tightness
    		if (Ext.isIE) {
    			Ext.apply(styleCfg, {
    				left: '-3px',
    				top: '-3px'
    			});
    		} else if (Ext.isGecko) {
    			Ext.apply(styleCfg, {
    				left: '-3px',
    				top: '-3px'
    			});
    		} else if (Ext.isSafari) {
    			Ext.apply(styleCfg, {
    				left: '-4px',
    				top: '-2px'
    			});
    		}
    		this.clipEl = this.buttonCt.createChild({
    			tag: 'div',
    			style: styleCfg
    		});
    		this.setClipSize();
    		this.clipEl.on({
    			'mousemove': this.onButtonMouseMove,
    			'mouseover': this.onButtonMouseMove,
    			scope: this
    		});
    		
    		this.floatEl = this.clipEl.createChild({
    			tag: 'div',
    			style: {
    				position: 'absolute',
    				width: this.FLOAT_EL_WIDTH + 'px',
    				height: this.FLOAT_EL_HEIGHT + 'px',
    				overflow: 'hidden'
    			}
    		});
    		
    		
    		if (this.debug) {
    			this.clipEl.applyStyles({
    				'background-color': 'green'
    			});
    			this.floatEl.applyStyles({
    				'background-color': 'red'
    			});
    		} else {
    			// We don't set the clipEl to be transparent, because IE 6/7 occassionaly looses mouse events for transparent elements.
    			// We have listeners on the clipEl that can't be lost as they're needed for realligning the input file element.
    			this.floatEl.setOpacity(0.0);
    		}
    		
    		// Cover cases where someone tabs to the button:
    		// Listen to focus of the button so we can translate the focus to the input file el.
    		var buttonEl = this.el.child(this.buttonSelector);
    		buttonEl.on('focus', this.onButtonFocus, this);
    		// In IE, it's possible to tab to the text portion of the input file el.  
    		// We want to listen to keyevents so that if a space is pressed, we "click" the input file el.
    		if (Ext.isIE) {
    			this.el.on('keydown', this.onButtonKeyDown, this);
    		}
    		
    		this.createInputFile();
    	},
    	
    	
    	/*
    	 * Private helper methods:
    	 */
    	/**
    	 * Sets the size of clipEl so that is covering as much of the button as possible.
    	 * @private
    	 */
    	setClipSize: function(){
    		if (this.clipEl) {
    			var width = this.buttonCt.getWidth();
    			var height = this.buttonCt.getHeight();
    			// The button container can have a width and height of zero when it's rendered in a hidden panel.
    			// This is most noticable when using a card layout, as the items are all rendered but hidden,
    			// (unless deferredRender is set to true). 
    			// In this case, the clip size can't be determined, so we attempt to set it later.
    			// This check repeats until the button container has a size. 
    			if (width === 0 || height === 0) {
    				this.setClipSize.defer(100, this);
    			} else {
    				if (Ext.isIE) {
    					width = width + 5;
    					height = height + 5;
    				} else if (Ext.isGecko) {
    					width = width + 6;
    					height = height + 6;
    				} else if (Ext.isSafari) {
    					width = width + 6;
    					height = height + 6;
    				}
    				this.clipEl.setSize(width, height);
    			}
    		}
    	},
    	
    	/**
    	 * Creates the input file element and adds it to inputFileCt.
    	 * The created input file elementis sized, positioned, and styled appropriately.
    	 * Event handlers for the element are set up, and a tooltip is applied if defined in the original config.
    	 * @private
    	 */
    	createInputFile: function(){
    		// When an input file gets detached and set as the child of a different DOM element,
    		// straggling <em> elements get left behind.  
    		// I don't know why this happens but we delete any <em> elements we can find under the floatEl to prevent a memory leak.
    		this.floatEl.select('em').each(function(el){
    			el.remove();
    		});
    		this.inputFileEl = this.floatEl.createChild({
    			tag: 'input',
    			type: 'file',
    			size: 1, // must be > 0. It's value doesn't really matter due to our masking div (inputFileCt).  
    			name: this.inputFileName || Ext.id(this.el),
    			tabindex: this.tabIndex,
    			// Use the same pointer as an Ext.Button would use.  This doesn't work in Firefox.
    			// This positioning right-aligns the input file to ensure that the "Browse" button is visible.
    			style: {
    				position: 'absolute',
    				cursor: 'pointer',
    				right: '0px',
    				top: '0px'
    			}
    		});
    		this.inputFileEl = this.inputFileEl.child('input') || this.inputFileEl;
    		
    		// setup events
    		this.inputFileEl.on({
    			'click': this.onInputFileClick,
    			'change': this.onInputFileChange,
    			'focus': this.onInputFileFocus,
    			'select': this.onInputFileFocus,
    			'blur': this.onInputFileBlur,
    			scope: this
    		});
    		
    		// add a tooltip
    		if (this.tooltip) {
    			if (typeof this.tooltip == 'object') {
    				Ext.QuickTips.register(Ext.apply({
    					target: this.inputFileEl
    				}, this.tooltip));
    			} else {
    				this.inputFileEl.dom[this.tooltipType] = this.tooltip;
    			}
    		}
    	},
    	
    	/**
    	 * Redirecting focus to the input file element so the user can press space and select files.
    	 * @param {Event} e focus event.
    	 * @private
    	 */
    	onButtonFocus: function(e){
    		if (this.inputFileEl) {
    			this.inputFileEl.focus();
    			e.stopEvent();
    		}
    	},
    	
    	/**
    	 * Handler for the IE case where once can tab to the text box of an input file el.
    	 * If the key is a space, we simply "click" the inputFileEl.
    	 * @param {Event} e key event.
    	 * @private
    	 */
    	onButtonKeyDown: function(e){
    		if (this.inputFileEl && e.getKey() == Ext.EventObject.SPACE) {
    			this.inputFileEl.dom.click();
    			e.stopEvent();
    		}
    	},
    	
    	/**
    	 * Handler when the cursor moves over the clipEl.
    	 * The floatEl gets centered to the cursor location.
    	 * @param {Event} e mouse event.
    	 * @private
    	 */
    	onButtonMouseMove: function(e){
    		var xy = e.getXY();
    		xy[0] -= this.FLOAT_EL_WIDTH / 2;
    		xy[1] -= this.FLOAT_EL_HEIGHT / 2;
    		this.floatEl.setXY(xy);
    	},
    	
    	/**
    	 * Add the visual enhancement to the button when the input file recieves focus. 
    	 * This is the tip for the user that now he/she can press space to select the file.
    	 * @private
    	 */
    	onInputFileFocus: function(e){
    		if (!this.isDisabled) {
    			this.el.addClass("x-btn-over");
    		}
    	},
    	
    	/**
    	 * Removes the visual enhancement from the button.
    	 * @private
    	 */
    	onInputFileBlur: function(e){
    		this.el.removeClass("x-btn-over");
    	},
    	
    	/**
    	 * Handler when inputFileEl's "Browse..." button is clicked.
    	 * @param {Event} e click event.
    	 * @private
    	 */
    	onInputFileClick: function(e){
    		e.stopPropagation();
    	},
    	
    	/**
    	 * Handler when inputFileEl changes value (i.e. a new file is selected).
    	 * @private
    	 */
    	onInputFileChange: function(){
    		if (this.originalHandler) {
    			this.originalHandler.call(this.originalScope, this);
    		}
    	},
    	
    	
    	/*
    	 * Public methods:
    	 */
    	/**
    	 * Detaches the input file associated with this BrowseButton so that it can be used for other purposed (e.g. uplaoding).
    	 * The returned input file has all listeners and tooltips applied to it by this class removed.
    	 * @param {Boolean} whether to create a new input file element for this BrowseButton after detaching.
    	 * True will prevent creation.  Defaults to false.
    	 * @return {Ext.Element} the detached input file element.
    	 */
    	detachInputFile: function(noCreate){
    		var result = this.inputFileEl;
    		
    		if (typeof this.tooltip == 'object') {
    			Ext.QuickTips.unregister(this.inputFileEl);
    		} else {
    			this.inputFileEl.dom[this.tooltipType] = null;
    		}
    		this.inputFileEl.removeAllListeners();
    		this.inputFileEl = null;
    		
    		if (!noCreate) {
    			this.createInputFile();
    		}
    		return result;
    	},
    	
    	/**
    	 * @return {Ext.Element} the input file element attached to this BrowseButton.
    	 */
    	getInputFile: function(){
    		return this.inputFileEl;
    	},
    	
    	/**
    	 * @see Ext.Button.disable
    	 */
    	disable: function(){
    		Ext.ux.form.BrowseButton.superclass.disable.call(this);
    		this.inputFileEl.dom.disabled = true;
    	},
    	
    	/**
    	 * @see Ext.Button.enable
    	 */
    	enable: function(){
    		Ext.ux.form.BrowseButton.superclass.enable.call(this);
    		this.inputFileEl.dom.disabled = false;
    	}
    });
    
    Ext.reg('browsebutton', Ext.ux.form.BrowseButton);
    License: public domain (i.e. use it however you like without any restrictions).

    Ext compatibility:
    This class can be instantiated explicitly or with xtypes anywhere a regular Ext.Button can be except in 2 scenarios:
    1. Panel.addButton method both as an instantiated object or as an xtype config object.
    2. Panel.buttons config object as an xtype config object.
    These scenarios fail because Ext explicitly creates an Ext.Button in these cases. It works fine in a panel's tbar with instantiation or xtype, panel's items instantiation or xtype, or panel's buttons with instantiation.

    Browser compatibility:
    Internet Explorer 6:
    • No issues
    Internet Explorer 7
    • No issues
    Firefox 2 (Mac/Windows/Linux):
    • Pointer cursor doesn't display when hovering over the button.
    Firefox 3 (Mac/Windows/Linux):
    • Pointer cursor doesn't display when hovering over the button.
    Safari 3 - (Mac/Windows)
    • No issues
    Opera - (Mac/Windows/Linux)
    • Only works with explicitly instantiated buttons for a panel. Doesn't work in the tbar or items.

    Known issues:
    • Reverse-tabbing (shift+tab) doesn't work once one has tabbed to the BrowseButon. One has to tab twice to get past the BrowseButton.

  2. #2
    Sencha User loeppky's Avatar
    Join Date
    May 2007
    Location
    Seattle, WA
    Posts
    230
    Vote Rating
    0
    loeppky is on a distinguished road

      0  

    Default Ext.ux.form.BrowseButton sample

    Ext.ux.form.BrowseButton sample


    Here’s a sample of Ext.ux.form.BrowseButton in action: http://loeppky.com/steven/code/samples/BrowseButton/

    ScreenshotPanel class that uses Ext.ux.form.BrowseButton for selecting a screenshot, and then creates a form to upload it. This class highlights the different ways Ext.ux.form.BrowseButton can be used.

    Updates:
    • 3/12/08 - Added a link to a sample of this code online. ScreenshotsPanel now also lists the files that were selected for upload (although the upload itself fails due to having nothing implemented on the back end).
    • 3/13/08 - Corrected the titles of the buttons for the demo.
    • 6/6/08 - Made a few formatting changes. Updated to use Ext 2.1.
    Code:
    /**
     * @class Ext.ux.ScreenshotPanel
     * @extends Ext.Panel
     * Renders a browse button for demonstration purposes.
     * @constructor
     * @param {Object} config The config object
     */
    Ext.ux.ScreenshotsPanel = Ext.extend(Ext.Panel, {
    	/*
    	 * Config options
    	 */
    	/**
    	 * For whether to draw the panel (and it's BrowseButtons) in debug mode.
    	 * @type Boolean
    	 */
    	debug: false,
    	
    	
    	/*
    	 * Private properties
    	 */
    	/**
    	 * Panel for displaying the files that have selected for upload.
    	 * @type Ext.Panel
    	 */
    	filePanel: null,
    	/**
    	 * Form for uploading screenshot images.
    	 * Is only instantiated if a screenshot is selected to upload.
    	 * @type Ext.form.BasicForm
    	 */
    	addScreenshotForm: null,
    	
    	
    	/*
    	 * Protected methods
    	 */
    	/**
    	 * @see Ext.Panel.initConfiguration
    	 */
    	initComponent: function(){
    		var browseButtonBaseConfig = {
    			xtype: 'browsebutton',
    			handler: this.onAddScreenshot,
    			scope: this,
    			tooltip: 'Click to upload a new screenshot.',
    			inputFileName: 'screenshot',
    			debug: this.debug // set to true to see the "Browse" overlay
    		};
    		this.filePanel = new Ext.Panel({
    			frame: true,
    			title: 'selected files',
    			buttonAlign: 'center',
    			buttons: [{
    				text: 'Upload (does not work and will fail)',
    				handler: this.uploadScreenshots,
    				scope: this
    			}]
    		});
    		Ext.apply(this, {
    			tbar: [
    				new Ext.ux.form.BrowseButton(Ext.apply({
    					text: 'tbar - explicit'
    				}, browseButtonBaseConfig)), 
    				Ext.apply({
    					text: 'tbar - xtype'
    				}, browseButtonBaseConfig)
    			],
    			items: [
    				new Ext.ux.form.BrowseButton(Ext.apply({
    					text: 'items - explicit'
    				}, browseButtonBaseConfig)), 
    				Ext.apply({
    					text: 'items - xtype'
    				}, browseButtonBaseConfig), 
    				this.filePanel
    			],
    			buttons: [
    				new Ext.ux.form.BrowseButton(Ext.apply({
    					text: 'buttons - explicit'
    				}, browseButtonBaseConfig)), 
    				Ext.apply({
    					text: 'buttons - xtype'
    				}, browseButtonBaseConfig) // doesn't work correctly as Ext uses the config object to instaniate an Ext.Button
    			]
    		});
    		Ext.ux.ScreenshotsPanel.superclass.initComponent.call(this);
    	},
    	
    	
    	/*
    	 * Private methods
    	 */
    	/**
    	 * Handler for the add screenshot button.
    	 * @param {Ext.ux.form.BrowseButton} browseButton The browse button where "Add Screenshot" was clicked.
    	 * @private
    	 */
    	onAddScreenshot: function(browseButton){
    		if (!this.addScreenshotForm) { // if the form hasn't been created
    			var addScreenshotFormEl = this.filePanel.body.createChild({
    				tag: 'form',
    				style: 'display:none'
    			});
    			this.addScreenshotForm = new Ext.form.BasicForm(addScreenshotFormEl, {
    				url: '/AddScreenshot',
    				fileUpload: true
    			});
    		}
    		var inputFileEl = browseButton.detachInputFile();
    		inputFileEl.appendTo(this.addScreenshotForm.getEl());
    		this.filePanel.body.createChild({
    			tag: 'div',
    			html: inputFileEl.dom.value
    		});
    	},
    	
    	/**
    	 * Handler for the upload screenshots button
    	 */
    	uploadScreenshots: function(){
    		this.addScreenshotForm.submit({
    			params: {
    				extraParam1: 'value1'
    			},
    			success: this.onAddScreenshotSuccess,
    			failure: this.onAddScreenshotFailure,
    			scope: this,
    			waitTitle: 'Uploading Screenshot',
    			waitMsg: 'Your screenshot is being uploaded...'
    		});
    	},
    	
    	/**
    	 * Callback for when a screenshot has been successfully added.
    	 * @param {Ext.form.BasicForm} form the form for which the uploading occurred.
    	 * @param {Ext.form.Action} action the action of the form submit
    	 * @private
    	 */
    	onAddScreenshotSuccess: function(form, action){
    		// remove the file input element so that it doesn't get uploaded again with the next screenshot
    		var inputFileEl = this.addScreenshotForm.getEl().child('input');
    		inputFileEl.remove();
    		Ext.Msg.show({
    			title: 'Screenshot Upload Success',
    			msg: 'Your screenshot was successfully uploaded.',
    			buttons: Ext.Msg.OK,
    			minWidth: 300
    		});
    	},
    	
    	/**
    	 * Callback for when a screenshot has not been successfully added.
    	 * @param {Ext.form.BasicForm} form the form for which the uploading occurred.
    	 * @param {Ext.form.Action} action the action of the form submit
    	 * @private
    	 */
    	onAddScreenshotFailure: function(form, action){
    		// remove the file input element so that it doesn't get uploaded again with the next screenshot
    		var inputFileEl = this.addScreenshotForm.getEl().child('input');
    		inputFileEl.remove();
    		var errorMessageTemplate = new Ext.XTemplate('<p>Your screenshot was not uploaded.  The server reported the following errors:</p>', '<tpl for="errors">', '<p>- {.}</p>', '</tpl>');
    		Ext.Msg.show({
    			title: 'Screenshot Upload Failed',
    			msg: errorMessageTemplate.applyTemplate(action.result),
    			buttons: Ext.Msg.OK,
    			minWidth: 300
    		});
    	}
    });
    Index.html file for setting everything up. Note: you’ll have to change the file paths for your setup.
    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <link rel="stylesheet" type="text/css" href="../../external/ext-2.1/resources/css/ext-all.css"/>
            <!-- Ext dependencies -->
            <script type="text/javascript" src="../../external/ext-2.1/adapter/ext/ext-base.js">
            </script>
            <script type="text/javascript" src="../../external/ext-2.1/ext-all-debug.js">
            </script>
            <!-- Ext extension dependencies -->
            <script type="text/javascript" src="../../external/ext-extensions/source/widgets/form/BrowseButton.js">
            </script>
            <!-- Application dependencies -->
            <script type="text/javascript" src="ScreenshotsPanel.js">
            </script>
            <!-- Bootstrap application -->
            <script type="text/javascript">
                Ext.onReady(function(){
                	Ext.QuickTips.init();
                	var viewport = new Ext.Viewport({
                		items: [{
                			xtype: 'panel',
                			items: [{
    							tag : 'div',
    							html : 'Form post: <a href="http://extjs.com/forum/showthread.php?t=29032">http://extjs.com/forum/showthread.php?t=29032</a>'
    						}, new Ext.ux.ScreenshotsPanel({
                				title: 'Screenshot Adder - Debug = false, meaning Browse butons are hidden.',
                				frame: true,
                				debug: false
                			}), new Ext.ux.ScreenshotsPanel({
                				title: 'Screenshot Adder - Debug = true, meaning Browse butons are visible.',
                				frame: true,
                				debug: true
                			})]
                		}]
                	});
                });
            </script>
            <title>Ext.ux.form.BrowseButton sample</title>
        </head>
        <body>
        </body>
    </html>

  3. #3
    Ext User
    Join Date
    Jul 2007
    Location
    BKK, Thailand
    Posts
    17
    Vote Rating
    0
    shane.fox is on a distinguished road

      0  

    Default


    Good job.

    I got an error in the destroy method. 'inputFileCt is not defined'

    Perhaps it needs to be changed to 'this.inputFileCt.remove(); this.inputFileCt = null'

  4. #4
    Sencha User
    Join Date
    Mar 2007
    Posts
    464
    Vote Rating
    1
    JorisA is on a distinguished road

      0  

    Default


    Thnx a gazillion, I was just going to try do something like this for myself

  5. #5
    Sencha User loeppky's Avatar
    Join Date
    May 2007
    Location
    Seattle, WA
    Posts
    230
    Vote Rating
    0
    loeppky is on a distinguished road

      0  

    Default


    shane.fox: I forgot to update the destroy method yesterday when I improved the code. In looking at it again and testing, I have found that the destroy method is unnecessary to override. I have removed it from the Ext.ux.form.BrowseButton class above. Let me know how that works for you.

  6. #6
    Sencha User loeppky's Avatar
    Join Date
    May 2007
    Location
    Seattle, WA
    Posts
    230
    Vote Rating
    0
    loeppky is on a distinguished road

      0  

    Default


    JorisA: you're very welcome although the idea credit definitely goes to MaximGB

  7. #7
    Sencha User loeppky's Avatar
    Join Date
    May 2007
    Location
    Seattle, WA
    Posts
    230
    Vote Rating
    0
    loeppky is on a distinguished road

      0  

    Default Online sample posted

    Online sample posted


    I updated post #2 with a link to a sample of BrowseButton online: http://loeppky.com/steven/code/samples/BrowseButton/

  8. #8
    Ext JS Premium Member
    Join Date
    Nov 2007
    Location
    Greetings from Sol : Earth : Europe : Germany : MV : Rostock : S├╝dstadt
    Posts
    38
    Vote Rating
    0
    t34 is on a distinguished road

      0  

    Default thank you (+ some problems)

    thank you (+ some problems)


    Hi, i use your BrowseButton very successful in a ASP.NET - project. Thank you for the good job.
    If someone is interested - see my helper files in the appendix.

    Now for some Problems:
    • If one step with the TAB-key through the page he reaches the hidden file selector control. I check this with FF2 and IE6.
    • Konqueror shows the hidden field - so it is nearly impossible to use BrowseButton here.

    Greetings from the baltic,
    thomas
    Attached Files

  9. #9
    Sencha User loeppky's Avatar
    Join Date
    May 2007
    Location
    Seattle, WA
    Posts
    230
    Vote Rating
    0
    loeppky is on a distinguished road

      0  

    Default


    t34: Glad to hear it's working for you, and thanks for reporting these issues. Here's my thoughts:
    1. I have verified the tab key issue and made note of it. We'll see how important/worth while it is to fix. Feel free to take this on if you'd like
    2. Since Ext doesn't official support Konqueror, I don't think it's worth investing any effort there.
    Let me know if you run into any other issues. Thanks as well for the Baltic greeting. I spent 2 months in Bosnia a couple of years ago...

  10. #10
    Sencha Premium Member dawesi's Avatar
    Join Date
    Mar 2007
    Location
    Melbourne, Australia (aka GMT+10)
    Posts
    1,082
    Vote Rating
    41
    dawesi has a spectacular aura about dawesi has a spectacular aura about

      0  

    Default Demos not working on Win Firefox 2 + IE6

    Demos not working on Win Firefox 2 + IE6


    see pic below... both render the same
    Attached Images
    Teahouse Training Company
    Official Certified Sencha Trainer

    Australia / New Zealand / Singapore / Hong Kong & APAC



    SenchaWorld.com - Sencha webinars, videos, etc
    SenchaForge.org - (coming soon)
    TeahouseHQ.com - Sencha ecosystem training portal

    Code Validation : JSLint | JSONLint | JSONPLint