| 1 | var dexsuggest_oldvalue = ""; |
|---|
| 2 | var dexsuggest_host_el = null; |
|---|
| 3 | var dexsuggest_request = null; |
|---|
| 4 | |
|---|
| 5 | // set a teensy delay on the ajax request so we don't interrupt typing |
|---|
| 6 | var dexsuggest_timeout = null; |
|---|
| 7 | function dexsuggest_change_wrapper(evt) { |
|---|
| 8 | if (dexsuggest_timeout) |
|---|
| 9 | window.clearTimeout(dexsuggest_timeout); |
|---|
| 10 | |
|---|
| 11 | window.setTimeout(dexsuggest_change, 100, evt); |
|---|
| 12 | } |
|---|
| 13 | |
|---|
| 14 | // handle keypresses |
|---|
| 15 | function dexsuggest_change(evt) { |
|---|
| 16 | dexsuggest_timeout = null; |
|---|
| 17 | |
|---|
| 18 | if (evt.keyCode == 9 || evt.keyCode == 13) return; |
|---|
| 19 | |
|---|
| 20 | var suggestbox = document.getElementById("dexsuggest"); |
|---|
| 21 | var el = evt.target; |
|---|
| 22 | var suggestvalue = el.value; |
|---|
| 23 | |
|---|
| 24 | if (suggestvalue == dexsuggest_oldvalue) return; |
|---|
| 25 | dexsuggest_oldvalue = suggestvalue; |
|---|
| 26 | |
|---|
| 27 | if (!suggestvalue && suggestbox) { |
|---|
| 28 | suggestbox.style.visibility == "hidden"; |
|---|
| 29 | return; |
|---|
| 30 | } |
|---|
| 31 | |
|---|
| 32 | if (dexsuggest_request) |
|---|
| 33 | dexsuggest_request.abort(); |
|---|
| 34 | |
|---|
| 35 | var url = "/dex/suggest?extended=1;search=" + suggestvalue; |
|---|
| 36 | var type; |
|---|
| 37 | if ($(dexsuggest_host_el).is(".js-dexsuggest-pokemon")) |
|---|
| 38 | type = "pokemon"; |
|---|
| 39 | else if ($(dexsuggest_host_el).is(".js-dexsuggest-move")) |
|---|
| 40 | type = "move"; |
|---|
| 41 | |
|---|
| 42 | if (type) |
|---|
| 43 | url += ";type=" + type; |
|---|
| 44 | |
|---|
| 45 | dexsuggest_request = $.ajax({ |
|---|
| 46 | type: "GET", |
|---|
| 47 | url: url, |
|---|
| 48 | dataType: "json", |
|---|
| 49 | error: function() { |
|---|
| 50 | dexsuggest_request = null; |
|---|
| 51 | }, |
|---|
| 52 | success: function(res) { |
|---|
| 53 | dexsuggest_request = null; |
|---|
| 54 | if (res[0] != el.value) return; |
|---|
| 55 | |
|---|
| 56 | while (suggestbox.firstChild) |
|---|
| 57 | suggestbox.removeChild(suggestbox.firstChild); |
|---|
| 58 | suggestbox.scrollTop = 0; |
|---|
| 59 | |
|---|
| 60 | var opt; |
|---|
| 61 | var len = suggestvalue.length; |
|---|
| 62 | for (var i = 0; i < res[1].length; i++) { |
|---|
| 63 | opt = document.createElement('li'); |
|---|
| 64 | var typed_part = document.createElement('span'); |
|---|
| 65 | typed_part.className = 'typed'; |
|---|
| 66 | typed_part.appendChild( |
|---|
| 67 | document.createTextNode( res[1][i].label.substr(0, len) ) |
|---|
| 68 | ); |
|---|
| 69 | opt.appendChild(typed_part); |
|---|
| 70 | |
|---|
| 71 | var untyped_part = res[1][i].label.substr(len); |
|---|
| 72 | opt.appendChild( document.createTextNode(untyped_part) ); |
|---|
| 73 | |
|---|
| 74 | if (res[1][i].image) { |
|---|
| 75 | opt.style.backgroundImage = "url(" + res[1][i].image + ")"; |
|---|
| 76 | |
|---|
| 77 | if (res[1][i].bottom_align) // special hack for Pokemon |
|---|
| 78 | opt.style.backgroundPosition = "0.33em bottom"; |
|---|
| 79 | // XXX: any way to just override the vertical position? |
|---|
| 80 | else if (res[1][i].left_4px) // special hack for items |
|---|
| 81 | opt.style.backgroundPosition = "0.66em center"; |
|---|
| 82 | // XXX: THIS IS AWFUL, need better solution STAT |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | $(opt).click(dexsuggest_update_host); |
|---|
| 86 | |
|---|
| 87 | suggestbox.appendChild(opt); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | if (res[1].length) { |
|---|
| 91 | suggestbox.style.visibility = "visible"; |
|---|
| 92 | } else { |
|---|
| 93 | suggestbox.style.visibility = "hidden"; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | dexsuggest_resize(); |
|---|
| 97 | } |
|---|
| 98 | }); |
|---|
| 99 | } |
|---|
| 100 | |
|---|
| 101 | function dexsuggest_update_host(evt) { |
|---|
| 102 | $(dexsuggest_host_el).val(evt.currentTarget.textContent); |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | function dexsuggest_press(evt) { |
|---|
| 106 | var suggestbox = document.getElementById('dexsuggest'); |
|---|
| 107 | if (!suggestbox) return; |
|---|
| 108 | |
|---|
| 109 | var el = evt.target; |
|---|
| 110 | var suggestvalue = el.value; |
|---|
| 111 | |
|---|
| 112 | var old_host_el = dexsuggest_host_el; |
|---|
| 113 | dexsuggest_host_el = el; |
|---|
| 114 | if (el != old_host_el) { |
|---|
| 115 | dexsuggest_resize(); |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | if (!evt.charCode) { // no character generated |
|---|
| 119 | if (evt.keyCode == 27) { // esc |
|---|
| 120 | dexsuggest_hide(); |
|---|
| 121 | |
|---|
| 122 | // These two cases are used for moving the selection highlight up and |
|---|
| 123 | // down the fake listbox. |
|---|
| 124 | } else if (evt.keyCode == 38) { // up |
|---|
| 125 | if (suggestbox.style.visibility == "hidden") |
|---|
| 126 | return; |
|---|
| 127 | |
|---|
| 128 | var selected = $('#dexsuggest > .selected').get(0); |
|---|
| 129 | var prev; |
|---|
| 130 | if (selected) { |
|---|
| 131 | prev = selected.previousSibling; |
|---|
| 132 | } else { |
|---|
| 133 | prev = $('#dexsuggest > li:last-child').get(0); |
|---|
| 134 | } |
|---|
| 135 | if (prev) { |
|---|
| 136 | prev.className = 'selected'; |
|---|
| 137 | if (selected) |
|---|
| 138 | selected.className = undefined; |
|---|
| 139 | |
|---|
| 140 | dexsuggest_scrollto(prev); |
|---|
| 141 | evt.preventDefault(); |
|---|
| 142 | } |
|---|
| 143 | } else if (evt.keyCode == 40) { // down |
|---|
| 144 | if (suggestbox.style.visibility == "hidden") |
|---|
| 145 | suggestbox.style.visibility = "visible"; |
|---|
| 146 | |
|---|
| 147 | var selected = $('#dexsuggest > .selected').get(0); |
|---|
| 148 | var next; |
|---|
| 149 | if (selected) { |
|---|
| 150 | next = selected.nextSibling; |
|---|
| 151 | } else { |
|---|
| 152 | next = $('#dexsuggest > li').get(0); |
|---|
| 153 | } |
|---|
| 154 | if (next) { |
|---|
| 155 | next.className = 'selected'; |
|---|
| 156 | if (selected) |
|---|
| 157 | selected.className = undefined; |
|---|
| 158 | |
|---|
| 159 | dexsuggest_scrollto(next); |
|---|
| 160 | evt.preventDefault(); |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | // Select the highlighted entry if there be one, otherwise submit |
|---|
| 164 | } else if (evt.keyCode == 13) { // enter |
|---|
| 165 | // no suggestbox -> normal submit |
|---|
| 166 | if (suggestbox.style.visibility == "hidden") |
|---|
| 167 | return; |
|---|
| 168 | |
|---|
| 169 | var selected = $('#dexsuggest > .selected').get(0); |
|---|
| 170 | |
|---|
| 171 | // nothing selected |
|---|
| 172 | if (!selected) |
|---|
| 173 | return; |
|---|
| 174 | |
|---|
| 175 | // otherwise, copy selection to target box... |
|---|
| 176 | $(evt.target).val( selected.textContent ); |
|---|
| 177 | |
|---|
| 178 | // ...and kill submit |
|---|
| 179 | evt.preventDefault(); |
|---|
| 180 | |
|---|
| 181 | dexsuggest_hide(); |
|---|
| 182 | } |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | function dexsuggest_scrollto(el) { |
|---|
| 187 | var min_bottom = el.offsetTop + el.offsetHeight; |
|---|
| 188 | if (el.parentNode.scrollTop < min_bottom - el.parentNode.offsetHeight) |
|---|
| 189 | el.parentNode.scrollTop = min_bottom - el.parentNode.offsetHeight; |
|---|
| 190 | |
|---|
| 191 | var max_top = el.offsetTop; |
|---|
| 192 | if (el.parentNode.scrollTop > max_top) |
|---|
| 193 | el.parentNode.scrollTop = max_top; |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | function dexsuggest_resize() { |
|---|
| 197 | var el = document.getElementById('dexsuggest'); |
|---|
| 198 | if (!el) return; |
|---|
| 199 | if (!dexsuggest_host_el) return; |
|---|
| 200 | |
|---|
| 201 | var top_el = dexsuggest_host_el; |
|---|
| 202 | var left_el = dexsuggest_host_el; |
|---|
| 203 | |
|---|
| 204 | var offset_top = top_el ? top_el.offsetHeight : 0; |
|---|
| 205 | while (top_el) { |
|---|
| 206 | offset_top += top_el.offsetTop; |
|---|
| 207 | top_el = top_el.offsetParent; |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | var offset_left = 0; |
|---|
| 211 | while (left_el) { |
|---|
| 212 | offset_left += left_el.offsetLeft; |
|---|
| 213 | left_el = left_el.offsetParent; |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | el.style.top = offset_top + "px"; |
|---|
| 217 | el.style.left = offset_left + "px"; |
|---|
| 218 | el.style.width = dexsuggest_host_el.offsetWidth + "px"; |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | function dexsuggest_hide() { |
|---|
| 222 | $('#dexsuggest').css('visibility', 'hidden'); |
|---|
| 223 | } |
|---|
| 224 | |
|---|
| 225 | $(document).ready(function(evt) { |
|---|
| 226 | var suggestbox = document.createElement('ul'); |
|---|
| 227 | suggestbox.id = "dexsuggest"; |
|---|
| 228 | suggestbox.style.visibility = "hidden"; |
|---|
| 229 | document.body.appendChild(suggestbox); |
|---|
| 230 | |
|---|
| 231 | $(".js-dexsuggest") |
|---|
| 232 | .attr("autocomplete", "off") |
|---|
| 233 | .keyup(dexsuggest_change_wrapper) |
|---|
| 234 | .keypress(dexsuggest_press) |
|---|
| 235 | .blur(function(){ window.setTimeout(dexsuggest_hide, 100) }); |
|---|
| 236 | $(document).resize(dexsuggest_resize); |
|---|
| 237 | |
|---|
| 238 | dexsuggest_resize(); |
|---|
| 239 | }); |
|---|