function createSuggest() { var _key; var _list; var _listHeight = 12; var _currentListIndex = 0; var _maxListIndex; var _input, _output; var _label = function(d) { return d; }; var _callback = null; selectedData = null; function exports(_selection) { _selection.each(function(_data) { init(this); setEvent(); function init(that){ _input = d3.select(that); _output = _input .select(function() { return that.parentNode; }) .append("ul") .classed("suggest_output", true) .style("display", "none"); } function setEvent(){ //アローキーによる移動 _selection.on("keydown", function() { switch (d3.event.keyCode) { case 40: //down listDown(); break; case 38: //up listUp(); break; case 13: //enter //filtering(this.value) break; } }); //サジェスト _selection.on("input", function() { filtering(this.value); }); _selection.on("change.selected", function(d){ d3.select(".suggest_output").style("display", "none"); selectEnd(selectedData); }); } //サジェストリストを降る function listDown() { if (!_maxListIndex || _maxListIndex == _currentListIndex) return; claerSelected(); _currentListIndex += 1; selected = _list .filter(":nth-child(" + _currentListIndex + ")") .classed("selected", true); setValue(selected); if(_currentListIndex > 1) _output.node().scrollTop += _listHeight; } //サジェストリストを上る function listUp() { if (!_maxListIndex || _currentListIndex == 1) return; claerSelected(); _currentListIndex -= 1; selected = _list .filter(":nth-child(" + _currentListIndex + ")") .classed("selected", true); setValue(selected); _output.node().scrollTop -= _listHeight; } //データ内をサーチしてサジェストするデータを抽出 function filtering(string) { var re = new RegExp("^" + string); var filtered = _data.filter(function(d) { var keys = _key(d); if (keys.length == 1) keys = [keys]; return keys.some(function(key) { return re.test(key); }); }); if (_data.length == filtered.length) filtered = []; if (filtered.length <= 0) hideOutput(); appendList(filtered); } //サジェストするデータをリスト要素として追加 function appendList(data) { _currentListIndex = 0; _maxListIndex = data.length; var select = _output.selectAll(".suggest_data").data(data); var enter = select .enter() .append("li") .classed("suggest_data", true); var remove = select.exit().remove(); _list = select.merge(enter); if (data.length > 0) { addListEvent(_list); showOutput(); } } function addListEvent(_list) { _listHeight = _list.filter(":first-child").node().clientHeight; _list.text(function(d) { return _label(d); }); _list .on("mouseover", function(d, i) { claerSelected(); var that = d3.select(this); that.classed("selected", true); setValue(that); _currentListIndex = i++; }) .on("click", clicked); } function setValue(listElm){ selectedData = listElm.data(); _input.node().value = listElm.text(); } function claerSelected() { _list.classed("selected", false); } function showOutput() { _output.style("display", "block"); } function hideOutput() { _output.style("display", "none"); } function clicked() { hideOutput(); _output.selectAll(".suggest_data").remove(); _currentListIndex = 0; _maxListIndex = null; // _input.node().blur(); // _input.node().focus(); selectEnd(selectedData); } function selectEnd(d){ _callback(d); } }); } function triggerEvent(element, event, arg) { if (element.dispatchEvent) { // IE以外 element.dispatchEvent(new Event(event)); } else { // IE var evt = document.createEventObject(); return element.fireEvent("on"+event, evt) } } exports.key = function(_arg) { if (!arguments.length) return _key; _key = _arg; return this; }; exports.label = function(_arg) { if (!arguments.length) return _label; _label = _arg; return this; }; exports.callback = function(_arg) { if (!arguments.length) return _callback; _callback = _arg; return this; }; return exports; }