1/*! UIkit 2.27.1 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2(function(addon) { 3 4 var component; 5 6 if (window.UIkit) { 7 component = addon(UIkit); 8 } 9 10 if (typeof define == "function" && define.amd) { 11 define("uikit-autocomplete", ["uikit"], function(){ 12 return component || addon(UIkit); 13 }); 14 } 15 16})(function(UI){ 17 18 "use strict"; 19 20 var active; 21 22 UI.component('autocomplete', { 23 24 defaults: { 25 minLength: 3, 26 param: 'search', 27 method: 'post', 28 delay: 300, 29 loadingClass: 'uk-loading', 30 flipDropdown: false, 31 skipClass: 'uk-skip', 32 hoverClass: 'uk-active', 33 source: null, 34 renderer: null, 35 36 // template 37 38 template: '<ul class="uk-nav uk-nav-autocomplete uk-autocomplete-results">{{~items}}<li data-value="{{$item.value}}"><a>{{$item.value}}</a></li>{{/items}}</ul>' 39 }, 40 41 visible : false, 42 value : null, 43 selected : null, 44 45 boot: function() { 46 47 // init code 48 UI.$html.on("focus.autocomplete.uikit", "[data-uk-autocomplete]", function(e) { 49 50 var ele = UI.$(this); 51 52 if (!ele.data("autocomplete")) { 53 UI.autocomplete(ele, UI.Utils.options(ele.attr("data-uk-autocomplete"))); 54 } 55 }); 56 57 // register outer click for autocompletes 58 UI.$html.on("click.autocomplete.uikit", function(e) { 59 if (active && e.target!=active.input[0]) active.hide(); 60 }); 61 }, 62 63 init: function() { 64 65 var $this = this, 66 select = false, 67 trigger = UI.Utils.debounce(function(e) { 68 69 if (select) { 70 return (select = false); 71 } 72 73 $this.handle(); 74 }, this.options.delay); 75 76 77 this.dropdown = this.find('.uk-dropdown'); 78 this.template = this.find('script[type="text/autocomplete"]').html(); 79 this.template = UI.Utils.template(this.template || this.options.template); 80 this.input = this.find("input:first").attr("autocomplete", "off"); 81 82 if (!this.dropdown.length) { 83 this.dropdown = UI.$('<div class="uk-dropdown"></div>').appendTo(this.element); 84 } 85 86 if (this.options.flipDropdown) { 87 this.dropdown.addClass('uk-dropdown-flip'); 88 } 89 90 this.dropdown.attr('aria-expanded', 'false'); 91 92 this.input.on({ 93 94 keydown: function(e) { 95 96 if (e && e.which && !e.shiftKey && $this.visible) { 97 98 switch (e.which) { 99 case 13: // enter 100 select = true; 101 102 if ($this.selected) { 103 e.preventDefault(); 104 $this.select(); 105 } 106 break; 107 case 38: // up 108 e.preventDefault(); 109 $this.pick('prev', true); 110 break; 111 case 40: // down 112 e.preventDefault(); 113 $this.pick('next', true); 114 break; 115 case 27: 116 case 9: // esc, tab 117 $this.hide(); 118 break; 119 default: 120 break; 121 } 122 } 123 124 }, 125 126 keyup: trigger 127 }); 128 129 this.dropdown.on("click", ".uk-autocomplete-results > *", function(){ 130 $this.select(); 131 }); 132 133 this.dropdown.on("mouseover", ".uk-autocomplete-results > *", function(){ 134 $this.pick(UI.$(this)); 135 }); 136 137 this.triggercomplete = trigger; 138 }, 139 140 handle: function() { 141 142 var $this = this, old = this.value; 143 144 this.value = this.input.val(); 145 146 if (this.value.length < this.options.minLength) return this.hide(); 147 148 if (this.value != old) { 149 $this.request(); 150 } 151 152 return this; 153 }, 154 155 pick: function(item, scrollinview) { 156 157 var $this = this, 158 items = UI.$(this.dropdown.find('.uk-autocomplete-results').children(':not(.'+this.options.skipClass+')')), 159 selected = false;
160 161 if (typeof item !== "string" && !item.hasClass(this.options.skipClass)) { 162 selected = item; 163 } else if (item == 'next' || item == 'prev') { 164 165 if (this.selected) { 166 var index = items.index(this.selected); 167 168 if (item == 'next') { 169 selected = items.eq(index + 1 < items.length ? index + 1 : 0); 170 } else { 171 selected = items.eq(index - 1 < 0 ? items.length - 1 : index - 1); 172 } 173 174 } else { 175 selected = items[(item == 'next') ? 'first' : 'last'](); 176 } 177 178 selected = UI.$(selected); 179 } 180 181 if (selected && selected.length) { 182 this.selected = selected; 183 items.removeClass(this.options.hoverClass); 184 this.selected.addClass(this.options.hoverClass); 185 186 // jump to selected if not in view 187 if (scrollinview) { 188 189 var top = selected.position().top, 190 scrollTop = $this.dropdown.scrollTop(), 191 dpheight = $this.dropdown.height(); 192 193 if (top > dpheight || top < 0) { 194 $this.dropdown.scrollTop(scrollTop + top); 195 } 196 } 197 } 198 }, 199 200 select: function() { 201 202 if(!this.selected) return; 203 204 var data = this.selected.data(); 205 206 this.trigger("selectitem.uk.autocomplete", [data, this]); 207 208 if (data.value) { 209 this.input.val(data.value).trigger('change'); 210 } 211 212 this.hide(); 213 }, 214 215 show: function() { 216 217 if (this.visible) return; 218 219 this.visible = true; 220 this.element.addClass("uk-open"); 221 222 if (active && active!==this) { 223 active.hide(); 224 } 225 226 active = this; 227 228 // Update aria 229 this.dropdown.attr('aria-expanded', 'true'); 230 231 return this; 232 }, 233 234 hide: function() { 235 if (!this.visible) return; 236 this.visible = false; 237 this.element.removeClass("uk-open"); 238 239 if (active === this) { 240 active = false; 241 } 242 243 // Update aria 244 this.dropdown.attr('aria-expanded', 'false'); 245 246 return this; 247 }, 248 249 request: function() { 250 251 var $this = this, 252 release = function(data) { 253 254 if(data) { 255 $this.render(data); 256 } 257 258 $this.element.removeClass($this.options.loadingClass); 259 }; 260 261 this.element.addClass(this.options.loadingClass); 262 263 if (this.options.source) { 264 265 var source = this.options.source; 266 267 switch(typeof(this.options.source)) { 268 case 'function': 269 270 this.options.source.apply(this, [release]); 271 272 break; 273 274 case 'object': 275 276 if(source.length) { 277 278 var items = []; 279 280 source.forEach(function(item){ 281 if(item.value && item.value.toLowerCase().indexOf($this.value.toLowerCase())!=-1) { 282 items.push(item); 283 } 284 }); 285 286 release(items); 287 } 288 289 break; 290 291 case 'string': 292 293 var params ={}; 294 295 params[this.options.param] = this.value; 296 297 UI.$.ajax({ 298 url: this.options.source, 299 data: params, 300 type: this.options.method, 301 dataType: 'json' 302 }).done(function(json) { 303 release(json || []); 304 }); 305 306 break; 307 308 default: 309 release(null); 310 } 311 312 } else { 313 this.element.removeClass($this.options.loadingClass); 314 } 315 }, 316 317 render: function(data) { 318 319 this.dropdown.empty(); 320 321 this.selected = false;
322 323 if (this.options.renderer) { 324 325 this.options.renderer.apply(this, [data]); 326 327 } else if(data && data.length) { 328 329 this.dropdown.append(this.template({"items":data})); 330 this.show(); 331 332 this.trigger('show.uk.autocomplete'); 333 } 334 335 return this; 336 } 337 }); 338 339 return UI.autocomplete; 340});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.