Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / static / im / js / jquery.dropkick-1.0.0.js @ de57f345

History | View | Annotate | Download (10.9 kB)

1
/**
2
 * DropKick
3
 *
4
 * Highly customizable <select> lists
5
 * https://github.com/JamieLottering/DropKick
6
 *
7
 * &copy; 2011 Jamie Lottering <http://github.com/JamieLottering>
8
 *                        <http://twitter.com/JamieLottering>
9
 * 
10
 */
11

    
12
(function ($, window, document) {
13

    
14
  function fixLabel (lbl){
15
    if ( lbl.length > 25 ) {
16
            return lbl.substring(0,25)+'...';
17
    } else {
18
            return lbl;
19
    }
20
           console.info(lbl.length);
21
     
22
  }
23

    
24
  var ie6 = false;
25

    
26
  // Help prevent flashes of unstyled content
27
  if ($.browser.msie && $.browser.version.substr(0, 1) < 7) {
28
    ie6 = true;
29
  } else {
30
    document.documentElement.className = document.documentElement.className + ' dk_fouc';
31
  }
32
  
33
  var
34
    // Public methods exposed to $.fn.dropkick()
35
    methods = {},
36

    
37
    // Cache every <select> element that gets dropkicked
38
    lists   = [],
39

    
40
    // Convenience keys for keyboard navigation
41
    keyMap = {
42
      'left'  : 37,
43
      'up'    : 38,
44
      'right' : 39,
45
      'down'  : 40,
46
      'enter' : 13
47
    },
48

    
49
    // HTML template for the dropdowns
50
    dropdownTemplate = [
51
      '<div class="dk_container" id="dk_container_{{ id }}" tabindex="{{ tabindex }}" style="display:inline-block;">',
52
        '<a class="dk_toggle">',
53
          '<span class="dk_label">{{ label }}</span>',
54
        '</a>',
55
        '<div class="dk_options">',
56
          '<ul class="dk_options_inner">',
57
          '</ul>',
58
        '</div>',
59
      '</div>'
60
    ].join(''),
61

    
62
    // HTML template for dropdown options
63
    optionTemplate = '<li class="{{ current }}"><a data-dk-dropdown-value="{{ value }}">{{ text }}</a></li>',
64

    
65
    // Some nice default values
66
    defaults = {
67
      startSpeed : 1000,  // I recommend a high value here, I feel it makes the changes less noticeable to the user
68
      theme  : false,
69
      change : false
70
    },
71

    
72
    // Make sure we only bind keydown on the document once
73
    keysBound = false
74
  ;
75

    
76
  // Called by using $('foo').dropkick();
77
  methods.init = function (settings) {
78
    settings = $.extend({}, defaults, settings);
79

    
80
    return this.each(function () {
81
      var
82
        // The current <select> element
83
        $select = $(this),
84

    
85
        // Store a reference to the originally selected <option> element
86
        $original = $select.find(':selected').first(),
87

    
88
        // Save all of the <option> elements
89
        $options = $select.find('option'),
90

    
91
        // We store lots of great stuff using jQuery data
92
        data = $select.data('dropkick') || {},
93

    
94
        // This gets applied to the 'dk_container' element
95
        id = $select.attr('id') || $select.attr('name'),
96

    
97
        // This gets updated to be equal to the longest <option> element
98
        width  = settings.width || $select.outerWidth(),
99

    
100
        // Check if we have a tabindex set or not
101
        tabindex  = $select.attr('tabindex') ? $select.attr('tabindex') : '',
102

    
103
        // The completed dk_container element
104
        $dk = false,
105

    
106
        theme
107
      ;
108

    
109
      // Dont do anything if we've already setup dropkick on this element
110
      if (data.id) {
111
        return $select;
112
      } else {
113
        data.settings  = settings;
114
        data.tabindex  = tabindex;
115
        data.id        = id;
116
        data.$original = $original;
117
        data.$select   = $select;
118
        data.value     = _notBlank($select.val()) || _notBlank($original.attr('value'));
119
        data.label     = $original.text();
120
        data.options   = $options;
121
      }
122
          data.label = fixLabel(data.label);
123
      // Build the dropdown HTML
124
      $dk = _build(dropdownTemplate, data);
125

    
126
      // Make the dropdown fixed width if desired
127
      $dk.find('.dk_toggle').css({
128
        'width' : width + 'px'
129
      });
130

    
131
      // Hide the <select> list and place our new one in front of it
132
      $select.before($dk);
133

    
134
      // Update the reference to $dk
135
      $dk = $('#dk_container_' + id).fadeIn(settings.startSpeed);
136

    
137
      // Save the current theme
138
      theme = settings.theme ? settings.theme : 'default';
139
      $dk.addClass('dk_theme_' + theme);
140
      data.theme = theme;
141

    
142
      // Save the updated $dk reference into our data object
143
      data.$dk = $dk;
144

    
145
      // Save the dropkick data onto the <select> element
146
      $select.data('dropkick', data);
147

    
148
      // Do the same for the dropdown, but add a few helpers
149
      $dk.data('dropkick', data);
150

    
151
      lists[lists.length] = $select;
152

    
153
      // Focus events
154
      $dk.bind('focus.dropkick', function (e) {
155
        $dk.addClass('dk_focus');
156
      }).bind('blur.dropkick', function (e) {
157
        $dk.removeClass('dk_open dk_focus');
158
      });
159

    
160
      setTimeout(function () {
161
        $select.hide();
162
      }, 0);
163
    });
164
  };
165

    
166
  // Allows dynamic theme changes
167
  methods.theme = function (newTheme) {
168
    var
169
      $select   = $(this),
170
      list      = $select.data('dropkick'),
171
      $dk       = list.$dk,
172
      oldtheme  = 'dk_theme_' + list.theme
173
    ;
174

    
175
    $dk.removeClass(oldtheme).addClass('dk_theme_' + newTheme);
176

    
177
    list.theme = newTheme;
178
  };
179

    
180
  // Reset all <selects and dropdowns in our lists array
181
  methods.reset = function () {
182
    for (var i = 0, l = lists.length; i < l; i++) {
183
      var
184
        listData  = lists[i].data('dropkick'),
185
        $dk       = listData.$dk,
186
        $current  = $dk.find('li').first()
187
      ;
188

    
189
      $dk.find('.dk_label').text(fixLabel(listData.label));
190
      $dk.find('.dk_options_inner').animate({ scrollTop: 0 }, 0);
191

    
192
      _setCurrent($current, $dk);
193
      _updateFields($current, $dk, true);
194
    }
195
  };
196

    
197
  // Expose the plugin
198
  $.fn.dropkick = function (method) {
199
    if (!ie6) {
200
      if (methods[method]) {
201
        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
202
      } else if (typeof method === 'object' || ! method) {
203
        return methods.init.apply(this, arguments);
204
      }
205
    }
206
  };
207

    
208
  // private
209
  function _handleKeyBoardNav(e, $dk) {
210
    var
211
      code     = e.keyCode,
212
      data     = $dk.data('dropkick'),
213
      options  = $dk.find('.dk_options'),
214
      open     = $dk.hasClass('dk_open'),
215
      current  = $dk.find('.dk_option_current'),
216
      first    = options.find('li').first(),
217
      last     = options.find('li').last(),
218
      next,
219
      prev
220
    ;
221

    
222
    switch (code) {
223
      case keyMap.enter:
224
        if (open) {
225
          _updateFields(current.find('a'), $dk);
226
          _closeDropdown($dk);
227
        } else {
228
          _openDropdown($dk);
229
        }
230
        e.preventDefault();
231
      break;
232

    
233
      case keyMap.up:
234
        prev = current.prev('li');
235
        if (open) {
236
          if (prev.length) {
237
            _setCurrent(prev, $dk);
238
          } else {
239
            _setCurrent(last, $dk);
240
          }
241
        } else {
242
          _openDropdown($dk);
243
        }
244
        e.preventDefault();
245
      break;
246

    
247
      case keyMap.down:
248
        if (open) {
249
          next = current.next('li').first();
250
          if (next.length) {
251
            _setCurrent(next, $dk);
252
          } else {
253
            _setCurrent(first, $dk);
254
          }
255
        } else {
256
          _openDropdown($dk);
257
        }
258
        e.preventDefault();
259
      break;
260

    
261
      default:
262
      break;
263
    }
264
  }
265

    
266
  // Update the <select> value, and the dropdown label
267
  function _updateFields(option, $dk, reset) {
268
    var value, label, data;
269

    
270
    value = option.attr('data-dk-dropdown-value');
271
    label = option.text();
272
    data  = $dk.data('dropkick');
273

    
274
    $select = data.$select;
275
    $select.val(value);
276

    
277
    $dk.find('.dk_label').text(fixLabel(label));
278

    
279
    reset = reset || false;
280

    
281
    if (data.settings.change && !reset) {
282
      data.settings.change.call($select, value, label);
283
    }
284
  }
285

    
286
  // Set the currently selected option
287
  function _setCurrent($current, $dk) {
288
    $dk.find('.dk_option_current').removeClass('dk_option_current');
289
    $current.addClass('dk_option_current');
290

    
291
    _setScrollPos($dk, $current);
292
  }
293

    
294
  function _setScrollPos($dk, anchor) {
295
    var height = anchor.prevAll('li').outerHeight() * anchor.prevAll('li').length;
296
    $dk.find('.dk_options_inner').animate({ scrollTop: height + 'px' }, 0);
297
  }
298

    
299
  // Close a dropdown
300
  function _closeDropdown($dk) {
301
    $dk.removeClass('dk_open');
302
  }
303

    
304
  // Open a dropdown
305
  function _openDropdown($dk) {
306
    var data = $dk.data('dropkick');
307
    $dk.find('.dk_options').css({ top : $dk.find('.dk_toggle').outerHeight() - 1 });
308
    $dk.toggleClass('dk_open');
309

    
310
  }
311

    
312
  /**
313
   * Turn the dropdownTemplate into a jQuery object and fill in the variables.
314
   */
315
  function _build (tpl, view) {
316
    var
317
      // Template for the dropdown
318
      template  = tpl,
319
      // Holder of the dropdowns options
320
      options   = [],
321
      $dk
322
    ;
323

    
324
    template = template.replace('{{ id }}', view.id);
325
    template = template.replace('{{ label }}', view.label);
326
    template = template.replace('{{ tabindex }}', view.tabindex);
327

    
328
    if (view.options && view.options.length) {
329
      for (var i = 0, l = view.options.length; i < l; i++) {
330
        var
331
          $option   = $(view.options[i]),
332
          current   = 'dk_option_current',
333
          oTemplate = optionTemplate
334
        ;
335

    
336
        oTemplate = oTemplate.replace('{{ value }}', $option.val());
337
        oTemplate = oTemplate.replace('{{ current }}', (_notBlank($option.val()) === view.value) ? current : '');
338
        oTemplate = oTemplate.replace('{{ text }}', $option.text());
339

    
340
        options[options.length] = oTemplate;
341
      }
342
    }
343

    
344
    $dk = $(template);
345
    $dk.find('.dk_options_inner').html(options.join(''));
346

    
347
    return $dk;
348
  }
349

    
350
  function _notBlank(text) {
351
    return ($.trim(text).length > 0) ? text : false;
352
  }
353

    
354
  $(function () {
355

    
356
    // Handle click events on the dropdown toggler
357
    $('.dk_toggle').live('click', function (e) {
358
      var $dk  = $(this).parents('.dk_container').first();
359

    
360
      _openDropdown($dk);
361

    
362
      if ("ontouchstart" in window) {
363
        $dk.addClass('dk_touch');
364
        $dk.find('.dk_options_inner').addClass('scrollable vertical');
365
      }
366

    
367
      e.preventDefault();
368
      return false;
369
    });
370

    
371
    // Handle click events on individual dropdown options
372
    $('.dk_options a').live(($.browser.msie ? 'mousedown' : 'click'), function (e) {
373
      var
374
        $option = $(this),
375
        $dk     = $option.parents('.dk_container').first(),
376
        data    = $dk.data('dropkick')
377
      ;
378
    
379
      _closeDropdown($dk);
380
      _updateFields($option, $dk);
381
      _setCurrent($option.parent(), $dk);
382
    
383
      e.preventDefault();
384
      return false;
385
    });
386

    
387
    // Setup keyboard nav
388
    $(document).bind('keydown.dk_nav', function (e) {
389
      var
390
        // Look for an open dropdown...
391
        $open    = $('.dk_container.dk_open'),
392

    
393
        // Look for a focused dropdown
394
        $focused = $('.dk_container.dk_focus'),
395

    
396
        // Will be either $open, $focused, or null
397
        $dk = null
398
      ;
399

    
400
      // If we have an open dropdown, key events should get sent to that one
401
      if ($open.length) {
402
        $dk = $open;
403
      } else if ($focused.length && !$open.length) {
404
        // But if we have no open dropdowns, use the focused dropdown instead
405
        $dk = $focused;
406
      }
407

    
408
      if ($dk) {
409
        _handleKeyBoardNav(e, $dk);
410
      }
411
    });
412
  });
413
})(jQuery, window, document);