Page Menu
Home
Code
Search
Configure Global Search
Log In
Files
F947751
ComboBox.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
29 KB
Subscribers
None
ComboBox.js
View Options
if
(
!
dojo
.
_hasResource
[
"dijit.form.ComboBox"
]){
//_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo
.
_hasResource
[
"dijit.form.ComboBox"
]
=
true
;
dojo
.
provide
(
"dijit.form.ComboBox"
);
dojo
.
require
(
"dojo.data.ItemFileReadStore"
);
dojo
.
require
(
"dijit.form.ValidationTextBox"
);
dojo
.
requireLocalization
(
"dijit.form"
,
"ComboBox"
,
null
,
"ko,zh,ja,zh-tw,ru,it,hu,ROOT,fr,pt,pl,es,de,cs"
);
dojo
.
declare
(
"dijit.form.ComboBoxMixin"
,
null
,
{
// summary:
// Auto-completing text box, and base class for FilteringSelect widget.
//
// The drop down box's values are populated from an class called
// a data provider, which returns a list of values based on the characters
// that the user has typed into the input box.
//
// Some of the options to the ComboBox are actually arguments to the data
// provider.
//
// You can assume that all the form widgets (and thus anything that mixes
// in ComboBoxMixin) will inherit from _FormWidget and thus the "this"
// reference will also "be a" _FormWidget.
// item: Object
// This is the item returned by the dojo.data.store implementation that
// provides the data for this cobobox, it's the currently selected item.
item
:
null
,
// pageSize: Integer
// Argument to data provider.
// Specifies number of search results per page (before hitting "next" button)
pageSize
:
Infinity
,
// store: Object
// Reference to data provider object used by this ComboBox
store
:
null
,
// query: Object
// A query that can be passed to 'store' to initially filter the items,
// before doing further filtering based on searchAttr and the key.
query
:
{},
// autoComplete: Boolean
// If you type in a partial string, and then tab out of the <input> box,
// automatically copy the first entry displayed in the drop down list to
// the <input> field
autoComplete
:
true
,
// searchDelay: Integer
// Delay in milliseconds between when user types something and we start
// searching based on that value
searchDelay
:
100
,
// searchAttr: String
// Searches pattern match against this field
searchAttr
:
"name"
,
// ignoreCase: Boolean
// Set true if the ComboBox should ignore case when matching possible items
ignoreCase
:
true
,
// hasDownArrow: Boolean
// Set this textbox to have a down arrow button.
// Defaults to true.
hasDownArrow
:
true
,
// _hasFocus: Boolean
// Represents focus state of the textbox
// TODO: get rid of this; it's unnecessary (but currently referenced in FilteringSelect)
_hasFocus
:
false
,
templateString
:
"<table class=\"dijit dijitReset dijitInlineTable dijitLeft\" cellspacing=\"0\" cellpadding=\"0\"\n\tid=\"widget_${id}\" name=\"${name}\" dojoAttachEvent=\"onmouseenter:_onMouse,onmouseleave:_onMouse\" waiRole=\"presentation\"\n\t><tr class=\"dijitReset\"\n\t\t><td class='dijitReset dijitStretch dijitInputField' width=\"100%\"\n\t\t\t><input type=\"text\" autocomplete=\"off\" name=\"${name}\"\n\t\t\tdojoAttachEvent=\"onkeypress, onkeyup, onfocus, compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" waiRole=\"combobox\"\n\t\t/></td\n\t\t><td class=\"dijitReset dijitValidationIconField\" width=\"0%\"\n\t\t\t><div dojoAttachPoint='iconNode' class='dijitValidationIcon'></div\n\t\t\t><div class='dijitValidationIconText'>Χ</div\n\t\t></td\n\t\t><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton' width=\"0%\"\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\tdojoAttachEvent=\"onmousedown:_onArrowMouseDown,onmouseup:_onMouse,onmouseenter:_onMouse,onmouseleave:_onMouse\"\n\t\t\t><div class=\"dijitDownArrowButtonInner\" waiRole=\"presentation\"\n\t\t\t\t><div class=\"dijitDownArrowButtonChar\">▼</div\n\t\t\t></div\n\t\t></td\t\n\t></tr\n></table>\n"
,
baseClass
:
"dijitComboBox"
,
_lastDisplayedValue
:
""
,
getValue
:
function
(){
// don't get the textbox value but rather the previously set hidden value
return
dijit
.
form
.
TextBox
.
superclass
.
getValue
.
apply
(
this
,
arguments
);
},
setDisplayedValue
:
function
(
/*String*/
value
){
this
.
_lastDisplayedValue
=
value
;
this
.
setValue
(
value
,
true
);
},
_getCaretPos
:
function
(
/*DomNode*/
element
){
// khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
if
(
typeof
(
element
.
selectionStart
)
==
"number"
){
// FIXME: this is totally borked on Moz < 1.3. Any recourse?
return
element
.
selectionStart
;
}
else
if
(
dojo
.
isIE
){
// in the case of a mouse click in a popup being handled,
// then the document.selection is not the textarea, but the popup
// var r = document.selection.createRange();
// hack to get IE 6 to play nice. What a POS browser.
var
tr
=
document
.
selection
.
createRange
().
duplicate
();
var
ntr
=
element
.
createTextRange
();
tr
.
move
(
"character"
,
0
);
ntr
.
move
(
"character"
,
0
);
try
{
// If control doesnt have focus, you get an exception.
// Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
// There appears to be no workaround for this - googled for quite a while.
ntr
.
setEndPoint
(
"EndToEnd"
,
tr
);
return
String
(
ntr
.
text
).
replace
(
/\r/g
,
""
).
length
;
}
catch
(
e
){
return
0
;
// If focus has shifted, 0 is fine for caret pos.
}
}
},
_setCaretPos
:
function
(
/*DomNode*/
element
,
/*Number*/
location
){
location
=
parseInt
(
location
);
this
.
_setSelectedRange
(
element
,
location
,
location
);
},
_setSelectedRange
:
function
(
/*DomNode*/
element
,
/*Number*/
start
,
/*Number*/
end
){
if
(
!
end
){
end
=
element
.
value
.
length
;
}
// NOTE: Strange - should be able to put caret at start of text?
// Mozilla
// parts borrowed from http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130
if
(
element
.
setSelectionRange
){
dijit
.
focus
(
element
);
element
.
setSelectionRange
(
start
,
end
);
}
else
if
(
element
.
createTextRange
){
// IE
var
range
=
element
.
createTextRange
();
with
(
range
){
collapse
(
true
);
moveEnd
(
'character'
,
end
);
moveStart
(
'character'
,
start
);
select
();
}
}
else
{
//otherwise try the event-creation hack (our own invention)
// do we need these?
element
.
value
=
element
.
value
;
element
.
blur
();
dijit
.
focus
(
element
);
// figure out how far back to go
var
dist
=
parseInt
(
element
.
value
.
length
)
-
end
;
var
tchar
=
String
.
fromCharCode
(
37
);
var
tcc
=
tchar
.
charCodeAt
(
0
);
for
(
var
x
=
0
;
x
<
dist
;
x
++
){
var
te
=
document
.
createEvent
(
"KeyEvents"
);
te
.
initKeyEvent
(
"keypress"
,
true
,
true
,
null
,
false
,
false
,
false
,
false
,
tcc
,
tcc
);
element
.
dispatchEvent
(
te
);
}
}
},
onkeypress
:
function
(
/*Event*/
evt
){
// summary: handles keyboard events
//except for pasting case - ctrl + v(118)
if
(
evt
.
altKey
||
(
evt
.
ctrlKey
&&
evt
.
charCode
!=
118
)){
return
;
}
var
doSearch
=
false
;
this
.
item
=
null
;
// #4872
if
(
this
.
_isShowingNow
){
this
.
_popupWidget
.
handleKey
(
evt
);}
switch
(
evt
.
keyCode
){
case
dojo
.
keys
.
PAGE_DOWN
:
case
dojo
.
keys
.
DOWN_ARROW
:
if
(
!
this
.
_isShowingNow
||
this
.
_prev_key_esc
){
this
.
_arrowPressed
();
doSearch
=
true
;
}
else
{
this
.
_announceOption
(
this
.
_popupWidget
.
getHighlightedOption
());
}
dojo
.
stopEvent
(
evt
);
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
false
;
break
;
case
dojo
.
keys
.
PAGE_UP
:
case
dojo
.
keys
.
UP_ARROW
:
if
(
this
.
_isShowingNow
){
this
.
_announceOption
(
this
.
_popupWidget
.
getHighlightedOption
());
}
dojo
.
stopEvent
(
evt
);
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
false
;
break
;
case
dojo
.
keys
.
ENTER
:
// prevent submitting form if user presses enter
// also prevent accepting the value if either Next or Previous are selected
var
highlighted
;
if
(
this
.
_isShowingNow
&&
(
highlighted
=
this
.
_popupWidget
.
getHighlightedOption
())){
// only stop event on prev/next
if
(
highlighted
==
this
.
_popupWidget
.
nextButton
){
this
.
_nextSearch
(
1
);
dojo
.
stopEvent
(
evt
);
break
;
}
else
if
(
highlighted
==
this
.
_popupWidget
.
previousButton
){
this
.
_nextSearch
(
-
1
);
dojo
.
stopEvent
(
evt
);
break
;
}
}
else
{
this
.
setDisplayedValue
(
this
.
getDisplayedValue
());
}
// default case:
// prevent submit, but allow event to bubble
evt
.
preventDefault
();
// fall through
case
dojo
.
keys
.
TAB
:
var
newvalue
=
this
.
getDisplayedValue
();
// #4617: if the user had More Choices selected fall into the _onBlur handler
if
(
this
.
_popupWidget
&&
(
newvalue
==
this
.
_popupWidget
.
_messages
[
"previousMessage"
]
||
newvalue
==
this
.
_popupWidget
.
_messages
[
"nextMessage"
])){
break
;
}
if
(
this
.
_isShowingNow
){
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
false
;
if
(
this
.
_popupWidget
.
getHighlightedOption
()){
this
.
_popupWidget
.
setValue
({
target
:
this
.
_popupWidget
.
getHighlightedOption
()},
true
);
}
this
.
_hideResultList
();
}
break
;
case
dojo
.
keys
.
SPACE
:
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
false
;
if
(
this
.
_isShowingNow
&&
this
.
_popupWidget
.
getHighlightedOption
()){
dojo
.
stopEvent
(
evt
);
this
.
_selectOption
();
this
.
_hideResultList
();
}
else
{
doSearch
=
true
;
}
break
;
case
dojo
.
keys
.
ESCAPE
:
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
true
;
this
.
_hideResultList
();
if
(
this
.
_lastDisplayedValue
!=
this
.
getDisplayedValue
()){
this
.
setDisplayedValue
(
this
.
_lastDisplayedValue
);
dojo
.
stopEvent
(
evt
);
}
else
{
this
.
setValue
(
this
.
getValue
(),
false
);
}
break
;
case
dojo
.
keys
.
DELETE
:
case
dojo
.
keys
.
BACKSPACE
:
this
.
_prev_key_esc
=
false
;
this
.
_prev_key_backspace
=
true
;
doSearch
=
true
;
break
;
case
dojo
.
keys
.
RIGHT_ARROW
:
// fall through
case
dojo
.
keys
.
LEFT_ARROW
:
// fall through
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
false
;
break
;
default
:
// non char keys (F1-F12 etc..) shouldn't open list
this
.
_prev_key_backspace
=
false
;
this
.
_prev_key_esc
=
false
;
if
(
dojo
.
isIE
||
evt
.
charCode
!=
0
){
doSearch
=
true
;
}
}
if
(
this
.
searchTimer
){
clearTimeout
(
this
.
searchTimer
);
}
if
(
doSearch
){
// need to wait a tad before start search so that the event bubbles through DOM and we have value visible
this
.
searchTimer
=
setTimeout
(
dojo
.
hitch
(
this
,
this
.
_startSearchFromInput
),
this
.
searchDelay
);
}
},
_autoCompleteText
:
function
(
/*String*/
text
){
// summary:
// Fill in the textbox with the first item from the drop down list, and
// highlight the characters that were auto-completed. For example, if user
// typed "CA" and the drop down list appeared, the textbox would be changed to
// "California" and "ifornia" would be highlighted.
// IE7: clear selection so next highlight works all the time
this
.
_setSelectedRange
(
this
.
focusNode
,
this
.
focusNode
.
value
.
length
,
this
.
focusNode
.
value
.
length
);
// does text autoComplete the value in the textbox?
// #3744: escape regexp so the user's input isn't treated as a regular expression.
// Example: If the user typed "(" then the regexp would throw "unterminated parenthetical."
// Also see #2558 for the autocompletion bug this regular expression fixes.
if
(
new
RegExp
(
"^"
+
escape
(
this
.
focusNode
.
value
),
this
.
ignoreCase
?
"i"
:
""
).
test
(
escape
(
text
))){
var
cpos
=
this
.
_getCaretPos
(
this
.
focusNode
);
// only try to extend if we added the last character at the end of the input
if
((
cpos
+
1
)
>
this
.
focusNode
.
value
.
length
){
// only add to input node as we would overwrite Capitalisation of chars
// actually, that is ok
this
.
focusNode
.
value
=
text
;
//.substr(cpos);
// visually highlight the autocompleted characters
this
.
_setSelectedRange
(
this
.
focusNode
,
cpos
,
this
.
focusNode
.
value
.
length
);
dijit
.
setWaiState
(
this
.
focusNode
,
"valuenow"
,
text
);
}
}
else
{
// text does not autoComplete; replace the whole value and highlight
this
.
focusNode
.
value
=
text
;
this
.
_setSelectedRange
(
this
.
focusNode
,
0
,
this
.
focusNode
.
value
.
length
);
dijit
.
setWaiState
(
this
.
focusNode
,
"valuenow"
,
text
);
}
},
_openResultList
:
function
(
/*Object*/
results
,
/*Object*/
dataObject
){
if
(
this
.
disabled
||
dataObject
.
query
[
this
.
searchAttr
]
!=
this
.
_lastQuery
){
return
;
}
this
.
_popupWidget
.
clearResultList
();
if
(
!
results
.
length
){
this
.
_hideResultList
();
return
;
}
// Fill in the textbox with the first item from the drop down list, and
// highlight the characters that were auto-completed. For example, if user
// typed "CA" and the drop down list appeared, the textbox would be changed to
// "California" and "ifornia" would be highlighted.
var
zerothvalue
=
new
String
(
this
.
store
.
getValue
(
results
[
0
],
this
.
searchAttr
));
if
(
zerothvalue
&&
this
.
autoComplete
&&
!
this
.
_prev_key_backspace
&&
// when the user clicks the arrow button to show the full list,
// startSearch looks for "*".
// it does not make sense to autocomplete
// if they are just previewing the options available.
(
dataObject
.
query
[
this
.
searchAttr
]
!=
"*"
)){
this
.
_autoCompleteText
(
zerothvalue
);
// announce the autocompleted value
dijit
.
setWaiState
(
this
.
focusNode
||
this
.
domNode
,
"valuenow"
,
zerothvalue
);
}
this
.
_popupWidget
.
createOptions
(
results
,
dataObject
,
dojo
.
hitch
(
this
,
this
.
_getMenuLabelFromItem
));
// show our list (only if we have content, else nothing)
this
.
_showResultList
();
// #4091: tell the screen reader that the paging callback finished by shouting the next choice
if
(
dataObject
.
direction
){
if
(
dataObject
.
direction
==
1
){
this
.
_popupWidget
.
highlightFirstOption
();
}
else
if
(
dataObject
.
direction
==-
1
){
this
.
_popupWidget
.
highlightLastOption
();
}
this
.
_announceOption
(
this
.
_popupWidget
.
getHighlightedOption
());
}
},
_showResultList
:
function
(){
this
.
_hideResultList
();
var
items
=
this
.
_popupWidget
.
getItems
(),
visibleCount
=
Math
.
min
(
items
.
length
,
this
.
maxListLength
);
this
.
_arrowPressed
();
// hide the tooltip
this
.
_displayMessage
(
""
);
// Position the list and if it's too big to fit on the screen then
// size it to the maximum possible height
// Our dear friend IE doesnt take max-height so we need to calculate that on our own every time
// TODO: want to redo this, see http://trac.dojotoolkit.org/ticket/3272, http://trac.dojotoolkit.org/ticket/4108
with
(
this
.
_popupWidget
.
domNode
.
style
){
// natural size of the list has changed, so erase old width/height settings,
// which were hardcoded in a previous call to this function (via dojo.marginBox() call)
width
=
""
;
height
=
""
;
}
var
best
=
this
.
open
();
// #3212: only set auto scroll bars if necessary
// prevents issues with scroll bars appearing when they shouldn't when node is made wider (fractional pixels cause this)
var
popupbox
=
dojo
.
marginBox
(
this
.
_popupWidget
.
domNode
);
this
.
_popupWidget
.
domNode
.
style
.
overflow
=
((
best
.
h
==
popupbox
.
h
)
&&
(
best
.
w
==
popupbox
.
w
))
?
"hidden"
:
"auto"
;
// #4134: borrow TextArea scrollbar test so content isn't covered by scrollbar and horizontal scrollbar doesn't appear
var
newwidth
=
best
.
w
;
if
(
best
.
h
<
this
.
_popupWidget
.
domNode
.
scrollHeight
){
newwidth
+=
16
;}
dojo
.
marginBox
(
this
.
_popupWidget
.
domNode
,
{
h
:
best
.
h
,
w
:
Math
.
max
(
newwidth
,
this
.
domNode
.
offsetWidth
)});
},
_hideResultList
:
function
(){
if
(
this
.
_isShowingNow
){
dijit
.
popup
.
close
(
this
.
_popupWidget
);
this
.
_arrowIdle
();
this
.
_isShowingNow
=
false
;
}
},
_onBlur
:
function
(){
// summary: called magically when focus has shifted away from this widget and it's dropdown
this
.
_hasFocus
=
false
;
this
.
_hasBeenBlurred
=
true
;
this
.
_hideResultList
();
this
.
_arrowIdle
();
// if the user clicks away from the textbox OR tabs away, set the value to the textbox value
// #4617: if value is now more choices or previous choices, revert the value
var
newvalue
=
this
.
getDisplayedValue
();
if
(
this
.
_popupWidget
&&
(
newvalue
==
this
.
_popupWidget
.
_messages
[
"previousMessage"
]
||
newvalue
==
this
.
_popupWidget
.
_messages
[
"nextMessage"
])){
this
.
setValue
(
this
.
_lastValueReported
,
true
);
}
else
{
this
.
setDisplayedValue
(
newvalue
);
}
},
onfocus
:
function
(
/*Event*/
evt
){
this
.
_hasFocus
=
true
;
// update styling to reflect that we are focused
this
.
_onMouse
(
evt
);
},
_announceOption
:
function
(
/*Node*/
node
){
// summary:
// a11y code that puts the highlighted option in the textbox
// This way screen readers will know what is happening in the menu
if
(
node
==
null
){
return
;}
// pull the text value from the item attached to the DOM node
var
newValue
;
if
(
node
==
this
.
_popupWidget
.
nextButton
||
node
==
this
.
_popupWidget
.
previousButton
){
newValue
=
node
.
innerHTML
;
}
else
{
newValue
=
this
.
store
.
getValue
(
node
.
item
,
this
.
searchAttr
);
}
// get the text that the user manually entered (cut off autocompleted text)
this
.
focusNode
.
value
=
this
.
focusNode
.
value
.
substring
(
0
,
this
.
_getCaretPos
(
this
.
focusNode
));
// autocomplete the rest of the option to announce change
this
.
_autoCompleteText
(
newValue
);
},
_selectOption
:
function
(
/*Event*/
evt
){
var
tgt
=
null
;
if
(
!
evt
){
evt
=
{
target
:
this
.
_popupWidget
.
getHighlightedOption
()};
}
// what if nothing is highlighted yet?
if
(
!
evt
.
target
){
// handle autocompletion where the the user has hit ENTER or TAB
this
.
setDisplayedValue
(
this
.
getDisplayedValue
());
return
;
// otherwise the user has accepted the autocompleted value
}
else
{
tgt
=
evt
.
target
;
}
if
(
!
evt
.
noHide
){
this
.
_hideResultList
();
this
.
_setCaretPos
(
this
.
focusNode
,
this
.
store
.
getValue
(
tgt
.
item
,
this
.
searchAttr
).
length
);
}
this
.
_doSelect
(
tgt
);
},
_doSelect
:
function
(
tgt
){
this
.
item
=
tgt
.
item
;
this
.
setValue
(
this
.
store
.
getValue
(
tgt
.
item
,
this
.
searchAttr
),
true
);
},
_onArrowMouseDown
:
function
(
evt
){
// summary: callback when arrow is clicked
if
(
this
.
disabled
){
return
;
}
dojo
.
stopEvent
(
evt
);
this
.
focus
();
if
(
this
.
_isShowingNow
){
this
.
_hideResultList
();
}
else
{
// forces full population of results, if they click
// on the arrow it means they want to see more options
this
.
_startSearch
(
""
);
}
},
_startSearchFromInput
:
function
(){
this
.
_startSearch
(
this
.
focusNode
.
value
);
},
_startSearch
:
function
(
/*String*/
key
){
if
(
!
this
.
_popupWidget
){
this
.
_popupWidget
=
new
dijit
.
form
.
_ComboBoxMenu
({
onChange
:
dojo
.
hitch
(
this
,
this
.
_selectOption
)
});
}
// create a new query to prevent accidentally querying for a hidden value from FilteringSelect's keyField
var
query
=
this
.
query
;
this
.
_lastQuery
=
query
[
this
.
searchAttr
]
=
key
+
"*"
;
var
dataObject
=
this
.
store
.
fetch
({
queryOptions
:
{
ignoreCase
:
this
.
ignoreCase
,
deep
:
true
},
query
:
query
,
onComplete
:
dojo
.
hitch
(
this
,
"_openResultList"
),
start
:
0
,
count
:
this
.
pageSize
});
function
nextSearch
(
dataObject
,
direction
){
dataObject
.
start
+=
dataObject
.
count
*
direction
;
// #4091: tell callback the direction of the paging so the screen reader knows which menu option to shout
dataObject
.
direction
=
direction
;
dataObject
.
store
.
fetch
(
dataObject
);
}
this
.
_nextSearch
=
this
.
_popupWidget
.
onPage
=
dojo
.
hitch
(
this
,
nextSearch
,
dataObject
);
},
_getValueField
:
function
(){
return
this
.
searchAttr
;
},
/////////////// Event handlers /////////////////////
_arrowPressed
:
function
(){
if
(
!
this
.
disabled
&&
this
.
hasDownArrow
){
dojo
.
addClass
(
this
.
downArrowNode
,
"dijitArrowButtonActive"
);
}
},
_arrowIdle
:
function
(){
if
(
!
this
.
disabled
&&
this
.
hasDownArrow
){
dojo
.
removeClass
(
this
.
downArrowNode
,
"dojoArrowButtonPushed"
);
}
},
compositionend
:
function
(
/*Event*/
evt
){
// summary: When inputting characters using an input method, such as Asian
// languages, it will generate this event instead of onKeyDown event
// Note: this event is only triggered in FF (not in IE)
this
.
onkeypress
({
charCode
:-
1
});
},
//////////// INITIALIZATION METHODS ///////////////////////////////////////
constructor
:
function
(){
this
.
query
=
{};
},
postMixInProperties
:
function
(){
if
(
!
this
.
hasDownArrow
){
this
.
baseClass
=
"dijitTextBox"
;
}
if
(
!
this
.
store
){
// if user didn't specify store, then assume there are option tags
var
items
=
this
.
srcNodeRef
?
dojo
.
query
(
"> option"
,
this
.
srcNodeRef
).
map
(
function
(
node
){
node
.
style
.
display
=
"none"
;
return
{
value
:
node
.
getAttribute
(
"value"
),
name
:
String
(
node
.
innerHTML
)
};
})
:
{};
this
.
store
=
new
dojo
.
data
.
ItemFileReadStore
({
data
:
{
identifier
:
this
.
_getValueField
(),
items
:
items
}});
// if there is no value set and there is an option list,
// set the value to the first value to be consistent with native Select
if
(
items
&&
items
.
length
&&
!
this
.
value
){
// For <select>, IE does not let you set the value attribute of the srcNodeRef (and thus dojo.mixin does not copy it).
// IE does understand selectedIndex though, which is automatically set by the selected attribute of an option tag
this
.
value
=
items
[
this
.
srcNodeRef
.
selectedIndex
!=
-
1
?
this
.
srcNodeRef
.
selectedIndex
:
0
]
[
this
.
_getValueField
()];
}
}
},
uninitialize
:
function
(){
if
(
this
.
_popupWidget
){
this
.
_hideResultList
();
this
.
_popupWidget
.
destroy
()
};
},
_getMenuLabelFromItem
:
function
(
/*Item*/
item
){
return
{
html
:
false
,
label
:
this
.
store
.
getValue
(
item
,
this
.
searchAttr
)};
},
open
:
function
(){
this
.
_isShowingNow
=
true
;
return
dijit
.
popup
.
open
({
popup
:
this
.
_popupWidget
,
around
:
this
.
domNode
,
parent
:
this
});
}
}
);
dojo
.
declare
(
"dijit.form._ComboBoxMenu"
,
[
dijit
.
_Widget
,
dijit
.
_Templated
],
{
// summary:
// Focus-less div based menu for internal use in ComboBox
templateString
:
"<div class='dijitMenu' dojoAttachEvent='onmousedown,onmouseup,onmouseover,onmouseout' tabIndex='-1' style='overflow:\"auto\";'>"
+
"<div class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton'></div>"
+
"<div class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton'></div>"
+
"</div>"
,
_messages
:
null
,
postMixInProperties
:
function
(){
this
.
_messages
=
dojo
.
i18n
.
getLocalization
(
"dijit.form"
,
"ComboBox"
,
this
.
lang
);
this
.
inherited
(
"postMixInProperties"
,
arguments
);
},
setValue
:
function
(
/*Object*/
value
){
this
.
value
=
value
;
this
.
onChange
(
value
);
},
onChange
:
function
(
/*Object*/
value
){},
onPage
:
function
(
/*Number*/
direction
){},
postCreate
:
function
(){
// fill in template with i18n messages
this
.
previousButton
.
innerHTML
=
this
.
_messages
[
"previousMessage"
];
this
.
nextButton
.
innerHTML
=
this
.
_messages
[
"nextMessage"
];
this
.
inherited
(
"postCreate"
,
arguments
);
},
onClose
:
function
(){
this
.
_blurOptionNode
();
},
_createOption
:
function
(
/*Object*/
item
,
labelFunc
){
// summary: creates an option to appear on the popup menu
// subclassed by FilteringSelect
var
labelObject
=
labelFunc
(
item
);
var
menuitem
=
document
.
createElement
(
"div"
);
if
(
labelObject
.
html
){
menuitem
.
innerHTML
=
labelObject
.
label
;}
else
{
menuitem
.
appendChild
(
document
.
createTextNode
(
labelObject
.
label
));}
// #3250: in blank options, assign a normal height
if
(
menuitem
.
innerHTML
==
""
){
menuitem
.
innerHTML
=
" "
}
menuitem
.
item
=
item
;
return
menuitem
;
},
createOptions
:
function
(
results
,
dataObject
,
labelFunc
){
//this._dataObject=dataObject;
//this._dataObject.onComplete=dojo.hitch(comboBox, comboBox._openResultList);
// display "Previous . . ." button
this
.
previousButton
.
style
.
display
=
dataObject
.
start
==
0
?
"none"
:
""
;
// create options using _createOption function defined by parent ComboBox (or FilteringSelect) class
// #2309: iterate over cache nondestructively
var
_this
=
this
;
dojo
.
forEach
(
results
,
function
(
item
){
var
menuitem
=
_this
.
_createOption
(
item
,
labelFunc
);
menuitem
.
className
=
"dijitMenuItem"
;
_this
.
domNode
.
insertBefore
(
menuitem
,
_this
.
nextButton
);
});
// display "Next . . ." button
this
.
nextButton
.
style
.
display
=
dataObject
.
count
==
results
.
length
?
""
:
"none"
;
},
clearResultList
:
function
(){
// keep the previous and next buttons of course
while
(
this
.
domNode
.
childNodes
.
length
>
2
){
this
.
domNode
.
removeChild
(
this
.
domNode
.
childNodes
[
this
.
domNode
.
childNodes
.
length
-
2
]);
}
},
// these functions are called in showResultList
getItems
:
function
(){
return
this
.
domNode
.
childNodes
;
},
getListLength
:
function
(){
return
this
.
domNode
.
childNodes
.
length
-
2
;
},
onmousedown
:
function
(
/*Event*/
evt
){
dojo
.
stopEvent
(
evt
);
},
onmouseup
:
function
(
/*Event*/
evt
){
if
(
evt
.
target
===
this
.
domNode
){
return
;
}
else
if
(
evt
.
target
==
this
.
previousButton
){
this
.
onPage
(
-
1
);
}
else
if
(
evt
.
target
==
this
.
nextButton
){
this
.
onPage
(
1
);
}
else
{
var
tgt
=
evt
.
target
;
// while the clicked node is inside the div
while
(
!
tgt
.
item
){
// recurse to the top
tgt
=
tgt
.
parentNode
;
}
this
.
setValue
({
target
:
tgt
},
true
);
}
},
onmouseover
:
function
(
/*Event*/
evt
){
if
(
evt
.
target
===
this
.
domNode
){
return
;
}
var
tgt
=
evt
.
target
;
if
(
!
(
tgt
==
this
.
previousButton
||
tgt
==
this
.
nextButton
)){
// while the clicked node is inside the div
while
(
!
tgt
.
item
){
// recurse to the top
tgt
=
tgt
.
parentNode
;
}
}
this
.
_focusOptionNode
(
tgt
);
},
onmouseout
:
function
(
/*Event*/
evt
){
if
(
evt
.
target
===
this
.
domNode
){
return
;
}
this
.
_blurOptionNode
();
},
_focusOptionNode
:
function
(
/*DomNode*/
node
){
// summary:
// does the actual highlight
if
(
this
.
_highlighted_option
!=
node
){
this
.
_blurOptionNode
();
this
.
_highlighted_option
=
node
;
dojo
.
addClass
(
this
.
_highlighted_option
,
"dijitMenuItemHover"
);
}
},
_blurOptionNode
:
function
(){
// summary:
// removes highlight on highlighted option
if
(
this
.
_highlighted_option
){
dojo
.
removeClass
(
this
.
_highlighted_option
,
"dijitMenuItemHover"
);
this
.
_highlighted_option
=
null
;
}
},
_highlightNextOption
:
function
(){
// because each press of a button clears the menu,
// the highlighted option sometimes becomes detached from the menu!
// test to see if the option has a parent to see if this is the case.
if
(
!
this
.
getHighlightedOption
()){
this
.
_focusOptionNode
(
this
.
domNode
.
firstChild
.
style
.
display
==
"none"
?
this
.
domNode
.
firstChild
.
nextSibling
:
this
.
domNode
.
firstChild
);
}
else
if
(
this
.
_highlighted_option
.
nextSibling
&&
this
.
_highlighted_option
.
nextSibling
.
style
.
display
!=
"none"
){
this
.
_focusOptionNode
(
this
.
_highlighted_option
.
nextSibling
);
}
// scrollIntoView is called outside of _focusOptionNode because in IE putting it inside causes the menu to scroll up on mouseover
dijit
.
scrollIntoView
(
this
.
_highlighted_option
);
},
highlightFirstOption
:
function
(){
// highlight the non-Previous choices option
this
.
_focusOptionNode
(
this
.
domNode
.
firstChild
.
nextSibling
);
dijit
.
scrollIntoView
(
this
.
_highlighted_option
);
},
highlightLastOption
:
function
(){
// highlight the noon-More choices option
this
.
_focusOptionNode
(
this
.
domNode
.
lastChild
.
previousSibling
);
dijit
.
scrollIntoView
(
this
.
_highlighted_option
);
},
_highlightPrevOption
:
function
(){
// if nothing selected, highlight last option
// makes sense if you select Previous and try to keep scrolling up the list
if
(
!
this
.
getHighlightedOption
()){
this
.
_focusOptionNode
(
this
.
domNode
.
lastChild
.
style
.
display
==
"none"
?
this
.
domNode
.
lastChild
.
previousSibling
:
this
.
domNode
.
lastChild
);
}
else
if
(
this
.
_highlighted_option
.
previousSibling
&&
this
.
_highlighted_option
.
previousSibling
.
style
.
display
!=
"none"
){
this
.
_focusOptionNode
(
this
.
_highlighted_option
.
previousSibling
);
}
dijit
.
scrollIntoView
(
this
.
_highlighted_option
);
},
_page
:
function
(
/*Boolean*/
up
){
var
scrollamount
=
0
;
var
oldscroll
=
this
.
domNode
.
scrollTop
;
var
height
=
parseInt
(
dojo
.
getComputedStyle
(
this
.
domNode
).
height
);
// if no item is highlighted, highlight the first option
if
(
!
this
.
getHighlightedOption
()){
this
.
_highlightNextOption
();}
while
(
scrollamount
<
height
){
if
(
up
){
// stop at option 1
if
(
!
this
.
getHighlightedOption
().
previousSibling
||
this
.
_highlighted_option
.
previousSibling
.
style
.
display
==
"none"
){
break
;}
this
.
_highlightPrevOption
();
}
else
{
// stop at last option
if
(
!
this
.
getHighlightedOption
().
nextSibling
||
this
.
_highlighted_option
.
nextSibling
.
style
.
display
==
"none"
){
break
;}
this
.
_highlightNextOption
();
}
// going backwards
var
newscroll
=
this
.
domNode
.
scrollTop
;
scrollamount
+=
(
newscroll
-
oldscroll
)
*
(
up
?
-
1
:
1
);
oldscroll
=
newscroll
;
}
},
pageUp
:
function
(){
this
.
_page
(
true
);
},
pageDown
:
function
(){
this
.
_page
(
false
);
},
getHighlightedOption
:
function
(){
// summary:
// Returns the highlighted option.
return
this
.
_highlighted_option
&&
this
.
_highlighted_option
.
parentNode
?
this
.
_highlighted_option
:
null
;
},
handleKey
:
function
(
evt
){
switch
(
evt
.
keyCode
){
case
dojo
.
keys
.
DOWN_ARROW
:
this
.
_highlightNextOption
();
break
;
case
dojo
.
keys
.
PAGE_DOWN
:
this
.
pageDown
();
break
;
case
dojo
.
keys
.
UP_ARROW
:
this
.
_highlightPrevOption
();
break
;
case
dojo
.
keys
.
PAGE_UP
:
this
.
pageUp
();
break
;
}
}
}
);
dojo
.
declare
(
"dijit.form.ComboBox"
,
[
dijit
.
form
.
ValidationTextBox
,
dijit
.
form
.
ComboBoxMixin
],
{
postMixInProperties
:
function
(){
dijit
.
form
.
ComboBoxMixin
.
prototype
.
postMixInProperties
.
apply
(
this
,
arguments
);
dijit
.
form
.
ValidationTextBox
.
prototype
.
postMixInProperties
.
apply
(
this
,
arguments
);
}
}
);
}
File Metadata
Details
Attached
Mime Type
text/html
Expires
Sat, Apr 26, 13:13 (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26613
Default Alt Text
ComboBox.js (29 KB)
Attached To
rZEDHG ZedLegacy
Event Timeline
Log In to Comment