New file |
0,0 → 1,556 |
/* |
Copyright (c) 2004-2006, The Dojo Foundation |
All Rights Reserved. |
|
Licensed under the Academic Free License version 2.1 or above OR the |
modified BSD license. For more information on Dojo licensing, see: |
|
http://dojotoolkit.org/community/licensing.shtml |
*/ |
|
dojo.provide("dojo.widget.ComboBox"); |
dojo.require("dojo.widget.*"); |
dojo.require("dojo.event.*"); |
dojo.require("dojo.io.*"); |
dojo.require("dojo.html.*"); |
dojo.require("dojo.string"); |
dojo.require("dojo.widget.html.stabile"); |
dojo.require("dojo.widget.PopupContainer"); |
dojo.declare("dojo.widget.incrementalComboBoxDataProvider", null, function (options) { |
this.searchUrl = options.dataUrl; |
this._cache = {}; |
this._inFlight = false; |
this._lastRequest = null; |
this.allowCache = false; |
}, {_addToCache:function (keyword, data) { |
if (this.allowCache) { |
this._cache[keyword] = data; |
} |
}, startSearch:function (searchStr, callback) { |
if (this._inFlight) { |
} |
var tss = encodeURIComponent(searchStr); |
var realUrl = dojo.string.substituteParams(this.searchUrl, {"searchString":tss}); |
var _this = this; |
var request = this._lastRequest = dojo.io.bind({url:realUrl, method:"get", mimetype:"text/json", load:function (type, data, evt) { |
_this._inFlight = false; |
if (!dojo.lang.isArray(data)) { |
var arrData = []; |
for (var key in data) { |
arrData.push([data[key], key]); |
} |
data = arrData; |
} |
_this._addToCache(searchStr, data); |
if (request == _this._lastRequest) { |
callback(data); |
} |
}}); |
this._inFlight = true; |
}}); |
dojo.declare("dojo.widget.basicComboBoxDataProvider", null, function (options, node) { |
this._data = []; |
this.searchLimit = 30; |
this.searchType = "STARTSTRING"; |
this.caseSensitive = false; |
if (!dj_undef("dataUrl", options) && !dojo.string.isBlank(options.dataUrl)) { |
this._getData(options.dataUrl); |
} else { |
if ((node) && (node.nodeName.toLowerCase() == "select")) { |
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) { |
options.setAllValues(keyValArr[0], keyValArr[1]); |
} |
} |
this.setData(data); |
} |
} |
}, {_getData:function (url) { |
dojo.io.bind({url:url, load:dojo.lang.hitch(this, function (type, data, evt) { |
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"}); |
}, startSearch:function (searchStr, callback) { |
this._performSearch(searchStr, callback); |
}, _performSearch:function (searchStr, callback) { |
var st = this.searchType; |
var ret = []; |
if (!this.caseSensitive) { |
searchStr = searchStr.toLowerCase(); |
} |
for (var x = 0; x < this._data.length; x++) { |
if ((this.searchLimit > 0) && (ret.length >= this.searchLimit)) { |
break; |
} |
var dataLabel = new String((!this.caseSensitive) ? this._data[x][0].toLowerCase() : this._data[x][0]); |
if (dataLabel.length < searchStr.length) { |
continue; |
} |
if (st == "STARTSTRING") { |
if (searchStr == dataLabel.substr(0, searchStr.length)) { |
ret.push(this._data[x]); |
} |
} else { |
if (st == "SUBSTRING") { |
if (dataLabel.indexOf(searchStr) >= 0) { |
ret.push(this._data[x]); |
} |
} else { |
if (st == "STARTWORD") { |
var idx = dataLabel.indexOf(searchStr); |
if (idx == 0) { |
ret.push(this._data[x]); |
} |
if (idx <= 0) { |
continue; |
} |
var matches = false; |
while (idx != -1) { |
if (" ,/(".indexOf(dataLabel.charAt(idx - 1)) != -1) { |
matches = true; |
break; |
} |
idx = dataLabel.indexOf(searchStr, idx + 1); |
} |
if (!matches) { |
continue; |
} else { |
ret.push(this._data[x]); |
} |
} |
} |
} |
} |
callback(ret); |
}, setData:function (pdata) { |
this._data = pdata; |
}}); |
dojo.widget.defineWidget("dojo.widget.ComboBox", dojo.widget.HtmlWidget, {forceValidOption:false, searchType:"stringstart", dataProvider:null, autoComplete:true, searchDelay:100, dataUrl:"", fadeTime:200, maxListLength:8, mode:"local", selectedResult:null, dataProviderClass:"", buttonSrc:dojo.uri.moduleUri("dojo.widget", "templates/images/combo_box_arrow.png"), dropdownToggle:"fade", templateString:"<span _=\"whitespace and CR's between tags adds in FF\"\n\tclass=\"dojoComboBoxOuter\"\n\t><input style=\"display:none\" tabindex=\"-1\" name=\"\" value=\"\" \n\t\tdojoAttachPoint=\"comboBoxValue\"\n\t><input style=\"display:none\" tabindex=\"-1\" name=\"\" value=\"\" \n\t\tdojoAttachPoint=\"comboBoxSelectionValue\"\n\t><input type=\"text\" autocomplete=\"off\" class=\"dojoComboBox\"\n\t\tdojoAttachEvent=\"key:_handleKeyEvents; keyUp: onKeyUp; compositionEnd; onResize;\"\n\t\tdojoAttachPoint=\"textInputNode\"\n\t><img hspace=\"0\"\n\t\tvspace=\"0\"\n\t\tclass=\"dojoComboBox\"\n\t\tdojoAttachPoint=\"downArrowNode\"\n\t\tdojoAttachEvent=\"onMouseUp: handleArrowClick; onResize;\"\n\t\tsrc=\"${this.buttonSrc}\"\n></span>\n", templateCssString:".dojoComboBoxOuter {\n\tborder: 0px !important;\n\tmargin: 0px !important;\n\tpadding: 0px !important;\n\tbackground: transparent !important;\n\twhite-space: nowrap !important;\n}\n\n.dojoComboBox {\n\tborder: 1px inset #afafaf;\n\tmargin: 0px;\n\tpadding: 0px;\n\tvertical-align: middle !important;\n\tfloat: none !important;\n\tposition: static !important;\n\tdisplay: inline !important;\n}\n\n/* the input box */\ninput.dojoComboBox {\n\tborder-right-width: 0px !important; \n\tmargin-right: 0px !important;\n\tpadding-right: 0px !important;\n}\n\n/* the down arrow */\nimg.dojoComboBox {\n\tborder-left-width: 0px !important;\n\tpadding-left: 0px !important;\n\tmargin-left: 0px !important;\n}\n\n/* IE vertical-alignment calculations can be off by +-1 but these margins are collapsed away */\n.dj_ie img.dojoComboBox {\n\tmargin-top: 1px; \n\tmargin-bottom: 1px; \n}\n\n/* the drop down */\n.dojoComboBoxOptions {\n\tfont-family: Verdana, Helvetica, Garamond, sans-serif;\n\t/* font-size: 0.7em; */\n\tbackground-color: white;\n\tborder: 1px solid #afafaf;\n\tposition: absolute;\n\tz-index: 1000; \n\toverflow: auto;\n\tcursor: default;\n}\n\n.dojoComboBoxItem {\n\tpadding-left: 2px;\n\tpadding-top: 2px;\n\tmargin: 0px;\n}\n\n.dojoComboBoxItemEven {\n\tbackground-color: #f4f4f4;\n}\n\n.dojoComboBoxItemOdd {\n\tbackground-color: white;\n}\n\n.dojoComboBoxItemHighlight {\n\tbackground-color: #63709A;\n\tcolor: white;\n}\n", templateCssPath:dojo.uri.moduleUri("dojo.widget", "templates/ComboBox.css"), setValue:function (value) { |
this.comboBoxValue.value = value; |
if (this.textInputNode.value != value) { |
this.textInputNode.value = value; |
dojo.widget.html.stabile.setState(this.widgetId, this.getState(), true); |
this.onValueChanged(value); |
} |
}, onValueChanged:function (value) { |
}, getValue:function () { |
return this.comboBoxValue.value; |
}, getState:function () { |
return {value:this.getValue()}; |
}, setState:function (state) { |
this.setValue(state.value); |
}, enable:function () { |
this.disabled = false; |
this.textInputNode.removeAttribute("disabled"); |
}, disable:function () { |
this.disabled = true; |
this.textInputNode.setAttribute("disabled", true); |
}, _getCaretPos:function (element) { |
if (dojo.lang.isNumber(element.selectionStart)) { |
return element.selectionStart; |
} else { |
if (dojo.render.html.ie) { |
var tr = document.selection.createRange().duplicate(); |
var ntr = element.createTextRange(); |
tr.move("character", 0); |
ntr.move("character", 0); |
try { |
ntr.setEndPoint("EndToEnd", tr); |
return String(ntr.text).replace(/\r/g, "").length; |
} |
catch (e) { |
return 0; |
} |
} |
} |
}, _setCaretPos:function (element, location) { |
location = parseInt(location); |
this._setSelectedRange(element, location, location); |
}, _setSelectedRange:function (element, start, end) { |
if (!end) { |
end = element.value.length; |
} |
if (element.setSelectionRange) { |
element.focus(); |
element.setSelectionRange(start, end); |
} else { |
if (element.createTextRange) { |
var range = element.createTextRange(); |
with (range) { |
collapse(true); |
moveEnd("character", end); |
moveStart("character", start); |
select(); |
} |
} else { |
element.value = element.value; |
element.blur(); |
element.focus(); |
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); |
} |
} |
} |
}, _handleKeyEvents:function (evt) { |
if (evt.ctrlKey || evt.altKey || !evt.key) { |
return; |
} |
this._prev_key_backspace = false; |
this._prev_key_esc = false; |
var k = dojo.event.browser.keys; |
var doSearch = true; |
switch (evt.key) { |
case k.KEY_DOWN_ARROW: |
if (!this.popupWidget.isShowingNow) { |
this._startSearchFromInput(); |
} |
this._highlightNextOption(); |
dojo.event.browser.stopEvent(evt); |
return; |
case k.KEY_UP_ARROW: |
this._highlightPrevOption(); |
dojo.event.browser.stopEvent(evt); |
return; |
case k.KEY_TAB: |
if (!this.autoComplete && this.popupWidget.isShowingNow && this._highlighted_option) { |
dojo.event.browser.stopEvent(evt); |
this._selectOption({"target":this._highlighted_option, "noHide":false}); |
this._setSelectedRange(this.textInputNode, this.textInputNode.value.length, null); |
} else { |
this._selectOption(); |
return; |
} |
break; |
case k.KEY_ENTER: |
if (this.popupWidget.isShowingNow) { |
dojo.event.browser.stopEvent(evt); |
} |
if (this.autoComplete) { |
this._selectOption(); |
return; |
} |
case " ": |
if (this.popupWidget.isShowingNow && this._highlighted_option) { |
dojo.event.browser.stopEvent(evt); |
this._selectOption(); |
this._hideResultList(); |
return; |
} |
break; |
case k.KEY_ESCAPE: |
this._hideResultList(); |
this._prev_key_esc = true; |
return; |
case k.KEY_BACKSPACE: |
this._prev_key_backspace = true; |
if (!this.textInputNode.value.length) { |
this.setAllValues("", ""); |
this._hideResultList(); |
doSearch = false; |
} |
break; |
case k.KEY_RIGHT_ARROW: |
case k.KEY_LEFT_ARROW: |
doSearch = false; |
break; |
default: |
if (evt.charCode == 0) { |
doSearch = false; |
} |
} |
if (this.searchTimer) { |
clearTimeout(this.searchTimer); |
} |
if (doSearch) { |
this._blurOptionNode(); |
this.searchTimer = setTimeout(dojo.lang.hitch(this, this._startSearchFromInput), this.searchDelay); |
} |
}, compositionEnd:function (evt) { |
evt.key = evt.keyCode; |
this._handleKeyEvents(evt); |
}, onKeyUp:function (evt) { |
this.setValue(this.textInputNode.value); |
}, setSelectedValue:function (value) { |
this.comboBoxSelectionValue.value = value; |
}, setAllValues:function (value1, value2) { |
this.setSelectedValue(value2); |
this.setValue(value1); |
}, _focusOptionNode:function (node) { |
if (this._highlighted_option != node) { |
this._blurOptionNode(); |
this._highlighted_option = node; |
dojo.html.addClass(this._highlighted_option, "dojoComboBoxItemHighlight"); |
} |
}, _blurOptionNode:function () { |
if (this._highlighted_option) { |
dojo.html.removeClass(this._highlighted_option, "dojoComboBoxItemHighlight"); |
this._highlighted_option = null; |
} |
}, _highlightNextOption:function () { |
if ((!this._highlighted_option) || !this._highlighted_option.parentNode) { |
this._focusOptionNode(this.optionsListNode.firstChild); |
} else { |
if (this._highlighted_option.nextSibling) { |
this._focusOptionNode(this._highlighted_option.nextSibling); |
} |
} |
dojo.html.scrollIntoView(this._highlighted_option); |
}, _highlightPrevOption:function () { |
if (this._highlighted_option && this._highlighted_option.previousSibling) { |
this._focusOptionNode(this._highlighted_option.previousSibling); |
} else { |
this._highlighted_option = null; |
this._hideResultList(); |
return; |
} |
dojo.html.scrollIntoView(this._highlighted_option); |
}, _itemMouseOver:function (evt) { |
if (evt.target === this.optionsListNode) { |
return; |
} |
this._focusOptionNode(evt.target); |
dojo.html.addClass(this._highlighted_option, "dojoComboBoxItemHighlight"); |
}, _itemMouseOut:function (evt) { |
if (evt.target === this.optionsListNode) { |
return; |
} |
this._blurOptionNode(); |
}, onResize:function () { |
var inputSize = dojo.html.getContentBox(this.textInputNode); |
if (inputSize.height <= 0) { |
dojo.lang.setTimeout(this, "onResize", 100); |
return; |
} |
var buttonSize = {width:inputSize.height, height:inputSize.height}; |
dojo.html.setContentBox(this.downArrowNode, buttonSize); |
}, fillInTemplate:function (args, frag) { |
dojo.html.applyBrowserClass(this.domNode); |
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"; |
dojo.html.copyStyle(this.domNode, source); |
dojo.html.copyStyle(this.textInputNode, source); |
dojo.html.copyStyle(this.downArrowNode, source); |
with (this.downArrowNode.style) { |
width = "0px"; |
height = "0px"; |
} |
var dpClass; |
if (this.dataProviderClass) { |
if (typeof this.dataProviderClass == "string") { |
dpClass = dojo.evalObjPath(this.dataProviderClass); |
} else { |
dpClass = this.dataProviderClass; |
} |
} else { |
if (this.mode == "remote") { |
dpClass = dojo.widget.incrementalComboBoxDataProvider; |
} else { |
dpClass = dojo.widget.basicComboBoxDataProvider; |
} |
} |
this.dataProvider = new dpClass(this, this.getFragNodeRef(frag)); |
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; |
this.domNode.appendChild(this.optionsListNode); |
dojo.html.addClass(this.optionsListNode, "dojoComboBoxOptions"); |
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"); |
}, _openResultList:function (results) { |
if (this.disabled) { |
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); |
if ((cpos + 1) > this.textInputNode.value.length) { |
this.textInputNode.value += results[0][0].substr(cpos); |
this._setSelectedRange(this.textInputNode, cpos, this.textInputNode.value.length); |
} |
} |
var even = true; |
while (results.length) { |
var tr = results.shift(); |
if (tr) { |
var td = document.createElement("div"); |
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); |
} |
} |
this._showResultList(); |
}, _onFocusInput:function () { |
this._hasFocus = true; |
}, _onBlurInput:function () { |
this._hasFocus = false; |
this._handleBlurTimer(true, 500); |
}, _handleBlurTimer:function (clear, millisec) { |
if (this.blurTimer && (clear || millisec)) { |
clearTimeout(this.blurTimer); |
} |
if (millisec) { |
this.blurTimer = dojo.lang.setTimeout(this, "_checkBlurred", millisec); |
} |
}, _onMouseOver:function (evt) { |
if (!this._mouseover_list) { |
this._handleBlurTimer(true, 0); |
this._mouseover_list = true; |
} |
}, _onMouseOut:function (evt) { |
var relTarget = evt.relatedTarget; |
try { |
if (!relTarget || relTarget.parentNode != this.optionsListNode) { |
this._mouseover_list = false; |
this._handleBlurTimer(true, 100); |
this._tryFocus(); |
} |
} |
catch (e) { |
} |
}, _isInputEqualToResult:function (result) { |
var input = this.textInputNode.value; |
if (!this.dataProvider.caseSensitive) { |
input = input.toLowerCase(); |
result = result.toLowerCase(); |
} |
return (input == result); |
}, _isValidOption:function () { |
var tgt = dojo.html.firstElement(this.optionsListNode); |
var isValidOption = false; |
while (!isValidOption && tgt) { |
if (this._isInputEqualToResult(tgt.getAttribute("resultName"))) { |
isValidOption = true; |
} else { |
tgt = dojo.html.nextElement(tgt); |
} |
} |
return isValidOption; |
}, _checkBlurred:function () { |
if (!this._hasFocus && !this._mouseover_list) { |
this._hideResultList(); |
if (!this.textInputNode.value.length) { |
this.setAllValues("", ""); |
return; |
} |
var isValidOption = this._isValidOption(); |
if (this.forceValidOption && !isValidOption) { |
this.setAllValues("", ""); |
return; |
} |
if (!isValidOption) { |
this.setSelectedValue(""); |
} |
} |
}, _selectOption:function (evt) { |
var tgt = null; |
if (!evt) { |
evt = {target:this._highlighted_option}; |
} |
if (!dojo.html.isDescendantOf(evt.target, this.optionsListNode)) { |
if (!this.textInputNode.value.length) { |
return; |
} |
tgt = dojo.html.firstElement(this.optionsListNode); |
if (!tgt || !this._isInputEqualToResult(tgt.getAttribute("resultName"))) { |
return; |
} |
} else { |
tgt = evt.target; |
} |
while ((tgt.nodeType != 1) || (!tgt.getAttribute("resultName"))) { |
tgt = tgt.parentNode; |
if (tgt === dojo.body()) { |
return false; |
} |
} |
this.selectedResult = [tgt.getAttribute("resultName"), tgt.getAttribute("resultValue")]; |
this.setAllValues(tgt.getAttribute("resultName"), tgt.getAttribute("resultValue")); |
if (!evt.noHide) { |
this._hideResultList(); |
this._setSelectedRange(this.textInputNode, 0, null); |
} |
this._tryFocus(); |
}, _clearResultList:function () { |
if (this.optionsListNode.innerHTML) { |
this.optionsListNode.innerHTML = ""; |
} |
}, _hideResultList:function () { |
this.popupWidget.close(); |
}, _showResultList:function () { |
var childs = this.optionsListNode.childNodes; |
if (childs.length) { |
var visibleCount = Math.min(childs.length, this.maxListLength); |
with (this.optionsListNode.style) { |
display = ""; |
if (visibleCount == childs.length) { |
height = ""; |
} else { |
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 { |
this._hideResultList(); |
} |
}, handleArrowClick:function () { |
this._handleBlurTimer(true, 0); |
this._tryFocus(); |
if (this.popupWidget.isShowingNow) { |
this._hideResultList(); |
} else { |
this._startSearch(""); |
} |
}, _tryFocus:function () { |
try { |
this.textInputNode.focus(); |
} |
catch (e) { |
} |
}, _startSearchFromInput:function () { |
this._startSearch(this.textInputNode.value); |
}, _startSearch:function (key) { |
this.dataProvider.startSearch(key, dojo.lang.hitch(this, "_openResultList")); |
}, postCreate:function () { |
this.onResize(); |
dojo.event.connect(this.textInputNode, "onblur", this, "_onBlurInput"); |
dojo.event.connect(this.textInputNode, "onfocus", this, "_onFocusInput"); |
if (this.disabled) { |
this.disable(); |
} |
var s = dojo.widget.html.stabile.getState(this.widgetId); |
if (s) { |
this.setState(s); |
} |
}}); |
|