Author: hermanns
Date: Fri Dec 1 12:54:52 2006
New Revision: 481382
URL: http://svn.apache.org/viewvc?view=rev&rev=481382
Log:
Autocompleter problems
o removed code duplication
Issue Number: WW-1529
Submitted by: Musachy Barroso
Modified:
struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js
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=481382&r1=481381&r2=481382
==============================================================================
---
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
Fri Dec 1 12:54:52 2006
@@ -291,296 +291,3 @@
}
}
});
-dojo.provide("struts.widget.ComboBox");
-
-dojo.require("dojo.html.*");
-dojo.require("dojo.widget.ComboBox");
-
-struts.widget.ComboBoxDataProvider = function(/*Array*/ dataPairs, /*Number*/
limit, /*Number*/ timeout){
- // NOTE: this data provider is designed as a naive reference
- // implementation, and as such it is written more for readability than
- // speed. A deployable data provider would implement lookups, search
- // caching (and invalidation), and a significantly less naive data
- // structure for storage of items.
-
- this.data = [];
- this.searchTimeout = timeout || 500;
- this.searchLimit = limit || 30;
- this.searchType = "STARTSTRING"; // may also be "STARTWORD" or "SUBSTRING"
- this.caseSensitive = false;
- // for caching optimizations
- this._lastSearch = "";
- this._lastSearchResults = null;
-
- this.beforeLoading = "";
- this.afterLoading = "";
-
- this.formId = "";
- this.formFilter = "";
-
- this.init = function(/*Widget*/ cbox, /*DomNode*/ node){
- this.beforeLoading = cbox.beforeLoading;
- this.afterLoading = cbox.afterLoading;
-
- this.formId = cbox.formId;
- this.formFilter = cbox.formFilter;
-
- if(!dojo.string.isBlank(cbox.dataUrl)){
- this.getData(cbox.dataUrl);
- }else{
- // check to see if we can populate the list from <option> elements
- if((node)&&(node.nodeName.toLowerCase() == "select")){
- // NOTE: we're not handling <optgroup> here yet
- var opts = node.getElementsByTagName("option");
- var ol = opts.length;
- var data = [];
- for(var x=0; x<ol; x++){
- 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){
- cbox.setAllValues(keyValArr[0], keyValArr[1]);
- }
- }
- this.setData(data);
- }
- }
- };
-
- this.getData = function(/*String*/ url){
- if(!dojo.string.isBlank(this.beforeLoading)) {
- eval(this.beforeLoading);
- }
-
- dojo.io.bind({
- url: url,
- formNode: dojo.byId(this.formId),
- formFilter: window[this.formFilter],
- load: dojo.lang.hitch(this, function(type, data, evt){
- if(!dojo.string.isBlank(this.afterLoading)) {
- eval(this.afterLoading);
- }
- if(!dojo.lang.isArray(data)){
- var arrData = [];
- for(var key in data){
- arrData.push([data[key], key]);
- }
- data = arrData;
- }
- this.setData(data);
- }),
- mimetype: "text/json"
- });
- };
-
- this.startSearch = function(/*String*/ searchStr, /*String*/ type,
/*Boolean*/ ignoreLimit){
- // FIXME: need to add timeout handling here!!
- this._preformSearch(searchStr, type, ignoreLimit);
- };
-
- this._preformSearch = function(/*String*/ searchStr, /*String*/ type,
/*Boolean*/ ignoreLimit){
- //
- // NOTE: this search is LINEAR, which means that it exhibits perhaps
- // the worst possible speed characteristics of any search type. It's
- // written this way to outline the responsibilities and interfaces for
- // a search.
- //
- var st = type||this.searchType;
- // FIXME: this is just an example search, which means that we implement
- // only a linear search without any of the attendant (useful!)
optimizations
- var ret = [];
- if(!this.caseSensitive){
- searchStr = searchStr.toLowerCase();
- }
- for(var x=0; x<this.data.length; x++){
- if((!ignoreLimit)&&(ret.length >= this.searchLimit)){
- break;
- }
- // FIXME: we should avoid copies if possible!
- var dataLabel = new String((!this.caseSensitive) ?
this.data[x][0].toLowerCase() : this.data[x][0]);
- if(dataLabel.length < searchStr.length){
- // this won't ever be a good search, will it? What if we start
- // to support regex search?
- continue;
- }
-
- if(st == "STARTSTRING"){
- if(searchStr == dataLabel.substr(0, searchStr.length)){
- ret.push(this.data[x]);
- }
- }else if(st == "SUBSTRING"){
- // this one is a gimmie
- if(dataLabel.indexOf(searchStr) >= 0){
- ret.push(this.data[x]);
- }
- }else if(st == "STARTWORD"){
- // do a substring search and then attempt to determine if the
- // preceeding char was the beginning of the string or a
- // whitespace char.
- var idx = dataLabel.indexOf(searchStr);
- if(idx == 0){
- // implicit match
- ret.push(this.data[x]);
- }
- if(idx <= 0){
- // if we didn't match or implicily matched, march onward
- continue;
- }
- // otherwise, we have to go figure out if the match was at the
- // start of a word...
- // this code is taken almost directy from nWidgets
- var matches = false;
- while(idx!=-1){
- // make sure the match either starts whole string, or
- // follows a space, or follows some punctuation
- if(" ,/(".indexOf(dataLabel.charAt(idx-1)) != -1){
- // FIXME: what about tab chars?
- matches = true; break;
- }
- idx = dataLabel.indexOf(searchStr, idx+1);
- }
- if(!matches){
- continue;
- }else{
- ret.push(this.data[x]);
- }
- }
- }
- this.provideSearchResults(ret);
- };
-
- this.provideSearchResults = function(/*Array*/ resultsDataPairs){
- };
-
- this.addData = function(/*Array*/ pairs){
- // FIXME: incredibly naive and slow!
- this.data = this.data.concat(pairs);
- };
-
- this.setData = function(/*Array*/ pdata){
- // populate this.data and initialize lookup structures
- this.data = pdata;
- };
-
- if(dataPairs){
- this.setData(dataPairs);
- }
-};
-
-dojo.widget.defineWidget(
- "struts.widget.ComboBox",
- dojo.widget.ComboBox, {
- widgetType : "ComboBox",
-
- dropdownHeight: 120,
- dropdownWidth: 0,
- itemHeight: 0,
-
- refreshListenTopic : "",
- onValueChangedPublishTopic : "",
-
- //callbacks
- beforeLoading : "",
- afterLoading : "",
-
- formId : "",
- formFilter : "",
- dataProviderClass: "struts.widget.ComboBoxDataProvider",
- //from Dojo's ComboBox
- showResultList: function() {
- // Our dear friend IE doesnt take max-height so we need to calculate that on
our own every time
- var childs = this.optionsListNode.childNodes;
- if(childs.length){
-
- this.optionsListNode.style.width = this.dropdownWidth === 0 ?
(dojo.html.getMarginBox(this.domNode).width-2)+"px" : this.dropdownWidth + "px";
-
- if(this.itemHeight === 0 ||
dojo.string.isBlank(this.textInputNode.value)) {
- this.optionsListNode.style.height = this.dropdownHeight + "px";
- this.optionsListNode.style.display = "";
- this.itemHeight = dojo.html.getMarginBox(childs[0]).height;
- }
-
- //if there is extra space, adjust height
- var totalHeight = this.itemHeight * childs.length;
- if(totalHeight < this.dropdownHeight) {
- this.optionsListNode.style.height = totalHeight + 2 + "px";
- }
-
- this.popupWidget.open(this.domNode, this, this.downArrowNode);
- } else {
- this.hideResultList();
- }
- },
-
- openResultList: function(/*Array*/ results){
- if (!this.isEnabled){
- return;
- }
- this.clearResultList();
- if(!results.length){
- this.hideResultList();
- }
-
- if( (this.autoComplete)&&
- (results.length)&&
- (!this._prev_key_backspace)&&
- (this.textInputNode.value.length > 0)){
- var cpos = this.getCaretPos(this.textInputNode);
- // only try to extend if we added the last character at the end of the
input
- if((cpos+1) > this.textInputNode.value.length){
- // only add to input node as we would overwrite Capitalisation of
chars
- this.textInputNode.value += results[0][0].substr(cpos);
- // build a new range that has the distance from the earlier
- // caret position to the end of the first string selected
- this.setSelectedRange(this.textInputNode, cpos,
this.textInputNode.value.length);
- }
- }
- var typedText = this.textInputNode.value;
- var even = true;
- while(results.length){
- var tr = results.shift();
- if(tr){
- var td = document.createElement("div");
- var text = tr[0];
- var i = text.toLowerCase().indexOf(typedText.toLowerCase());
- if(i >= 0) {
- var pre = text.substring(0, i);
- var matched = text.substring(i, typedText.length);
- var post = text.substring(i + typedText.length);
-
- td.appendChild(document.createTextNode(pre));
- var boldNode = document.createElement("b");
- td.appendChild(boldNode);
- boldNode.appendChild(document.createTextNode(matched));
- td.appendChild(document.createTextNode(post));
- } else {
- td.appendChild(document.createTextNode(tr[0]));
- }
-
- td.setAttribute("resultName", tr[0]);
- td.setAttribute("resultValue", tr[1]);
- td.className = "dojoComboBoxItem "+((even) ?
"dojoComboBoxItemEven" : "dojoComboBoxItemOdd");
- even = (!even);
- this.optionsListNode.appendChild(td);
- }
- }
-
- // show our list (only if we have content, else nothing)
- this.showResultList();
- },
-
- postCreate : function() {
- struts.widget.ComboBox.superclass.postCreate.apply(this);
-
- //events
- if(!dojo.string.isBlank(this.refreshListenTopic)) {
- var self = this;
- dojo.event.topic.subscribe(this.refreshListenTopic, function() {
- self.dataProvider.getData(self.dataUrl);
- });
- }
- if(!dojo.string.isBlank(this.onValueChangedPublishTopic)) {
- dojo.event.topic.registerPublisher(this.onValueChangedPublishTopic,
this, "onValueChanged");
- }
- }
-});