Blame | Last modification | View Log | RSS feed
/** typeahead.js* https://github.com/twitter/typeahead.js* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT*/var Dropdown = (function() {'use strict';// constructor// -----------function Dropdown(o) {var that = this, onSuggestionClick, onSuggestionMouseEnter,onSuggestionMouseLeave;o = o || {};if (!o.menu) {$.error('menu is required');}this.isOpen = false;this.isEmpty = true;this.datasets = _.map(o.datasets, initializeDataset);// bound functionsonSuggestionClick = _.bind(this._onSuggestionClick, this);onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);this.$menu = $(o.menu).on('click.tt', '.tt-suggestion', onSuggestionClick).on('mouseenter.tt', '.tt-suggestion', onSuggestionMouseEnter).on('mouseleave.tt', '.tt-suggestion', onSuggestionMouseLeave);_.each(this.datasets, function(dataset) {that.$menu.append(dataset.getRoot());dataset.onSync('rendered', that._onRendered, that);});}// instance methods// ----------------_.mixin(Dropdown.prototype, EventEmitter, {// ### private_onSuggestionClick: function onSuggestionClick($e) {this.trigger('suggestionClicked', $($e.currentTarget));},_onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {this._removeCursor();this._setCursor($($e.currentTarget), true);},_onSuggestionMouseLeave: function onSuggestionMouseLeave() {this._removeCursor();},_onRendered: function onRendered() {this.isEmpty = _.every(this.datasets, isDatasetEmpty);this.isEmpty ? this._hide() : (this.isOpen && this._show());this.trigger('datasetRendered');function isDatasetEmpty(dataset) { return dataset.isEmpty(); }},_hide: function() {this.$menu.hide();},_show: function() {// can't use jQuery#show because $menu is a span element we want// display: block; not dislay: inline;this.$menu.css('display', 'block');},_getSuggestions: function getSuggestions() {return this.$menu.find('.tt-suggestion');},_getCursor: function getCursor() {return this.$menu.find('.tt-cursor').first();},_setCursor: function setCursor($el, silent) {$el.first().addClass('tt-cursor');!silent && this.trigger('cursorMoved');},_removeCursor: function removeCursor() {this._getCursor().removeClass('tt-cursor');},_moveCursor: function moveCursor(increment) {var $suggestions, $oldCursor, newCursorIndex, $newCursor;if (!this.isOpen) { return; }$oldCursor = this._getCursor();$suggestions = this._getSuggestions();this._removeCursor();// shifting before and after modulo to deal with -1 indexnewCursorIndex = $suggestions.index($oldCursor) + increment;newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;if (newCursorIndex === -1) {this.trigger('cursorRemoved');return;}else if (newCursorIndex < -1) {newCursorIndex = $suggestions.length - 1;}this._setCursor($newCursor = $suggestions.eq(newCursorIndex));// in the case of scrollable overflow// make sure the cursor is visible in the menuthis._ensureVisible($newCursor);},_ensureVisible: function ensureVisible($el) {var elTop, elBottom, menuScrollTop, menuHeight;elTop = $el.position().top;elBottom = elTop + $el.outerHeight(true);menuScrollTop = this.$menu.scrollTop();menuHeight = this.$menu.height() +parseInt(this.$menu.css('paddingTop'), 10) +parseInt(this.$menu.css('paddingBottom'), 10);if (elTop < 0) {this.$menu.scrollTop(menuScrollTop + elTop);}else if (menuHeight < elBottom) {this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));}},// ### publicclose: function close() {if (this.isOpen) {this.isOpen = false;this._removeCursor();this._hide();this.trigger('closed');}},open: function open() {if (!this.isOpen) {this.isOpen = true;!this.isEmpty && this._show();this.trigger('opened');}},setLanguageDirection: function setLanguageDirection(dir) {this.$menu.css(dir === 'ltr' ? css.ltr : css.rtl);},moveCursorUp: function moveCursorUp() {this._moveCursor(-1);},moveCursorDown: function moveCursorDown() {this._moveCursor(+1);},getDatumForSuggestion: function getDatumForSuggestion($el) {var datum = null;if ($el.length) {datum = {raw: Dataset.extractDatum($el),value: Dataset.extractValue($el),datasetName: Dataset.extractDatasetName($el)};}return datum;},getDatumForCursor: function getDatumForCursor() {return this.getDatumForSuggestion(this._getCursor().first());},getDatumForTopSuggestion: function getDatumForTopSuggestion() {return this.getDatumForSuggestion(this._getSuggestions().first());},update: function update(query) {_.each(this.datasets, updateDataset);function updateDataset(dataset) { dataset.update(query); }},empty: function empty() {_.each(this.datasets, clearDataset);this.isEmpty = true;function clearDataset(dataset) { dataset.clear(); }},isVisible: function isVisible() {return this.isOpen && !this.isEmpty;},destroy: function destroy() {this.$menu.off('.tt');this.$menu = null;_.each(this.datasets, destroyDataset);function destroyDataset(dataset) { dataset.destroy(); }}});return Dropdown;// helper functions// ----------------function initializeDataset(oDataset) {return new Dataset(oDataset);}})();