Changeset 11933
- Timestamp:
- 01/02/08 03:39:13 (8 months ago)
- Location:
- dijit/trunk/form
- Files:
-
- 2 modified
-
ComboBox.js (modified) (30 diffs)
-
FilteringSelect.js (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
dijit/trunk/form/ComboBox.js
r11913 r11933 170 170 var doSearch = false; 171 171 this.item = null; // #4872 172 if(this._isShowingNow){this._popupWidget.handleKey(evt);} 172 var pw = this._popupWidget; 173 var dk = dojo.keys; 174 if(this._isShowingNow){ 175 pw.handleKey(evt); 176 } 173 177 switch(evt.keyCode){ 174 case d ojo.keys.PAGE_DOWN:175 case d ojo.keys.DOWN_ARROW:178 case dk.PAGE_DOWN: 179 case dk.DOWN_ARROW: 176 180 if(!this._isShowingNow||this._prev_key_esc){ 177 181 this._arrowPressed(); 178 182 doSearch=true; 179 183 }else{ 180 this._announceOption( this._popupWidget.getHighlightedOption());184 this._announceOption(pw.getHighlightedOption()); 181 185 } 182 186 dojo.stopEvent(evt); … … 185 189 break; 186 190 187 case d ojo.keys.PAGE_UP:188 case d ojo.keys.UP_ARROW:191 case dk.PAGE_UP: 192 case dk.UP_ARROW: 189 193 if(this._isShowingNow){ 190 this._announceOption( this._popupWidget.getHighlightedOption());194 this._announceOption(pw.getHighlightedOption()); 191 195 } 192 196 dojo.stopEvent(evt); … … 195 199 break; 196 200 197 case dojo.keys.ENTER: 198 // prevent submitting form if user presses enter 199 // also prevent accepting the value if either Next or Previous are selected 201 case dk.ENTER: 202 // prevent submitting form if user presses enter. Also 203 // prevent accepting the value if either Next or Previous 204 // are selected 200 205 var highlighted; 201 if(this._isShowingNow&&(highlighted=this._popupWidget.getHighlightedOption())){ 206 if( this._isShowingNow && 207 (highlighted = pw.getHighlightedOption()) 208 ){ 202 209 // only stop event on prev/next 203 if(highlighted ==this._popupWidget.nextButton){210 if(highlighted == pw.nextButton){ 204 211 this._nextSearch(1); 205 212 dojo.stopEvent(evt); 206 213 break; 207 } 208 else if(highlighted==this._popupWidget.previousButton){ 214 }else if(highlighted == pw.previousButton){ 209 215 this._nextSearch(-1); 210 216 dojo.stopEvent(evt); … … 219 225 // fall through 220 226 221 case dojo.keys.TAB: 222 var newvalue=this.getDisplayedValue(); 223 // #4617: if the user had More Choices selected fall into the _onBlur handler 224 if(this._popupWidget && 225 (newvalue == this._popupWidget._messages["previousMessage"] || 226 newvalue == this._popupWidget._messages["nextMessage"])){ 227 case dk.TAB: 228 var newvalue = this.getDisplayedValue(); 229 // #4617: 230 // if the user had More Choices selected fall into the 231 // _onBlur handler 232 if(pw && ( 233 newvalue == pw._messages["previousMessage"] || 234 newvalue == pw._messages["nextMessage"]) 235 ){ 227 236 break; 228 237 } … … 230 239 this._prev_key_backspace = false; 231 240 this._prev_key_esc = false; 232 if( this._popupWidget.getHighlightedOption()){233 this._popupWidget.setValue({target:this._popupWidget.getHighlightedOption()}, true);241 if(pw.getHighlightedOption()){ 242 pw.setValue({ target: pw.getHighlightedOption() }, true); 234 243 } 235 244 this._hideResultList(); … … 237 246 break; 238 247 239 case d ojo.keys.SPACE:248 case dk.SPACE: 240 249 this._prev_key_backspace = false; 241 250 this._prev_key_esc = false; 242 if(this._isShowingNow && this._popupWidget.getHighlightedOption()){251 if(this._isShowingNow && pw.getHighlightedOption()){ 243 252 dojo.stopEvent(evt); 244 253 this._selectOption(); … … 249 258 break; 250 259 251 case d ojo.keys.ESCAPE:260 case dk.ESCAPE: 252 261 this._prev_key_backspace = false; 253 262 this._prev_key_esc = true; … … 261 270 break; 262 271 263 case d ojo.keys.DELETE:264 case d ojo.keys.BACKSPACE:272 case dk.DELETE: 273 case dk.BACKSPACE: 265 274 this._prev_key_esc = false; 266 275 this._prev_key_backspace = true; … … 268 277 break; 269 278 270 case dojo.keys.RIGHT_ARROW: // fall through 271 272 case dojo.keys.LEFT_ARROW: // fall through 279 case dk.RIGHT_ARROW: // fall through 280 case dk.LEFT_ARROW: 273 281 this._prev_key_backspace = false; 274 282 this._prev_key_esc = false; 275 283 break; 276 284 277 default: // non char keys (F1-F12 etc..) shouldn't open list285 default: // non char keys (F1-F12 etc..) shouldn't open list 278 286 this._prev_key_backspace = false; 279 287 this._prev_key_esc = false; 280 288 if(dojo.isIE || evt.charCode != 0){ 281 doSearch =true;289 doSearch = true; 282 290 } 283 291 } … … 286 294 } 287 295 if(doSearch){ 288 // need to wait a tad before start search so that the event bubbles through DOM and we have value visible 289 this.searchTimer = setTimeout(dojo.hitch(this, this._startSearchFromInput), this.searchDelay); 296 // need to wait a tad before start search so that the event 297 // bubbles through DOM and we have value visible 298 this.searchTimer = setTimeout(dojo.hitch(this, "_startSearchFromInput"), this.searchDelay); 290 299 } 291 300 }, … … 293 302 _autoCompleteText: function(/*String*/ text){ 294 303 // summary: 295 // Fill in the textbox with the first item from the drop down list, and 296 // highlight the characters that were auto-completed. For example, if user 297 // typed "CA" and the drop down list appeared, the textbox would be changed to 298 // "California" and "ifornia" would be highlighted. 304 // Fill in the textbox with the first item from the drop down 305 // list, and highlight the characters that were 306 // auto-completed. For example, if user typed "CA" and the 307 // drop down list appeared, the textbox would be changed to 308 // "California" and "ifornia" would be highlighted. 309 310 var fn = this.focusNode; 299 311 300 312 // IE7: clear selection so next highlight works all the time 301 this._setSelectedRange( this.focusNode, this.focusNode.value.length, this.focusNode.value.length);313 this._setSelectedRange( fn, fn.value.length, fn.value.length); 302 314 // does text autoComplete the value in the textbox? 303 315 // #3744: escape regexp so the user's input isn't treated as a regular expression. 304 316 // Example: If the user typed "(" then the regexp would throw "unterminated parenthetical." 305 317 // Also see #2558 for the autocompletion bug this regular expression fixes. 306 if(new RegExp("^"+escape(this.focusNode.value), this.ignoreCase ? "i" : "").test(escape(text))){ 307 var cpos = this._getCaretPos(this.focusNode); 318 var re = new RegExp("^"+escape(fn.value), this.ignoreCase ? "i" : ""); 319 if(re.test(escape(text))){ 320 var cpos = this._getCaretPos(fn); 308 321 // only try to extend if we added the last character at the end of the input 309 if((cpos+1) > this.focusNode.value.length){322 if((cpos+1) > fn.value.length){ 310 323 // only add to input node as we would overwrite Capitalisation of chars 311 324 // actually, that is ok 312 this.focusNode.value = text;//.substr(cpos);325 fn.value = text;//.substr(cpos); 313 326 // visually highlight the autocompleted characters 314 this._setSelectedRange( this.focusNode, cpos, this.focusNode.value.length);315 dijit.setWaiState( this.focusNode, "valuenow", text);327 this._setSelectedRange(fn, cpos, fn.value.length); 328 dijit.setWaiState(fn, "valuenow", text); 316 329 } 317 330 }else{ 318 331 // text does not autoComplete; replace the whole value and highlight 319 this.focusNode.value = text;320 this._setSelectedRange( this.focusNode, 0, this.focusNode.value.length);321 dijit.setWaiState( this.focusNode, "valuenow", text);332 fn.value = text; 333 this._setSelectedRange(fn, 0, fn.value.length); 334 dijit.setWaiState(fn, "valuenow", text); 322 335 } 323 336 }, 324 337 325 338 _openResultList: function(/*Object*/ results, /*Object*/ dataObject){ 326 if(this.disabled || this.readOnly || dataObject.query[this.searchAttr] != this._lastQuery){ 339 if( this.disabled || 340 this.readOnly || 341 (dataObject.query[this.searchAttr] != this._lastQuery) 342 ){ 327 343 return; 328 344 } … … 333 349 } 334 350 335 // Fill in the textbox with the first item from the drop down list, and 336 // highlight the characters that were auto-completed. For example, if user 337 // typed "CA" and the drop down list appeared, the textbox would be changed to 338 // "California" and "ifornia" would be highlighted. 339 340 var zerothvalue=new String(this.store.getValue(results[0], this.searchAttr)); 351 // Fill in the textbox with the first item from the drop down list, 352 // and highlight the characters that were auto-completed. For 353 // example, if user typed "CA" and the drop down list appeared, the 354 // textbox would be changed to "California" and "ifornia" would be 355 // highlighted. 356 357 var zerothvalue = new String(this.store.getValue(results[0], this.searchAttr)); 341 358 if(zerothvalue && this.autoComplete && !this._prev_key_backspace && 342 // when the user clicks the arrow button to show the full list,343 // startSearch looks for "*".344 // it does not make sense to autocomplete345 // if they are just previewing the options available.346 359 (dataObject.query[this.searchAttr] != "*")){ 360 // when the user clicks the arrow button to show the full list, 361 // startSearch looks for "*". 362 // it does not make sense to autocomplete 363 // if they are just previewing the options available. 347 364 this._autoCompleteText(zerothvalue); 348 365 // announce the autocompleted value 349 dijit.setWaiState(this.focusNode || this.domNode, "valuenow", zerothvalue); 350 } 351 this._popupWidget.createOptions(results, dataObject, dojo.hitch(this, this._getMenuLabelFromItem)); 366 dijit.setWaiState((this.focusNode || this.domNode), "valuenow", zerothvalue); 367 } 368 this._popupWidget.createOptions( 369 results, 370 dataObject, 371 dojo.hitch(this, "_getMenuLabelFromItem") 372 ); 352 373 353 374 // show our list (only if we have content, else nothing) 354 375 this._showResultList(); 355 376 356 // #4091: tell the screen reader that the paging callback finished by shouting the next choice 377 // #4091: 378 // tell the screen reader that the paging callback finished by 379 // shouting the next choice 357 380 if(dataObject.direction){ 358 if( dataObject.direction==1){381 if(1 == dataObject.direction){ 359 382 this._popupWidget.highlightFirstOption(); 360 }else if( dataObject.direction==-1){383 }else if(-1 == dataObject.direction){ 361 384 this._popupWidget.highlightLastOption(); 362 385 } … … 375 398 // Position the list and if it's too big to fit on the screen then 376 399 // size it to the maximum possible height 377 // Our dear friend IE doesnt take max-height so we need to calculate that on our own every time 378 // TODO: want to redo this, see http://trac.dojotoolkit.org/ticket/3272, http://trac.dojotoolkit.org/ticket/4108 400 // Our dear friend IE doesnt take max-height so we need to 401 // calculate that on our own every time 402 403 // TODO: want to redo this, see 404 // http://trac.dojotoolkit.org/ticket/3272 405 // and 406 // http://trac.dojotoolkit.org/ticket/4108 407 379 408 with(this._popupWidget.domNode.style){ 380 // natural size of the list has changed, so erase old width/height settings, 381 // which were hardcoded in a previous call to this function (via dojo.marginBox() call) 382 width=""; 383 height=""; 384 } 385 var best=this.open(); 386 // #3212: only set auto scroll bars if necessary 387 // prevents issues with scroll bars appearing when they shouldn't when node is made wider (fractional pixels cause this) 388 var popupbox=dojo.marginBox(this._popupWidget.domNode); 389 this._popupWidget.domNode.style.overflow=((best.h==popupbox.h)&&(best.w==popupbox.w))?"hidden":"auto"; 390 // #4134: borrow TextArea scrollbar test so content isn't covered by scrollbar and horizontal scrollbar doesn't appear 391 var newwidth=best.w; 392 if(best.h<this._popupWidget.domNode.scrollHeight){newwidth+=16;} 393 dojo.marginBox(this._popupWidget.domNode, {h:best.h,w:Math.max(newwidth,this.domNode.offsetWidth)}); 409 // natural size of the list has changed, so erase old 410 // width/height settings, which were hardcoded in a previous 411 // call to this function (via dojo.marginBox() call) 412 width = ""; 413 height = ""; 414 } 415 var best = this.open(); 416 // #3212: 417 // only set auto scroll bars if necessary prevents issues with 418 // scroll bars appearing when they shouldn't when node is made 419 // wider (fractional pixels cause this) 420 var popupbox = dojo.marginBox(this._popupWidget.domNode); 421 this._popupWidget.domNode.style.overflow = 422 ((best.h==popupbox.h)&&(best.w==popupbox.w)) ? "hidden" : "auto"; 423 // #4134: 424 // borrow TextArea scrollbar test so content isn't covered by 425 // scrollbar and horizontal scrollbar doesn't appear 426 var newwidth = best.w; 427 if(best.h < this._popupWidget.domNode.scrollHeight){ 428 newwidth += 16; 429 } 430 dojo.marginBox(this._popupWidget.domNode, { 431 h: best.h, 432 w: Math.max(newwidth, this.domNode.offsetWidth) 433 }); 394 434 }, 395 435 … … 408 448 this._hideResultList(); 409 449 this._arrowIdle(); 410 // if the user clicks away from the textbox OR tabs away, set the value to the textbox value 411 // #4617: if value is now more choices or previous choices, revert the value 450 // if the user clicks away from the textbox OR tabs away, set the 451 // value to the textbox value 452 453 // #4617: 454 // if value is now more choices or previous choices, revert 455 // the value 412 456 var newvalue=this.getDisplayedValue(); 413 if(this._popupWidget&&(newvalue==this._popupWidget._messages["previousMessage"]||newvalue==this._popupWidget._messages["nextMessage"])){ 457 var pw = this._popupWidget; 458 if( pw && ( 459 newvalue == pw._messages["previousMessage"] || 460 newvalue == pw._messages["nextMessage"] 461 ) 462 ){ 414 463 this.setValue(this._lastValueReported, true); 415 464 }else{ … … 427 476 _announceOption: function(/*Node*/ node){ 428 477 // summary: 429 // a11y code that puts the highlighted option in the textbox 430 // This way screen readers will know what is happening in the menu 431 432 if(node==null){return;} 478 // a11y code that puts the highlighted option in the textbox 479 // This way screen readers will know what is happening in the 480 // menu 481 482 if(node == null){ 483 return; 484 } 433 485 // pull the text value from the item attached to the DOM node 434 486 var newValue; 435 if(node==this._popupWidget.nextButton||node==this._popupWidget.previousButton){ 436 newValue=node.innerHTML; 487 if( node == this._popupWidget.nextButton || 488 node == this._popupWidget.previousButton){ 489 newValue = node.innerHTML; 437 490 }else{ 438 newValue =this.store.getValue(node.item, this.searchAttr);491 newValue = this.store.getValue(node.item, this.searchAttr); 439 492 } 440 493 // get the text that the user manually entered (cut off autocompleted text) 441 this.focusNode.value =this.focusNode.value.substring(0, this._getCaretPos(this.focusNode));494 this.focusNode.value = this.focusNode.value.substring(0, this._getCaretPos(this.focusNode)); 442 495 // autocomplete the rest of the option to announce change 443 496 this._autoCompleteText(newValue); … … 460 513 if(!evt.noHide){ 461 514 this._hideResultList(); 462 this._setCaretPos(this.focusNode, this.store.getValue(tgt.item, this.searchAttr).length); 515 this._setCaretPos( 516 this.focusNode, 517 this.store.getValue(tgt.item, this.searchAttr).length 518 ); 463 519 } 464 520 this._doSelect(tgt); … … 500 556 }); 501 557 } 502 // create a new query to prevent accidentally querying for a hidden value from FilteringSelect's keyField 503 var query=this.query; 504 this._lastQuery=query[this.searchAttr] = this._getQueryString(key); 505 var dataObject=this.store.fetch({queryOptions:{ignoreCase:this.ignoreCase, deep:true}, query: query, onComplete:dojo.hitch(this, "_openResultList"), start:0, count:this.pageSize}); 506 function nextSearch(dataObject, direction){ 507 dataObject.start+=dataObject.count*direction; 508 // #4091: tell callback the direction of the paging so the screen reader knows which menu option to shout 509 dataObject.direction=direction; 558 // create a new query to prevent accidentally querying for a hidden 559 // value from FilteringSelect's keyField 560 var query = this.query; 561 this._lastQuery = query[this.searchAttr] = this._getQueryString(key); 562 var dataObject = this.store.fetch({ 563 queryOptions: { 564 ignoreCase: this.ignoreCase, 565 deep: true 566 }, 567 query: query, 568 onComplete: dojo.hitch(this, "_openResultList"), 569 start:0, 570 count:this.pageSize 571 }); 572 573 var nextSearch = function(dataObject, direction){ 574 dataObject.start += dataObject.count*direction; 575 // #4091: 576 // tell callback the direction of the paging so the screen 577 // reader knows which menu option to shout 578 dataObject.direction = direction; 510 579 dataObject.store.fetch(dataObject); 511 580 } 512 this._nextSearch =this._popupWidget.onPage=dojo.hitch(this, nextSearch, dataObject);581 this._nextSearch = this._popupWidget.onPage = dojo.hitch(this, nextSearch, dataObject); 513 582 }, 514 583 … … 531 600 }, 532 601 602 // FIXME: 603 // this is public so we can't remove until 2.0, but the name 604 // SHOULD be "compositionEnd" 533 605 compositionend: function(/*Event*/ evt){ 534 // summary: When inputting characters using an input method, such as Asian 535 // languages, it will generate this event instead of onKeyDown event 536 // Note: this event is only triggered in FF (not in IE) 606 // summary: 607 // When inputting characters using an input method, such as 608 // Asian languages, it will generate this event instead of 609 // onKeyDown event Note: this event is only triggered in FF 610 // (not in IE) 537 611 this.onkeypress({charCode:-1}); 538 612 }, … … 548 622 } 549 623 if(!this.store){ 624 var srcNodeRef = this.srcNodeRef; 550 625 // if user didn't specify store, then assume there are option tags 551