Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
15403 manish.sha 1
/*
2
 * typeahead.js
3
 * https://github.com/twitter/typeahead.js
4
 * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
5
 */
6
 
7
var Dropdown = (function() {
8
  'use strict';
9
 
10
  // constructor
11
  // -----------
12
 
13
  function Dropdown(o) {
14
    var that = this, onSuggestionClick, onSuggestionMouseEnter,
15
        onSuggestionMouseLeave;
16
 
17
    o = o || {};
18
 
19
    if (!o.menu) {
20
      $.error('menu is required');
21
    }
22
 
23
    this.isOpen = false;
24
    this.isEmpty = true;
25
 
26
    this.datasets = _.map(o.datasets, initializeDataset);
27
 
28
    // bound functions
29
    onSuggestionClick = _.bind(this._onSuggestionClick, this);
30
    onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);
31
    onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);
32
 
33
    this.$menu = $(o.menu)
34
    .on('click.tt', '.tt-suggestion', onSuggestionClick)
35
    .on('mouseenter.tt', '.tt-suggestion', onSuggestionMouseEnter)
36
    .on('mouseleave.tt', '.tt-suggestion', onSuggestionMouseLeave);
37
 
38
    _.each(this.datasets, function(dataset) {
39
      that.$menu.append(dataset.getRoot());
40
      dataset.onSync('rendered', that._onRendered, that);
41
    });
42
  }
43
 
44
  // instance methods
45
  // ----------------
46
 
47
  _.mixin(Dropdown.prototype, EventEmitter, {
48
 
49
    // ### private
50
 
51
    _onSuggestionClick: function onSuggestionClick($e) {
52
      this.trigger('suggestionClicked', $($e.currentTarget));
53
    },
54
 
55
    _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {
56
      this._removeCursor();
57
      this._setCursor($($e.currentTarget), true);
58
    },
59
 
60
    _onSuggestionMouseLeave: function onSuggestionMouseLeave() {
61
      this._removeCursor();
62
    },
63
 
64
    _onRendered: function onRendered() {
65
      this.isEmpty = _.every(this.datasets, isDatasetEmpty);
66
 
67
      this.isEmpty ? this._hide() : (this.isOpen && this._show());
68
 
69
      this.trigger('datasetRendered');
70
 
71
      function isDatasetEmpty(dataset) { return dataset.isEmpty(); }
72
    },
73
 
74
    _hide: function() {
75
      this.$menu.hide();
76
    },
77
 
78
    _show: function() {
79
      // can't use jQuery#show because $menu is a span element we want
80
      // display: block; not dislay: inline;
81
      this.$menu.css('display', 'block');
82
    },
83
 
84
    _getSuggestions: function getSuggestions() {
85
      return this.$menu.find('.tt-suggestion');
86
    },
87
 
88
    _getCursor: function getCursor() {
89
      return this.$menu.find('.tt-cursor').first();
90
    },
91
 
92
    _setCursor: function setCursor($el, silent) {
93
      $el.first().addClass('tt-cursor');
94
 
95
      !silent && this.trigger('cursorMoved');
96
    },
97
 
98
    _removeCursor: function removeCursor() {
99
      this._getCursor().removeClass('tt-cursor');
100
    },
101
 
102
    _moveCursor: function moveCursor(increment) {
103
      var $suggestions, $oldCursor, newCursorIndex, $newCursor;
104
 
105
      if (!this.isOpen) { return; }
106
 
107
      $oldCursor = this._getCursor();
108
      $suggestions = this._getSuggestions();
109
 
110
      this._removeCursor();
111
 
112
      // shifting before and after modulo to deal with -1 index
113
      newCursorIndex = $suggestions.index($oldCursor) + increment;
114
      newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;
115
 
116
      if (newCursorIndex === -1) {
117
        this.trigger('cursorRemoved');
118
 
119
        return;
120
      }
121
 
122
      else if (newCursorIndex < -1) {
123
        newCursorIndex = $suggestions.length - 1;
124
      }
125
 
126
      this._setCursor($newCursor = $suggestions.eq(newCursorIndex));
127
 
128
      // in the case of scrollable overflow
129
      // make sure the cursor is visible in the menu
130
      this._ensureVisible($newCursor);
131
    },
132
 
133
    _ensureVisible: function ensureVisible($el) {
134
      var elTop, elBottom, menuScrollTop, menuHeight;
135
 
136
      elTop = $el.position().top;
137
      elBottom = elTop + $el.outerHeight(true);
138
      menuScrollTop = this.$menu.scrollTop();
139
      menuHeight = this.$menu.height() +
140
        parseInt(this.$menu.css('paddingTop'), 10) +
141
        parseInt(this.$menu.css('paddingBottom'), 10);
142
 
143
      if (elTop < 0) {
144
        this.$menu.scrollTop(menuScrollTop + elTop);
145
      }
146
 
147
      else if (menuHeight < elBottom) {
148
        this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));
149
      }
150
    },
151
 
152
    // ### public
153
 
154
    close: function close() {
155
      if (this.isOpen) {
156
        this.isOpen = false;
157
 
158
        this._removeCursor();
159
        this._hide();
160
 
161
        this.trigger('closed');
162
      }
163
    },
164
 
165
    open: function open() {
166
      if (!this.isOpen) {
167
        this.isOpen = true;
168
 
169
        !this.isEmpty && this._show();
170
 
171
        this.trigger('opened');
172
      }
173
    },
174
 
175
    setLanguageDirection: function setLanguageDirection(dir) {
176
      this.$menu.css(dir === 'ltr' ? css.ltr : css.rtl);
177
    },
178
 
179
    moveCursorUp: function moveCursorUp() {
180
      this._moveCursor(-1);
181
    },
182
 
183
    moveCursorDown: function moveCursorDown() {
184
      this._moveCursor(+1);
185
    },
186
 
187
    getDatumForSuggestion: function getDatumForSuggestion($el) {
188
      var datum = null;
189
 
190
      if ($el.length) {
191
        datum = {
192
          raw: Dataset.extractDatum($el),
193
          value: Dataset.extractValue($el),
194
          datasetName: Dataset.extractDatasetName($el)
195
        };
196
      }
197
 
198
      return datum;
199
    },
200
 
201
    getDatumForCursor: function getDatumForCursor() {
202
      return this.getDatumForSuggestion(this._getCursor().first());
203
    },
204
 
205
    getDatumForTopSuggestion: function getDatumForTopSuggestion() {
206
      return this.getDatumForSuggestion(this._getSuggestions().first());
207
    },
208
 
209
    update: function update(query) {
210
      _.each(this.datasets, updateDataset);
211
 
212
      function updateDataset(dataset) { dataset.update(query); }
213
    },
214
 
215
    empty: function empty() {
216
      _.each(this.datasets, clearDataset);
217
      this.isEmpty = true;
218
 
219
      function clearDataset(dataset) { dataset.clear(); }
220
    },
221
 
222
    isVisible: function isVisible() {
223
      return this.isOpen && !this.isEmpty;
224
    },
225
 
226
    destroy: function destroy() {
227
      this.$menu.off('.tt');
228
 
229
      this.$menu = null;
230
 
231
      _.each(this.datasets, destroyDataset);
232
 
233
      function destroyDataset(dataset) { dataset.destroy(); }
234
    }
235
  });
236
 
237
  return Dropdown;
238
 
239
  // helper functions
240
  // ----------------
241
 
242
  function initializeDataset(oDataset) {
243
    return new Dataset(oDataset);
244
  }
245
})();