PageSourceSearch

https://helpdesk.myown.eu/scp/js/bootstrap-typeahead.js?d4e240b

js myown.eu collected 2026-10-10 00:29:12 UTC 9,659 bytes, 364 lines download raw bytes

1/* =============================================================
2 * bootstrap-typeahead.js v2.0.0
3 * http://twitter.github.com/bootstrap/javascript.html#typeahead
4 * =============================================================
5 * Copyright 2012 Twitter, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============================================================ */
19
20!function( $ ){
21
22  "use strict"
23
24  var Typeahead = function ( element, options ) {
25    this.$element = $(element)
26    this.options = $.extend({}, $.fn.typeahead.defaults, options)
27    this.matcher = this.options.matcher || this.matcher
28    this.sorter = this.options.sorter || this.sorter
29    this.highlighter = this.options.highlighter || this.highlighter
30    this.$menu = $(this.options.menu).appendTo('body')
31    if (this.options.scroll)
32      this.$menu.addClass('scroll');
33    this.source = this.options.source
34    this.onselect = this.options.onselect
35    this.strings = true
36    this.shown = false
37    this.deferred = null
38    this.listen()
39  }
40
41  Typeahead.prototype = {
42
43    constructor: Typeahead
44
45  , select: function (e) {
46      var val = JSON.parse(this.$menu.find('.active').attr('data-value'))
47        , text
48
49      if (!this.strings) text = val[this.options.property]
50      else text = val
51
52      this.$element.val(text)
53
54      if (typeof this.onselect == "function")
55          if (false === this.onselect(val, e))
56              return;
57
58      return this.hide()
59    }
60
61  , show: function () {
62      var pos = $.extend({}, this.$element.offset(), {
63        height: this.$element[0].offsetHeight
64      })
65
66      this.$menu.css({
67        top: pos.top + pos.height
68      , left: pos.left
69      })
70
71      this.$menu.show()
72      this.shown = true
73      return this
74    }
75
76  , hide: function () {
77      this.$menu.hide()
78      this.shown = false
79      return this
80    }
81
82  , fetch: function() {
83      var value = this.source(this, this.query)
84      if (value) this.process(value)
85    }
86
87  , lookup: function (event) {
88      var that = this
89        , items
90        , q
91        , value
92
93      this.query = this.$element.val();
94      /*Check if we have a match on the current source?? */
95      if (typeof this.source == "function") {
96        if (!this.options.delay) return this.fetch()
97        if (this.deferred) clearTimeout(this.deferred)
98        this.deferred = setTimeout(this.fetch.bind(this), this.options.delay)
99      } else {
100        this.process(this.source)
101      }
102    }
103
104  , process: function (results) {
105      var that = this
106        , items
107        , q
108
109      if (results.length && typeof results[0] != "string")
110          this.strings = false
111
112      this.query = this.$element.val()
113
114      if (this.query.length < this.options.minLength) {
115        return this.shown ? this.hide() : this
116      }
117
118      items = $.grep(results, function (item) {
119        if (!that.strings)
120          item = item[that.options.property]
121
122        if (that.matcher(item))
123            return item
124      })
125
126      items = this.sorter(items)
127
128      if (!items.length) {
129        return this.shown ? this.hide() : this
130      }
131
132      return this.render(items.slice(0, this.options.items)).show()
133    }
134
135  , matcher: function (item) {
136      return ~item.toLowerCase().indexOf(this.query.toLowerCase())
137    }
138
139  , sorter: function (items) {
140      var beginswith = []
141        , caseSensitive = []
142        , caseInsensitive = []
143        , item
144        , sortby
145
146      while (item = items.shift()) {
147        if (this.strings) sortby = item
148        else sortby = item[this.options.property]
149
150        if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
151        else if (~sortby.indexOf(this.query)) caseSensitive.push(item)
152        else caseInsensitive.push(item)
153      }
154
155      return beginswith.concat(caseSensitive, caseInsensitive)
156    }
157
158  , highlighter: function (item) {
159      if (!this.query)
160          return item;
161      var exp = this.query.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&").replace(' ', '|')
162      return item.replace(new RegExp(exp, 'ig'), '<strong>$&</strong>')
163    }
164
165  , render: function (items) {
166      var that = this
167
168      items = $(items).map(function (i, item) {
169        var orig = item;
170        i = $(that.options.item).attr('data-value', JSON.stringify(item))
171        if (!that.strings) {
172            if(item[that.options.render])
173                item = item[that.options.render];
174            else
175                item = item[that.options.property];
176        }
177        i.find('a').html(that.highlighter(item, orig))
178        return i[0]
179      })
180
181      items.first().addClass('active')
182      this.$menu.html(items)
183      return this
184    }
185
186  , adjustScroll: function(next) {
187      var top = this.$menu.scrollTop(),
188        bottom = top + this.$menu.height(),
189        pos = next.position();
190      if (pos.top < 0)
191        this.$menu.scrollTop(top + pos.top - 10);
192      else if (next.height() + top + pos.top > bottom)
193        this.$menu.scrollTop(top + pos.top - this.$menu.height() + next.height() + 10);
194  }
195
196  , next: function (event) {
197      var active = this.$menu.find('.active').removeClass('active')
198        , next = active.next()
199
200      if (!next.length) {
201        next = $(this.$menu.find('li')[0])
202      }
203
204      next.addClass('active')
205
206      if (this.options.scroll) {
207        this.adjustScroll(next);
208      }
209    }
210
211  , prev: function (event) {
212      var active = this.$menu.find('.active').removeClass('active')
213        , prev = active.prev()
214
215      if (!prev.length) {
216        prev = this.$menu.find('li').last()
217      }
218
219      prev.addClass('active')
220
221      if (this.options.scroll) {
222        this.adjustScroll(prev);
223      }
224    }
225
226  , listen: function () {
227      this.$element
228        .on('blur',     $.proxy(this.blur, this))
229        .on('keypress', $.proxy(this.keypress, this))
230        .on('keyup',    $.proxy(this.keyup, this))
231
232      if (this.eventSupported('keydown')) {
233        this.$element.on('keydown', $.proxy(this.keypress, this))
234      }
235
236      this.$menu
237        .on('click', $.proxy(this.click, this))
238        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
239    }
240
241  , eventSupported: function(eventName) {
242      var isSupported = eventName in this.$element
243      if (!isSupported) {
244        this.$element.setAttribute(eventName, 'return;')
245        isSupported = typeof this.$element[eventName] === 'function'
246      }
247      return isSupported
248    }
249
250  , keyup: function (e) {
251      e.stopPropagation()
252      e.preventDefault()
253
254      switch(e.keyCode) {
255        case 40: // down arrow
256        case 38: // up arrow
257          break
258
259        case 9: // tab
260        case 13: // enter
261          if (!this.shown) return
262          this.select(e)
263          break
264
265        case 27: // escape
266          this.hide()
267          break
268
269        default:
270          this.lookup()
271      }
272
273  }
274
275  , keypress: function (e) {
276      e.stopPropagation()
277      if (!this.shown) return
278
279      switch(e.keyCode) {
280        case 9: // tab
281        case 13: // enter
282        case 27: // escape
283          e.preventDefault()
284          break
285
286        case 38: // up arrow
287          e.preventDefault()
288          this.prev()
289          break
290
291        case 40: // down arrow
292          e.preventDefault()
293          this.next()
294          break
295      }
296    }
297
298  , blur: function (e) {
299      var that = this
300      e.stopPropagation()
301      e.preventDefault()
302      setTimeout(function () { that.hide() }, 150)
303    }
304
305  , click: function (e) {
306      e.stopPropagation()
307      e.preventDefault()
308      this.select(e)
309    }
310
311  , mouseenter: function (e) {
312      this.$menu.find('.active').removeClass('active')
313      $(e.currentTarget).addClass('active')
314    }
315
316  , visible: function() {
317      return this.shown;
318    }
319
320  }
321
322
323  /* TYPEAHEAD PLUGIN DEFINITION
324   * =========================== */
325
326  $.fn.typeahead = function ( option ) {
327    return this.each(function () {
328      var $this = $(this)
329        , data = $this.data('typeahead')
330        , options = typeof option == 'object' && option
331      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
332      if (typeof option == 'string') data[option]()
333    })
334  }
335
336  $.fn.typeahead.defaults = {
337    source: []
338  , items: 8
339  , menu: '<ul class="typeahead dropdown-menu"></ul>'
340  , item: '<li><a href="#"></a></li>'
341  , onselect: null
342  , property: 'value'
343  , render: 'info'
344  , minLength: 1
345  , scroll: false
346  , delay: 200
347  }
348
349  $.fn.typeahead.Constructor = Typeahead
350
351
352 /* TYPEAHEAD DATA-API
353  * ================== */
354
355  $(function () {
356    $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
357      var $this = $(this)
358      if ($this.data('typeahead')) return
359      e.preventDefault()
360      $this.typeahead($this.data())
361    })
362  })
363
364}( window.jQuery );

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.