dojo.provide("dojox.form.FilePickerTextBox"); dojo.require("dojox.widget.FilePicker"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dojox.form._HasDropDown"); dojo.declare( "dojox.form.FilePickerTextBox", [dijit.form.ValidationTextBox, dojox.form._HasDropDown], { // summary: // A validating text box tied to a file picker popup baseClass: "dojoxFilePickerTextBox", templatePath: dojo.moduleUrl("dojox.form", "resources/FilePickerTextBox.html"), // searchDelay: Integer // Delay in milliseconds between when user types something and we start // searching based on that value searchDelay: 500, // _stopClickEvent: boolean // Set to false since we want to handle our own click events _stopClickEvents: false, // valueItem: item // The item, in our store, of the directory relating to our value valueItem: null, // numPanes: number // The number of panes to display in our box (if we don't have any // minPaneWidth specified by our constraints) numPanes: 2.25, postMixInProperties: function(){ this.inherited(arguments); this.dropDown = new dojox.widget.FilePicker(this.constraints); }, postCreate: function(){ this.inherited(arguments); // Make our connections we want this.connect(this.dropDown, "onChange", this._onWidgetChange); this.connect(this.focusNode, "onblur", "_focusBlur"); this.connect(this.focusNode, "onfocus", "_focusFocus"); this.connect(this.focusNode, "ondblclick", function(){ dijit.selectInputText(this.focusNode); }); }, _setValueAttr: function(/*string*/value, priorityChange, fromWidget){ // summary: sets the value of this widget if(!this._searchInProgress){ this.inherited(arguments); value = value||""; var tVal = this.dropDown.attr("pathValue")||""; if(value !== tVal){ this._skip = true; var fx = dojo.hitch(this, "_setBlurValue"); this.dropDown._setPathValueAttr(value, !fromWidget, this._settingBlurValue ? fx : null); } } }, _onWidgetChange: function(/*item*/item){ // summary: called when the path gets changed in the dropdown if(!item && this.focusNode.value){ this._hasValidPath = false; this.focusNode.value = ""; }else{ this.valueItem = item; var value = this.dropDown._getPathValueAttr(item); if(value){ this._hasValidPath = true; } if(!this._skip){ this._setValueAttr(value, undefined, true); } delete this._skip; } this.validate(); }, startup: function(){ if(!this.dropDown._started){ this.dropDown.startup(); } this.inherited(arguments); }, openDropDown: function(){ // set width to 0 so that it will resize automatically this.dropDown.domNode.style.width="0px"; if(!("minPaneWidth" in (this.constraints||{}))){ this.dropDown.attr("minPaneWidth", (this.domNode.offsetWidth / this.numPanes)); } this.inherited(arguments); }, toggleDropDown: function(){ this.inherited(arguments); // Make sure our display is up-to-date with our value if(this._opened){ this.dropDown.attr("pathValue", this.attr("value")); } }, _focusBlur: function(/*Event*/ e){ // summary: called when the focus node gets blurred if(e.explicitOriginalTarget == this.focusNode && !this._allowBlur){ window.setTimeout(dojo.hitch(this, function(){ if(!this._allowBlur){ this.focus(); } }), 1); }else if(this._menuFocus){ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": false}); delete this._menuFocus; } }, _focusFocus: function(/*Event*/ e){ // summary: called when the focus node gets focus if(this._menuFocus){ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": false}); } delete this._menuFocus; var focusNode = dijit.getFocus(this); if(focusNode && focusNode.node){ focusNode = dijit.byNode(focusNode.node); if(focusNode){ this._menuFocus = focusNode.domNode; } } if(this._menuFocus){ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": true}); } delete this._allowBlur; }, _onBlur: function(){ // summary: called when focus is shifted away from this widget this._allowBlur = true; delete this.dropDown._savedFocus; this.inherited(arguments); }, _setBlurValue: function(){ // summary: sets the value of the widget once focus has left if(this.dropDown && !this._settingBlurValue){ this._settingBlurValue = true; this.attr("value", this.focusNode.value); }else{ delete this._settingBlurValue; this.inherited(arguments); } }, parse: function(/* String */ value, /* Object */ constraints){ // summary: // Function to convert a formatted string to a value - we use // it to verify that it *really* is a valid value if(this._hasValidPath || this._hasSelection){ return value; } var dd = this.dropDown, topDir = dd.topDir, sep = dd.pathSeparator; var ddVal = dd.attr("pathValue"); var norm = function(v){ if(topDir.length && v.indexOf(topDir) === 0){ v = v.substring(topDir.length); } if(sep && v[v.length - 1] == sep){ v = v.substring(0, v.length - 1); } return v; }; ddVal = norm(ddVal); var val = norm(value); if(val == ddVal){ return value; } return undefined; }, _startSearchFromInput: function(){ // summary: kicks off a search based off the current text value of the widget var dd = this.dropDown, fn = this.focusNode; var val = fn.value, oVal = val, topDir = dd.topDir; if(this._hasSelection){ dijit.selectInputText(fn, oVal.length); } this._hasSelection = false; if(topDir.length && val.indexOf(topDir) === 0){ val = val.substring(topDir.length); } var dirs = val.split(dd.pathSeparator); var setFromChain = dojo.hitch(this, function(idx){ var dir = dirs[idx]; var child = dd.getChildren()[idx]; var conn; this._searchInProgress = true; var _cleanup = dojo.hitch(this, function(){ delete this._searchInProgress; }); if((dir || child) && !this._opened){ this.toggleDropDown(); } if(dir && child){ var fx = dojo.hitch(this, function(){ if(conn){ this.disconnect(conn); } delete conn; var children = child._menu.getChildren(); var exact = dojo.filter(children, function(i){ return i.label == dir; })[0]; var first = dojo.filter(children, function(i){ return (i.label.indexOf(dir) === 0); })[0]; if(exact && ((dirs.length > idx + 1 && exact.children) || (!exact.children))){ idx++; child._menu.onItemClick(exact, {type: "internal", stopPropagation: function(){}, preventDefault: function(){}}); if(dirs[idx]){ setFromChain(idx); }else{ _cleanup(); } }else{ child._setSelected(null); if(first && dirs.length === idx + 1){ dd._setInProgress = true; dd._removeAfter(child); delete dd._setInProgress; var targetString = first.label; if(first.children){ targetString += dd.pathSeparator; } targetString = targetString.substring(dir.length); window.setTimeout(function(){ dijit.scrollIntoView(first.domNode); }, 1); fn.value = oVal + targetString; dijit.selectInputText(fn, oVal.length); this._hasSelection = true; try{first.focusNode.focus();}catch(e){} }else{ if(this._menuFocus){ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": false, "Focus": false}); } delete this._menuFocus; } _cleanup(); } }); if(!child.isLoaded){ conn = this.connect(child, "onLoad", fx); }else{ fx(); } }else{ if(child){ child._setSelected(null); dd._setInProgress = true; dd._removeAfter(child); delete dd._setInProgress; } _cleanup(); } }); setFromChain(0); }, _onKey: function(/*Event*/ e){ // summary: callback when the user presses a key on menu popup node if(this.disabled || this.readOnly){ return; } var dk = dojo.keys; var c = e.charOrCode; if(c==dk.DOWN_ARROW){ this._allowBlur = true; } if(c==dk.ENTER && this._opened){ this.dropDown.onExecute(); dijit.selectInputText(this.focusNode, this.focusNode.value.length); this._hasSelection = false; dojo.stopEvent(e); return; } if((c==dk.RIGHT_ARROW || c==dk.LEFT_ARROW || c==dk.TAB) && this._hasSelection){ this._startSearchFromInput(); dojo.stopEvent(e); return; } this.inherited(arguments); var doSearch = false; if((c==dk.BACKSPACE || c==dk.DELETE) && this._hasSelection){ this._hasSelection = false; }else if(c==dk.BACKSPACE || c==dk.DELETE || c==" "){ doSearch = true; }else{ doSearch = e.keyChar !== ""; } if(this._searchTimer){ window.clearTimeout(this._searchTimer); } delete this._searchTimer; if(doSearch){ this._hasValidPath = false; this._hasSelection = false; this._searchTimer = window.setTimeout(dojo.hitch(this, "_startSearchFromInput"), this.searchDelay + 1); } } } );