summaryrefslogtreecommitdiffstats
path: root/WebHob_1.5/b3/assets/js/bootstrap3-typeahead.js
diff options
context:
space:
mode:
Diffstat (limited to 'WebHob_1.5/b3/assets/js/bootstrap3-typeahead.js')
-rw-r--r--WebHob_1.5/b3/assets/js/bootstrap3-typeahead.js584
1 files changed, 584 insertions, 0 deletions
diff --git a/WebHob_1.5/b3/assets/js/bootstrap3-typeahead.js b/WebHob_1.5/b3/assets/js/bootstrap3-typeahead.js
new file mode 100644
index 0000000..b614a22
--- /dev/null
+++ b/WebHob_1.5/b3/assets/js/bootstrap3-typeahead.js
@@ -0,0 +1,584 @@
+/* =============================================================
+ * bootstrap3-typeahead.js v3.1.0
+ * https://github.com/bassjobsen/Bootstrap-3-Typeahead
+ * =============================================================
+ * Original written by @mdo and @fat
+ * =============================================================
+ * Copyright 2014 Bass Jobsen @bassjobsen
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+(function (root, factory) {
+
+ 'use strict';
+
+ // CommonJS module is defined
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = factory(require('jquery'));
+ }
+ // AMD module is defined
+ else if (typeof define === 'function' && define.amd) {
+ define(['jquery'], function ($) {
+ return factory ($);
+ });
+ } else {
+ factory(root.jQuery);
+ }
+
+}(this, function ($) {
+
+ 'use strict';
+ // jshint laxcomma: true
+
+
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
+ * ================================= */
+
+ var Typeahead = function (element, options) {
+ this.$element = $(element);
+ this.options = $.extend({}, $.fn.typeahead.defaults, options);
+ this.matcher = this.options.matcher || this.matcher;
+ this.sorter = this.options.sorter || this.sorter;
+ this.select = this.options.select || this.select;
+ this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;
+ this.highlighter = this.options.highlighter || this.highlighter;
+ this.render = this.options.render || this.render;
+ this.updater = this.options.updater || this.updater;
+ this.displayText = this.options.displayText || this.displayText;
+ this.source = this.options.source;
+ this.delay = this.options.delay;
+ this.$menu = $(this.options.menu);
+ this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null;
+ this.fitToElement = typeof this.options.fitToElement == 'boolean' ? this.options.fitToElement : false;
+ this.shown = false;
+ this.listen();
+ this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' || this.options.showHintOnFocus === "all" ? this.options.showHintOnFocus : false;
+ this.afterSelect = this.options.afterSelect;
+ this.addItem = false;
+ this.value = this.$element.val() || this.$element.text();
+ };
+
+ Typeahead.prototype = {
+
+ constructor: Typeahead,
+
+ select: function () {
+ var val = this.$menu.find('.active').data('value');
+ this.$element.data('active', val);
+ if (this.autoSelect || val) {
+ var newVal = this.updater(val);
+ // Updater can be set to any random functions via "options" parameter in constructor above.
+ // Add null check for cases when updater returns void or undefined.
+ if (!newVal) {
+ newVal = '';
+ }
+ this.$element
+ .val(this.displayText(newVal) || newVal)
+ .text(this.displayText(newVal) || newVal)
+ .change();
+ this.afterSelect(newVal);
+ }
+ return this.hide();
+ },
+
+ updater: function (item) {
+ return item;
+ },
+
+ setSource: function (source) {
+ this.source = source;
+ },
+
+ show: function () {
+ var pos = $.extend({}, this.$element.position(), {
+ height: this.$element[0].offsetHeight
+ });
+
+ var scrollHeight = typeof this.options.scrollHeight == 'function' ?
+ this.options.scrollHeight.call() :
+ this.options.scrollHeight;
+
+ var element;
+ if (this.shown) {
+ element = this.$menu;
+ } else if (this.$appendTo) {
+ element = this.$menu.appendTo(this.$appendTo);
+ this.hasSameParent = this.$appendTo.is(this.$element.parent());
+ } else {
+ element = this.$menu.insertAfter(this.$element);
+ this.hasSameParent = true;
+ }
+
+ if (!this.hasSameParent) {
+ // We cannot rely on the element position, need to position relative to the window
+ element.css("position", "fixed");
+ var offset = this.$element.offset();
+ pos.top = offset.top;
+ pos.left = offset.left;
+ }
+ // The rules for bootstrap are: 'dropup' in the parent and 'dropdown-menu-right' in the element.
+ // Note that to get right alignment, you'll need to specify `menu` in the options to be:
+ // '<ul class="typeahead dropdown-menu" role="listbox"></ul>'
+ var dropup = $(element).parent().hasClass('dropup');
+ var newTop = dropup ? 'auto' : (pos.top + pos.height + scrollHeight);
+ var right = $(element).hasClass('dropdown-menu-right');
+ var newLeft = right ? 'auto' : pos.left;
+ // it seems like setting the css is a bad idea (just let Bootstrap do it), but I'll keep the old
+ // logic in place except for the dropup/right-align cases.
+ element.css({ top: newTop, left: newLeft }).show();
+
+ if (this.options.fitToElement === true) {
+ element.css("width", this.$element.outerWidth() + "px");
+ }
+
+ this.shown = true;
+ return this;
+ },
+
+ hide: function () {
+ this.$menu.hide();
+ this.shown = false;
+ return this;
+ },
+
+ lookup: function (query) {
+ var items;
+ if (typeof(query) != 'undefined' && query !== null) {
+ this.query = query;
+ } else {
+ this.query = this.$element.val() || this.$element.text() || '';
+ }
+
+ if (this.query.length < this.options.minLength && !this.options.showHintOnFocus) {
+ return this.shown ? this.hide() : this;
+ }
+
+ var worker = $.proxy(function () {
+
+ if ($.isFunction(this.source)) {
+ this.source(this.query, $.proxy(this.process, this));
+ } else if (this.source) {
+ this.process(this.source);
+ }
+ }, this);
+
+ clearTimeout(this.lookupWorker);
+ this.lookupWorker = setTimeout(worker, this.delay);
+ },
+
+ process: function (items) {
+ var that = this;
+
+ items = $.grep(items, function (item) {
+ return that.matcher(item);
+ });
+
+ items = this.sorter(items);
+
+ if (!items.length && !this.options.addItem) {
+ return this.shown ? this.hide() : this;
+ }
+
+ if (items.length > 0) {
+ this.$element.data('active', items[0]);
+ } else {
+ this.$element.data('active', null);
+ }
+
+ // Add item
+ if (this.options.addItem){
+ items.push(this.options.addItem);
+ }
+
+ if (this.options.items == 'all') {
+ return this.render(items).show();
+ } else {
+ return this.render(items.slice(0, this.options.items)).show();
+ }
+ },
+
+ matcher: function (item) {
+ var it = this.displayText(item);
+ return ~it.toLowerCase().indexOf(this.query.toLowerCase());
+ },
+
+ sorter: function (items) {
+ var beginswith = [];
+ var caseSensitive = [];
+ var caseInsensitive = [];
+ var item;
+
+ while ((item = items.shift())) {
+ var it = this.displayText(item);
+ if (!it.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
+ else if (~it.indexOf(this.query)) caseSensitive.push(item);
+ else caseInsensitive.push(item);
+ }
+
+ return beginswith.concat(caseSensitive, caseInsensitive);
+ },
+
+ highlighter: function (item) {
+ var html = $('<div></div>');
+ var query = this.query;
+ var i = item.toLowerCase().indexOf(query.toLowerCase());
+ var len = query.length;
+ var leftPart;
+ var middlePart;
+ var rightPart;
+ var strong;
+ if (len === 0) {
+ return html.text(item).html();
+ }
+ while (i > -1) {
+ leftPart = item.substr(0, i);
+ middlePart = item.substr(i, len);
+ rightPart = item.substr(i + len);
+ strong = $('<strong></strong>').text(middlePart);
+ html
+ .append(document.createTextNode(leftPart))
+ .append(strong);
+ item = rightPart;
+ i = item.toLowerCase().indexOf(query.toLowerCase());
+ }
+ return html.append(document.createTextNode(item)).html();
+ },
+
+ render: function (items) {
+ var that = this;
+ var self = this;
+ var activeFound = false;
+ var data = [];
+ var _category = that.options.separator;
+
+ $.each(items, function (key,value) {
+ // inject separator
+ if (key > 0 && value[_category] !== items[key - 1][_category]){
+ data.push({
+ __type: 'divider'
+ });
+ }
+
+ // inject category header
+ if (value[_category] && (key === 0 || value[_category] !== items[key - 1][_category])){
+ data.push({
+ __type: 'category',
+ name: value[_category]
+ });
+ }
+ data.push(value);
+ });
+
+ items = $(data).map(function (i, item) {
+ if ((item.__type || false) == 'category'){
+ return $(that.options.headerHtml).text(item.name)[0];
+ }
+
+ if ((item.__type || false) == 'divider'){
+ return $(that.options.headerDivider)[0];
+ }
+
+ var text = self.displayText(item);
+ i = $(that.options.item).data('value', item);
+ i.find('a').html(that.highlighter(text, item));
+ if (text == self.$element.val()) {
+ i.addClass('active');
+ self.$element.data('active', item);
+ activeFound = true;
+ }
+ return i[0];
+ });
+
+ if (this.autoSelect && !activeFound) {
+ items.filter(':not(.dropdown-header)').first().addClass('active');
+ this.$element.data('active', items.first().data('value'));
+ }
+ this.$menu.html(items);
+ return this;
+ },
+
+ displayText: function (item) {
+ return typeof item !== 'undefined' && typeof item.name != 'undefined' && item.name || item;
+ },
+
+ next: function (event) {
+ var active = this.$menu.find('.active').removeClass('active');
+ var next = active.next();
+
+ if (!next.length) {
+ next = $(this.$menu.find('li')[0]);
+ }
+
+ next.addClass('active');
+ },
+
+ prev: function (event) {
+ var active = this.$menu.find('.active').removeClass('active');
+ var prev = active.prev();
+
+ if (!prev.length) {
+ prev = this.$menu.find('li').last();
+ }
+
+ prev.addClass('active');
+ },
+
+ listen: function () {
+ this.$element
+ .on('focus', $.proxy(this.focus, this))
+ .on('blur', $.proxy(this.blur, this))
+ .on('keypress', $.proxy(this.keypress, this))
+ .on('input', $.proxy(this.input, this))
+ .on('keyup', $.proxy(this.keyup, this));
+
+ if (this.eventSupported('keydown')) {
+ this.$element.on('keydown', $.proxy(this.keydown, this));
+ }
+
+ this.$menu
+ .on('click', $.proxy(this.click, this))
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
+ .on('mousedown', $.proxy(this.mousedown,this));
+ },
+
+ destroy : function () {
+ this.$element.data('typeahead',null);
+ this.$element.data('active',null);
+ this.$element
+ .off('focus')
+ .off('blur')
+ .off('keypress')
+ .off('input')
+ .off('keyup');
+
+ if (this.eventSupported('keydown')) {
+ this.$element.off('keydown');
+ }
+
+ this.$menu.remove();
+ this.destroyed = true;
+ },
+
+ eventSupported: function (eventName) {
+ var isSupported = eventName in this.$element;
+ if (!isSupported) {
+ this.$element.setAttribute(eventName, 'return;');
+ isSupported = typeof this.$element[eventName] === 'function';
+ }
+ return isSupported;
+ },
+
+ move: function (e) {
+ if (!this.shown) return;
+
+ switch (e.keyCode) {
+ case 9: // tab
+ case 13: // enter
+ case 27: // escape
+ e.preventDefault();
+ break;
+
+ case 38: // up arrow
+ // with the shiftKey (this is actually the left parenthesis)
+ if (e.shiftKey) return;
+ e.preventDefault();
+ this.prev();
+ break;
+
+ case 40: // down arrow
+ // with the shiftKey (this is actually the right parenthesis)
+ if (e.shiftKey) return;
+ e.preventDefault();
+ this.next();
+ break;
+ }
+ },
+
+ keydown: function (e) {
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
+ if (!this.shown && e.keyCode == 40) {
+ this.lookup();
+ } else {
+ this.move(e);
+ }
+ },
+
+ keypress: function (e) {
+ if (this.suppressKeyPressRepeat) return;
+ this.move(e);
+ },
+
+ input: function (e) {
+ // This is a fixed for IE10/11 that fires the input event when a placehoder is changed
+ // (https://connect.microsoft.com/IE/feedback/details/810538/ie-11-fires-input-event-on-focus)
+ var currentValue = this.$element.val() || this.$element.text();
+ if (this.value !== currentValue) {
+ this.value = currentValue;
+ this.lookup();
+ }
+ },
+
+ keyup: function (e) {
+ if (this.destroyed) {
+ return;
+ }
+ switch (e.keyCode) {
+ case 40: // down arrow
+ case 38: // up arrow
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ break;
+
+ case 9: // tab
+ case 13: // enter
+ if (!this.shown) return;
+ this.select();
+ break;
+
+ case 27: // escape
+ if (!this.shown) return;
+ this.hide();
+ break;
+ }
+
+
+ },
+
+ focus: function (e) {
+ if (!this.focused) {
+ this.focused = true;
+ if (this.options.showHintOnFocus && this.skipShowHintOnFocus !== true) {
+ if(this.options.showHintOnFocus === "all") {
+ this.lookup("");
+ } else {
+ this.lookup();
+ }
+ }
+ }
+ if (this.skipShowHintOnFocus) {
+ this.skipShowHintOnFocus = false;
+ }
+ },
+
+ blur: function (e) {
+ if (!this.mousedover && !this.mouseddown && this.shown) {
+ this.hide();
+ this.focused = false;
+ } else if (this.mouseddown) {
+ // This is for IE that blurs the input when user clicks on scroll.
+ // We set the focus back on the input and prevent the lookup to occur again
+ this.skipShowHintOnFocus = true;
+ this.$element.focus();
+ this.mouseddown = false;
+ }
+ },
+
+ click: function (e) {
+ e.preventDefault();
+ this.skipShowHintOnFocus = true;
+ this.select();
+ this.$element.focus();
+ this.hide();
+ },
+
+ mouseenter: function (e) {
+ this.mousedover = true;
+ this.$menu.find('.active').removeClass('active');
+ $(e.currentTarget).addClass('active');
+ },
+
+ mouseleave: function (e) {
+ this.mousedover = false;
+ if (!this.focused && this.shown) this.hide();
+ },
+
+ /**
+ * We track the mousedown for IE. When clicking on the menu scrollbar, IE makes the input blur thus hiding the menu.
+ */
+ mousedown: function (e) {
+ this.mouseddown = true;
+ this.$menu.one("mouseup", function(e){
+ // IE won't fire this, but FF and Chrome will so we reset our flag for them here
+ this.mouseddown = false;
+ }.bind(this));
+ },
+
+ };
+
+
+ /* TYPEAHEAD PLUGIN DEFINITION
+ * =========================== */
+
+ var old = $.fn.typeahead;
+
+ $.fn.typeahead = function (option) {
+ var arg = arguments;
+ if (typeof option == 'string' && option == 'getActive') {
+ return this.data('active');
+ }
+ return this.each(function () {
+ var $this = $(this);
+ var data = $this.data('typeahead');
+ var options = typeof option == 'object' && option;
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)));
+ if (typeof option == 'string' && data[option]) {
+ if (arg.length > 1) {
+ data[option].apply(data, Array.prototype.slice.call(arg, 1));
+ } else {
+ data[option]();
+ }
+ }
+ });
+ };
+
+ $.fn.typeahead.defaults = {
+ source: [],
+ items: 8,
+ menu: '<ul class="typeahead dropdown-menu" role="listbox"></ul>',
+ item: '<li><a class="dropdown-item" href="#" role="option"></a></li>',
+ minLength: 1,
+ scrollHeight: 0,
+ autoSelect: true,
+ afterSelect: $.noop,
+ addItem: false,
+ delay: 0,
+ separator: 'category',
+ headerHtml: '<li class="dropdown-header"></li>',
+ headerDivider: '<li class="divider" role="separator"></li>'
+ };
+
+ $.fn.typeahead.Constructor = Typeahead;
+
+ /* TYPEAHEAD NO CONFLICT
+ * =================== */
+
+ $.fn.typeahead.noConflict = function () {
+ $.fn.typeahead = old;
+ return this;
+ };
+
+
+ /* TYPEAHEAD DATA-API
+ * ================== */
+
+ $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
+ var $this = $(this);
+ if ($this.data('typeahead')) return;
+ $this.typeahead($this.data());
+ });
+
+}));