Author: husted Date: Wed Dec 27 13:26:44 2006 New Revision: 490569 URL: http://svn.apache.org/viewvc?view=rev&rev=490569 Log: WW-1562 Apply patch submitted by Musachy Barros. Fixed on this patch: * Added "loadOnTextChange" * Added "loadMinimumCout" * selected values are loaded if page is loaded again * added "showDownArrow"
Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css Modified: struts/struts2/trunk/apps/showcase/src/main/webapp/ajax/autocompleter/index.jsp struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Autocompleter.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/ui/AutocompleterTag.java struts/struts2/trunk/core/src/main/resources/META-INF/struts-tags.tld struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ComboBox.js struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js struts/struts2/trunk/core/src/main/resources/template/ajax/autocompleter.ftl struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/AutocompleterTest.java struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-1.txt struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-2.txt Modified: struts/struts2/trunk/apps/showcase/src/main/webapp/ajax/autocompleter/index.jsp URL: http://svn.apache.org/viewvc/struts/struts2/trunk/apps/showcase/src/main/webapp/ajax/autocompleter/index.jsp?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/apps/showcase/src/main/webapp/ajax/autocompleter/index.jsp (original) +++ struts/struts2/trunk/apps/showcase/src/main/webapp/ajax/autocompleter/index.jsp Wed Dec 27 13:26:44 2006 @@ -11,11 +11,20 @@ <body> + <s:url id="jsonList" value="/JSONList.action"/> -Using a JSON list returned from an action (href="/JSONList.action"), without autoComplete (autoComplete="false"), use indicator +Using a JSON list returned from an action (href="/JSONList.action"), without autoComplete (autoComplete="false"), use indicator, search substring (searchType="substring") +<br/> +<s:autocompleter name="state" theme="ajax" indicator="indicator1" href="%{jsonList}" cssStyle="width: 200px;" autoComplete="false" searchType="substring"/> +<img id="indicator1" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading..." style="display:none"/> + +<br/> +<br/> + +Reload on type (loadOnTextChange="true"), after 3 characters (loadMinimumCout="3", it is "3" by default), without the down arrow button (showDownArrow="false") <br/> -<s:autocompleter name="state" theme="ajax" indicator="indicator" href="%{jsonList}" cssStyle="width: 200px;" autoComplete="false"/> +<s:autocompleter theme="ajax" indicator="indicator" href="%{jsonList}" cssStyle="width: 200px;" autoComplete="false" loadOnTextChange="true" loadMinimumCount="3" showDownArrow="false"/> <img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading..." style="display:none"/> <br/> @@ -64,7 +73,7 @@ <form id="selectForm"> <p>Autocompleter 1 <s:autocompleter theme="simple" name="select" list="{'fruits','colors'}" value="colors" notifyTopics="/Changed" forceValidOption="true" id="sel"/></p> </form> -Autocompleter 2 <s:autocompleter theme="ajax" href="%{#autoex}" autoComplete="false" formId="selectForm" listenTopics="/Changed" notifyTopics="/OpsChanged" forceValidOption="true" id="ops"/> +Autocompleter 2 <s:autocompleter theme="ajax" href="%{#autoex}" autoComplete="false" formId="selectForm" listenTopics="/Changed" forceValidOption="true" id="ops"/> <br/> <br/> Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Autocompleter.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Autocompleter.java?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Autocompleter.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Autocompleter.java Wed Dec 27 13:26:44 2006 @@ -48,6 +48,10 @@ * <li>formId</li> * <li>formFilter</li> * <li>indicator</li> + * <li>loadOnTextChange</li> + * <li>loadMinimumCount</li> + * <li>showDownArrow</li> + * <li>searchType</li> * </ul> * 'dropdownWidth' width in pixels of the drodpdown, same as autocompleter's width by default<p/> * 'dropdownHeight' height in pixels of the drodown, 120 px by default<p/> @@ -61,6 +65,10 @@ * 'listenTopics' comma separated list of topics names, that will trigger a request * 'indicator' element to be shown while the request executing * 'showErrorTransportText': whether errors should be displayed (on 'targets')<p/> + * 'loadOnTextChange' options will be reloaded everytime a character is typed on the textbox<p/> + * 'loadMinimumCount' minimum number of characters that will force the content to be loaded<p/> + * 'showDownError' show or hide the down arrow button + * 'searchType' how the search must be performed, options are: "startstring", "startword" and "substring"<p/> * 'notifyTopics' comma separated list of topics names, that will be published. Three parameters are passed:<p/> * <ul> * <li>data: selected value when type='valuechanged'</li> @@ -88,6 +96,9 @@ protected String listenTopics; protected String notifyTopics; protected String indicator; + protected String loadOnTextChange; + protected String loadMinimumCount; + protected String showDownArrow; public Autocompleter(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { @@ -109,8 +120,11 @@ if (forceValidOption != null) addParameter("forceValidOption", findValue(forceValidOption, Boolean.class)); - if (searchType != null) - addParameter("searchType", findString(searchType)); + if (searchType != null) { + String type = findString(searchType); + if(type != null) + addParameter("searchType", type.toUpperCase()); + } if (autoComplete != null) addParameter("autoComplete", findValue(autoComplete, Boolean.class)); if (delay != null) @@ -135,6 +149,14 @@ addParameter("notifyTopics", findString(notifyTopics)); if (indicator != null) addParameter("indicator", findString(indicator)); + if (loadOnTextChange != null) + addParameter("loadOnTextChange", findValue(loadOnTextChange, Boolean.class)); + if (loadMinimumCount != null) + addParameter("loadMinimumCount", findValue(loadMinimumCount, Integer.class)); + if (showDownArrow != null) + addParameter("showDownArrow", findValue(showDownArrow, Boolean.class)); + else + addParameter("showDownArrow", Boolean.TRUE); //get the key value if(name != null) { String keyNameExpr = "%{" + name + "Key}"; @@ -188,7 +210,7 @@ /** - * set how the serach bust be preformed, optionas are: "startstring", "startword" and "substring" + * set how the search must be performed, options are: "startstring", "startword" and "substring" * @s.tagattribute required="false" default="stringstart" type="String" */ public void setSearchType(String searchType) { @@ -254,5 +276,29 @@ */ public void setIndicator(String indicator) { this.indicator = indicator; + } + + /** + * Minimum number of characters that will force the content to be loaded + * @s.tagattribute required="false" type="Integer" default="3" + */ + public void setLoadMinimumCount(String loadMinimumCount) { + this.loadMinimumCount = loadMinimumCount; + } + + /** + * Options will be reloaded everytime a character is typed on the textbox. + * @s.tagattribute required="false" type="Boolean" default="false" + */ + public void setLoadOnTextChange(String loadOnType) { + this.loadOnTextChange = loadOnType; + } + + /** + * Show or hide the down arrow button + * @s.tagattribute required="false" type="Boolean" default="true" + */ + public void setShowDownArrow(String showDownArrow) { + this.showDownArrow = showDownArrow; } } Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/ui/AutocompleterTag.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/ui/AutocompleterTag.java?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/ui/AutocompleterTag.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/ui/AutocompleterTag.java Wed Dec 27 13:26:44 2006 @@ -47,6 +47,9 @@ protected String listenTopics; protected String notifyTopics; protected String indicator; + protected String loadOnTextChange; + protected String loadMinimumCount; + protected String showDownArrow; public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { return new Autocompleter(stack, req, res); @@ -69,6 +72,9 @@ autocompleter.setListenTopics(listenTopics); autocompleter.setNotifyTopics(notifyTopics); autocompleter.setIndicator(indicator); + autocompleter.setLoadMinimumCount(loadMinimumCount); + autocompleter.setLoadOnTextChange(loadOnTextChange); + autocompleter.setShowDownArrow(showDownArrow); } public void setAutoComplete(String autoComplete) { @@ -122,4 +128,21 @@ public void setIndicator(String indicator) { this.indicator = indicator; } + + public void setLoadMinimumCount(String loadMinimumCount) { + this.loadMinimumCount = loadMinimumCount; + } + + public String getLoadMinimumCount() { + return loadMinimumCount; + } + + public void setLoadOnTextChange(String loadOnTextChange) { + this.loadOnTextChange = loadOnTextChange; + } + + public void setShowDownArrow(String showDownArrow) { + this.showDownArrow = showDownArrow; + } + } Modified: struts/struts2/trunk/core/src/main/resources/META-INF/struts-tags.tld URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/META-INF/struts-tags.tld?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/META-INF/struts-tags.tld (original) +++ struts/struts2/trunk/core/src/main/resources/META-INF/struts-tags.tld Wed Dec 27 13:26:44 2006 @@ -2886,6 +2886,30 @@ <description><![CDATA[Id of element that will be show while doing the request]]></description> </attribute> + <attribute> + <name>loadOnTextChange</name> + <required>false</required> + <rtexprvalue>true</rtexprvalue> + + <description><![CDATA[Reload options when text changes on the textbox (false by default)]]></description> + + </attribute> + <attribute> + <name>loadMinimumCount</name> + <required>false</required> + <rtexprvalue>true</rtexprvalue> + + <description><![CDATA[Minimum number of characters that will force the content to be loaded (3 by default)]]></description> + + </attribute> + <attribute> + <name>showDownArrow</name> + <required>false</required> + <rtexprvalue>true</rtexprvalue> + + <description><![CDATA[Show or hide the down arrow button (true by default)]]></description> + + </attribute> <attribute> <name>autoComplete</name> <required>false</required> @@ -2977,7 +3001,15 @@ <description><![CDATA[The URL to call to obtain the content]]></description> </attribute> - <attribute> + <attribute> + <name>searchType</name> + <required>false</required> + <rtexprvalue>true</rtexprvalue> + + <description><![CDATA[how the search must be performed, options are: "startstring" (default), "startword" and "substring"]]></description> + + </attribute> + <attribute> <name>list</name> <required>false</required> <rtexprvalue>true</rtexprvalue> Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ComboBox.js URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ComboBox.js?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ComboBox.js (original) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ComboBox.js Wed Dec 27 13:26:44 2006 @@ -98,7 +98,7 @@ var text = opts[x].textContent || opts[x].innerText || opts[x].innerHTML; var keyValArr = [String(text), String(opts[x].value)]; data.push(keyValArr); - if(opts[x].selected){ + if(opts[x].selected){ cbox.setAllValues(keyValArr[0], keyValArr[1]); } } @@ -110,7 +110,7 @@ this.getData = function(/*String*/ url){ dojo.io.bind({ url: url, - load: dojo.lang.hitch(this, function(type, data, evt){ + load: dojo.lang.hitch(this, function(type, data, evt){ if(!dojo.lang.isArray(data)){ var arrData = []; for(var key in data){ @@ -212,7 +212,7 @@ // populate this.data and initialize lookup structures this.data = pdata; }; - + if(dataPairs){ this.setData(dataPairs); } @@ -224,11 +224,11 @@ { // Applies to any renderer isContainer: false, - + forceValidOption: false, - searchType: "stringstart", + searchType: "STARTSTRING", dataProvider: null, - + startSearch: function(/*String*/ searchString){}, selectNextResult: function(){}, selectPrevResult: function(){}, @@ -248,11 +248,11 @@ dataUrl: "", fadeTime: 200, disabled: false, - // maxListLength limits list to X visible rows, scroll on rest - maxListLength: 8, + // maxListLength limits list to X visible rows, scroll on rest + maxListLength: 8, // mode can also be "remote" for JSON-returning live search or "html" for // dumber live search - mode: "local", + mode: "local", selectedResult: null, _highlighted_option: null, _prev_key_backspace: false, @@ -285,7 +285,7 @@ getValue: function(){ return this.comboBoxValue.value; }, - + getState: function(){ return {value: this.getValue()}; }, @@ -296,15 +296,15 @@ enable:function(){ this.disabled=false; - this.isEnabled = true; + this.isEnabled = true; this.textInputNode.removeAttribute("disabled"); }, - + disable: function(){ - this.disabled = true; + this.disabled = true; this.isEnabled = false; - this.textInputNode.setAttribute("disabled",true); - }, + this.textInputNode.setAttribute("disabled",true); + }, getCaretPos: function(/*DomNode*/ element){ // khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22 @@ -329,7 +329,7 @@ } catch (e){ return 0; // If focus has shifted, 0 is fine for caret pos. } - + } }, @@ -398,7 +398,7 @@ if(!this.autoComplete && this.popupWidget.isShowingNow && this._highlighted_option){ dojo.event.browser.stopEvent(evt); this.selectOption({ 'target': this._highlighted_option, 'noHide': false}); - + // put caret last this.setSelectedRange(this.textInputNode, this.textInputNode.value.length, null); }else{ @@ -452,14 +452,14 @@ if(doSearch){ // if we have gotten this far we dont want to keep our highlight this.blurOptionNode(); - + // need to wait a tad before start search so that the event bubbles through DOM and we have value visible this.searchTimer = setTimeout(dojo.lang.hitch(this, this.startSearchFromInput), this.searchDelay); } }, - // When inputting characters using an input method, such as Asian - // languages, it will generate this event instead of onKeyDown event + // When inputting characters using an input method, such as Asian + // languages, it will generate this event instead of onKeyDown event compositionEnd: function(/*Event*/ evt){ evt.key = evt.keyCode; this._handleKeyEvents(evt); @@ -543,9 +543,9 @@ // For inlining a table we need browser specific CSS dojo.html.applyBrowserClass(this.domNode); - var source = this.getFragNodeRef(frag); - if (! this.name && source.name){ this.name = source.name; } - this.comboBoxValue.name = this.name; + var source = this.getFragNodeRef(frag); + if (! this.name && source.name){ this.name = source.name; } + this.comboBoxValue.name = this.name; this.comboBoxSelectionValue.name = this.name+"_selected"; /* different nodes get different parts of the style */ @@ -568,7 +568,7 @@ this.dataProvider = new dpClass(); this.dataProvider.init(this, this.getFragNodeRef(frag)); - this.popupWidget = new dojo.widget.createWidget("PopupContainer", + this.popupWidget = new dojo.widget.createWidget("PopupContainer", {toggle: this.dropdownToggle, toggleDuration: this.toggleDuration}); dojo.event.connect(this, 'destroy', this.popupWidget, 'destroy'); this.optionsListNode = this.popupWidget.domNode; @@ -577,7 +577,7 @@ dojo.event.connect(this.optionsListNode, 'onclick', this, 'selectOption'); dojo.event.connect(this.optionsListNode, 'onmouseover', this, '_onMouseOver'); dojo.event.connect(this.optionsListNode, 'onmouseout', this, '_onMouseOut'); - + dojo.event.connect(this.optionsListNode, "onmouseover", this, "itemMouseOver"); dojo.event.connect(this.optionsListNode, "onmouseout", this, "itemMouseOut"); }, @@ -648,7 +648,7 @@ this.blurTimer = dojo.lang.setTimeout(this, "checkBlurred", millisec); } }, - + // these 2 are needed in IE and Safari as inputTextNode loses focus when scrolling optionslist _onMouseOver: function(/*Event*/ evt){ if(!this._mouseover_list){ @@ -726,7 +726,7 @@ if(!dojo.html.isDescendantOf(evt.target, this.optionsListNode)){ // handle autocompletion where the the user has hit ENTER or TAB - + // if the input is empty do nothing if(!this.textInputNode.value.length){ return; @@ -739,7 +739,7 @@ } // otherwise the user has accepted the autocompleted value }else{ - tgt = evt.target; + tgt = evt.target; } while((tgt.nodeType!=1)||(!tgt.getAttribute("resultName"))){ @@ -790,7 +790,7 @@ height = visibleCount * dojo.html.getMarginBox(childs[0]).height +"px"; } width = (dojo.html.getMarginBox(this.domNode).width-2)+"px"; - + } this.popupWidget.open(this.domNode, this, this.downArrowNode); }else{ @@ -828,7 +828,7 @@ dojo.event.connect(this.dataProvider, "provideSearchResults", this, "openResultList"); dojo.event.connect(this.textInputNode, "onblur", this, "onBlurInput"); dojo.event.connect(this.textInputNode, "onfocus", this, "onFocusInput"); - if (this.disabled){ + if (this.disabled){ this.disable(); } var s = dojo.widget.html.stabile.getState(this.widgetId); Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css?view=auto&rev=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css (added) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css Wed Dec 27 13:26:44 2006 @@ -0,0 +1,68 @@ +.dojoComboBoxOuter { + border: 0px !important; + margin: 0px !important; + padding: 0px !important; + background: transparent !important; + white-space: nowrap !important; +} + +.dojoComboBox { + border: 1px inset #afafaf; + margin: 0px; + padding: 0px; + vertical-align: middle !important; + float: none !important; + position: static !important; + display: inline; +} + +/* the input box */ +input.dojoComboBox { + border-right-width: 1px !important; + margin-right: 0px !important; + padding-right: 0px !important; +} + +/* the down arrow */ +img.dojoComboBox { + border-left-width: 0px !important; + padding-left: 0px !important; + margin-left: 0px !important; +} + +/* IE vertical-alignment calculations can be off by +-1 but these margins are collapsed away */ +.dj_ie img.dojoComboBox { + margin-top: 1px; + margin-bottom: 1px; +} + +/* the drop down */ +.dojoComboBoxOptions { + font-family: Verdana, Helvetica, Garamond, sans-serif; + /* font-size: 0.7em; */ + background-color: white; + border: 1px solid #afafaf; + position: absolute; + z-index: 1000; + overflow: auto; + cursor: default; +} + +.dojoComboBoxItem { + padding-left: 2px; + padding-top: 2px; + margin: 0px; +} + +.dojoComboBoxItemEven { + background-color: #f4f4f4; +} + +.dojoComboBoxItemOdd { + background-color: white; +} + +.dojoComboBoxItemHighlight { + background-color: #63709A; + color: white; +} Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js (original) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js Wed Dec 27 13:26:44 2006 @@ -17,6 +17,7 @@ loadingText : "Loading...", errorText : "", showError : true, + showLoading : true, //pub/sub events listenTopics : "", @@ -35,14 +36,14 @@ indicator : "", parseContent : true, - postCreate : function() { + var self = this; + //attach listeners if(!dojo.string.isBlank(this.listenTopics)) { this.log("Listening to " + this.listenTopics + " to refresh"); var topics = this.listenTopics.split(","); if(topics) { - var self = this; if(topics) { if(topics) { dojo.lang.forEach(topics, function(topic){ @@ -61,15 +62,29 @@ //split targets this.targetsArray = this.targets.split(","); } + if(!dojo.string.isBlank(this.event)) { - dojo.event.connect(this.domNode, this.event, this, "reloadContents"); + dojo.event.connect(this.domNode, this.event, function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + self.reloadContents(); + }); } - if(dojo.string.isBlank(this.href)) { - this.formNode = dojo.string.isBlank(this.formId) ? dojo.dom.getFirstAncestorByTag(this.domNode, "form") : dojo.byId(this.formId); - this.href = this.formNode.action; + + if(dojo.string.isBlank(this.href) && dojo.string.isBlank(this.formId)) { + //no href and no formId, we must be inside a form + this.formNode = dojo.dom.getFirstAncestorByTag(this.domNode, "form"); } else { this.formNode = dojo.byId(this.formId); } + + if(this.formNode && dojo.string.isBlank(this.href)) { + this.href = this.formNode.action; + } + + if(!dojo.string.isBlank(this.formId)) { + this.formNode = dojo.byId(this.formId); + } }, log : function(text) { @@ -81,10 +96,10 @@ var self = this; var xmlParser = new dojo.xml.Parse(); dojo.lang.forEach(this.targetsArray, function(target) { - var node = dojo.byId(target); node.innerHTML = text; - if(self.parseContent){ + + if(self.parseContent && text != self.loadingText){ var frag = xmlParser.parseElement(node, null, true); dojo.widget.getParser().createSubComponents(frag, dojo.widget.byId(target)); } @@ -131,10 +146,13 @@ notify : function(data, type, e) { if(this.notifyTopicsArray) { + var self = this; dojo.lang.forEach(this.notifyTopicsArray, function(topic) { try { - dojo.event.topic.publish(topic, data, type, null); - } catch(e){} + dojo.event.topic.publish(topic, data, type, e); + } catch(ex){ + self.log(ex); + } }); } }, @@ -147,12 +165,13 @@ eval(this.beforeLoading); } - if(!dojo.string.isBlank(this.loadingText)) { + if(this.showLoading && !dojo.string.isBlank(this.loadingText)) { event.text = this.loadingText; } }, - reloadContents : function() { + reloadContents : function(evt) { + if(!dojo.string.isBlank(this.handler)) { //use custom handler this.log("Invoking handler: " + this.handler); @@ -169,14 +188,39 @@ eval(this.beforeLoading); } - //show indicator - dojo.html.show(this.indicator); try { var self = this; - this.notify(this.widgetId, "before", {}); - this.setContent(this.loadingText); + var request = {cancel: false}; + this.notify(this.widgetId, "before", request); + if(request.cancel) { + this.log("Request canceled"); + return; + } + + //if the href is null, we still call the "beforeLoading" + // and publish the notigy topics + if(dojo.string.isBlank(this.href)) { + return; + } + + //if there is a parent form, and it has a "onsubmit" + //execute it, validation is usually there + if(this.formNode && this.formNode.onsubmit != null) { + var makeRequest = this.formNode.onsubmit.call(evt); + if(makeRequest != null && !makeRequest) { + this.log("Request canceled by 'onsubmit' of the form"); + return; + } + } + + //show indicator + dojo.html.show(this.indicator); + if(this.showLoading) { + this.setContent(this.loadingText); + } + dojo.io.bind({ - url: self.href, + url: this.href, useCache: false, preventCache: true, formNode: self.formNode, Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js (original) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js Wed Dec 27 13:26:44 2006 @@ -12,9 +12,10 @@ event: "onclick", postCreate : function() { - this.domNode.href = "#"; struts.widget.BindAnchor.superclass.postCreate.apply(this); + this.domNode.href = "#"; } }); + Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js (original) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js Wed Dec 27 13:26:44 2006 @@ -25,7 +25,9 @@ //messages loadingText : "Loading...", + showLoading : true, errorText : "", + showError : true, //pub/sub events listenTopics : "", @@ -42,7 +44,6 @@ formFilter : "", firstTime : true, - showError : true, indicator: "", //make dojo process the content @@ -56,7 +57,11 @@ return; } } - if(!dojo.string.isBlank(this.loadingText)) { + if(!this.showLoading) { + event.returnValue = false; + return; + } + if(this.showLoading && !dojo.string.isBlank(this.loadingText)) { event.text = this.loadingText; } }, @@ -85,10 +90,13 @@ notify : function(data, type, e) { if(this.notifyTopicsArray) { + var self = this; dojo.lang.forEach(this.notifyTopicsArray, function(topic) { try { - dojo.event.topic.publish(topic, data, type, null); - } catch(e){} + dojo.event.topic.publish(topic, data, type, e); + } catch(ex) { + self.log(ex); + } }); } }, @@ -129,7 +137,6 @@ //start the timer if(this.autoStart) { - this.log("autostarting"); //start after delay if(this.delay > 0) { if(this.updateFreq > 0) { @@ -185,10 +192,16 @@ return; } } + + var request = {cancel: false}; + this.notify(this.widgetId, "before", request); + if(request.cancel) { + return; + } + //show indicator dojo.html.show(this.indicator); - this.notify(this.widgetId, "before", {}); this._handleDefaults("Loading...", "onDownloadStart"); var self = this; dojo.io.bind({ Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js (original) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js Wed Dec 27 13:26:44 2006 @@ -198,6 +198,9 @@ visibleDownArrow : true, fadeTime : 100, + //dojo has "stringstart" which is invalid + searchType: "STARTSTRING", + templateCssPath: dojo.uri.dojoUri("struts/ComboBox.css"), //from Dojo's ComboBox showResultList: function() { @@ -258,10 +261,12 @@ var i = text.toLowerCase().indexOf(typedText.toLowerCase()); if(i >= 0) { var pre = text.substring(0, i); - var matched = text.substring(i, typedText.length); + var matched = text.substring(i, i + typedText.length); var post = text.substring(i + typedText.length); - td.appendChild(document.createTextNode(pre)); + if(!dojo.string.isBlank(pre)) { + td.appendChild(document.createTextNode(pre)); + } var boldNode = document.createElement("b"); td.appendChild(boldNode); boldNode.appendChild(document.createTextNode(matched)); @@ -290,7 +295,12 @@ var topics = this.listenTopics.split(","); for(var i = 0; i < topics.length; i++) { dojo.event.topic.subscribe(topics[i], function() { - self.notify(this.widgetId, "before", {}); + var request = {cancel: false}; + self.notify(this.widgetId, "before", request); + if(request.cancel) { + return; + } + self.clearValues(); self.dataProvider.getData(self.dataUrl); }); } @@ -312,6 +322,11 @@ if(!this.visibleDownArrow) { dojo.html.hide(this.downArrowNode); } + + //search type + if(!dojo.string.isBlank(this.searchType)) { + this.dataProvider.searchType = this.searchType.toUpperCase(); + } }, clearValues : function() { @@ -328,8 +343,10 @@ if(this.notifyTopicsArray) { dojo.lang.forEach(this.notifyTopicsArray, function(topic) { try { - dojo.event.topic.publish(topic, data, type, null); - } catch(e){} + dojo.event.topic.publish(topic, data, type, e); + } catch(ex) { + dojo.debug(ex); + } }); } }, @@ -339,13 +356,15 @@ if(this.loadOnType) { if(searchStr.length >= this.loadMinimum) { var nuHref = this.dataUrl + (this.dataUrl.indexOf("?") > -1 ? "&" : "?"); - nuHref += this.name + '=' + searchStr; - this.dataProvider.getData(nuHref); - this.startSearch(searchStr); - } + nuHref += this.name + '=' + searchStr; + this.dataProvider.getData(nuHref); + this.startSearch(searchStr); + } else { + this.hideResultList(); + } } else { - this.startSearch(searchStr); + this.startSearch(searchStr); } } }); Modified: struts/struts2/trunk/core/src/main/resources/template/ajax/autocompleter.ftl URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/template/ajax/autocompleter.ftl?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/template/ajax/autocompleter.ftl (original) +++ struts/struts2/trunk/core/src/main/resources/template/ajax/autocompleter.ftl Wed Dec 27 13:26:44 2006 @@ -15,7 +15,7 @@ forceValidOption="${parameters.forceValidOption?string?html}"<#rt/> </#if> <#if parameters.searchType?if_exists != ""> - searchType="${parameters.searchType}"<#rt/> + searchType="${parameters.searchType?html}"<#rt/> </#if> <#if parameters.autoComplete?exists> autoComplete="${parameters.autoComplete?string?html}"<#rt/> @@ -67,6 +67,15 @@ </#if> <#if parameters.indicator?if_exists != ""> indicator="${parameters.indicator?html}"<#rt/> +</#if> +<#if parameters.loadOnTextChange?default(false)> + loadOnType="${parameters.loadOnTextChange?string?html}"<#rt/> +</#if> +<#if parameters.loadMinimumCount?exists> + loadMinimum="${parameters.loadMinimumCount?c}"<#rt/> +</#if> +<#if parameters.showDownArrow?exists> + visibleDownArrow="${parameters.showDownArrow?string?html}"<#rt/> </#if> <#include "/${parameters.templateDir}/simple/scripting-events.ftl" /> > Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/AutocompleterTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/AutocompleterTest.java?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/AutocompleterTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/ui/AutocompleterTest.java Wed Dec 27 13:26:44 2006 @@ -23,6 +23,9 @@ tag.setName("f"); tag.setValue("g"); tag.setIndicator("h"); + tag.setLoadOnTextChange("true"); + tag.setLoadMinimumCount("3"); + tag.setShowDownArrow("false"); tag.doStartTag(); tag.doEndTag(); Modified: struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-1.txt URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-1.txt?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-1.txt (original) +++ struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-1.txt Wed Dec 27 13:26:44 2006 @@ -3,11 +3,14 @@ id="f" dataUrl="a" forceValidOption="false" - searchType="b" + searchType="B" autoComplete="true" searchDelay="100" dropdownWidth="10" dropdownHeight="10" name="f" initialValue="g" -indicator="h"> + indicator="h" + loadOnType="true" + loadMinimum="3" + visibleDownArrow="false"> Modified: struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-2.txt URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-2.txt?view=diff&rev=490569&r1=490568&r2=490569 ============================================================================== --- struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-2.txt (original) +++ struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/jsp/ui/Autocompleter-2.txt Wed Dec 27 13:26:44 2006 @@ -3,7 +3,7 @@ id="f" dataUrl="a" forceValidOption="false" - searchType="b" + searchType="B" autoComplete="true" searchDelay="100" dropdownWidth="10"