root / snf-astakos-app / astakos / im / static / im / js / jquery.dropkick-1.0.0.js @ 0f4a8a68
History | View | Annotate | Download (10.6 kB)
1 |
/**
|
---|---|
2 |
* DropKick
|
3 |
*
|
4 |
* Highly customizable <select> lists
|
5 |
* https://github.com/JamieLottering/DropKick
|
6 |
*
|
7 |
* © 2011 Jamie Lottering <http://github.com/JamieLottering>
|
8 |
* <http://twitter.com/JamieLottering>
|
9 |
*
|
10 |
*/
|
11 |
(function ($, window, document) { |
12 |
|
13 |
var ie6 = false; |
14 |
|
15 |
// Help prevent flashes of unstyled content
|
16 |
if ($.browser.msie && $.browser.version.substr(0, 1) < 7) { |
17 |
ie6 = true;
|
18 |
} else {
|
19 |
document.documentElement.className = document.documentElement.className + ' dk_fouc';
|
20 |
} |
21 |
|
22 |
var
|
23 |
// Public methods exposed to $.fn.dropkick()
|
24 |
methods = {}, |
25 |
|
26 |
// Cache every <select> element that gets dropkicked
|
27 |
lists = [], |
28 |
|
29 |
// Convenience keys for keyboard navigation
|
30 |
keyMap = { |
31 |
'left' : 37, |
32 |
'up' : 38, |
33 |
'right' : 39, |
34 |
'down' : 40, |
35 |
'enter' : 13 |
36 |
}, |
37 |
|
38 |
// HTML template for the dropdowns
|
39 |
dropdownTemplate = [ |
40 |
'<div class="dk_container" id="dk_container_{{ id }}" tabindex="{{ tabindex }}">',
|
41 |
'<a class="dk_toggle">',
|
42 |
'<span class="dk_label">{{ label }}</span>',
|
43 |
'</a>',
|
44 |
'<div class="dk_options">',
|
45 |
'<ul class="dk_options_inner">',
|
46 |
'</ul>',
|
47 |
'</div>',
|
48 |
'</div>'
|
49 |
].join(''),
|
50 |
|
51 |
// HTML template for dropdown options
|
52 |
optionTemplate = '<li class="{{ current }}"><a data-dk-dropdown-value="{{ value }}">{{ text }}</a></li>',
|
53 |
|
54 |
// Some nice default values
|
55 |
defaults = { |
56 |
startSpeed : 1000, // I recommend a high value here, I feel it makes the changes less noticeable to the user |
57 |
theme : false, |
58 |
change : false |
59 |
}, |
60 |
|
61 |
// Make sure we only bind keydown on the document once
|
62 |
keysBound = false
|
63 |
; |
64 |
|
65 |
// Called by using $('foo').dropkick();
|
66 |
methods.init = function (settings) { |
67 |
settings = $.extend({}, defaults, settings);
|
68 |
|
69 |
return this.each(function () { |
70 |
var
|
71 |
// The current <select> element
|
72 |
$select = $(this), |
73 |
|
74 |
// Store a reference to the originally selected <option> element
|
75 |
$original = $select.find(':selected').first(), |
76 |
|
77 |
// Save all of the <option> elements
|
78 |
$options = $select.find('option'), |
79 |
|
80 |
// We store lots of great stuff using jQuery data
|
81 |
data = $select.data('dropkick') || {}, |
82 |
|
83 |
// This gets applied to the 'dk_container' element
|
84 |
id = $select.attr('id') || $select.attr('name'), |
85 |
|
86 |
// This gets updated to be equal to the longest <option> element
|
87 |
width = settings.width || $select.outerWidth(),
|
88 |
|
89 |
// Check if we have a tabindex set or not
|
90 |
tabindex = $select.attr('tabindex') ? $select.attr('tabindex') : '', |
91 |
|
92 |
// The completed dk_container element
|
93 |
$dk = false, |
94 |
|
95 |
theme |
96 |
; |
97 |
|
98 |
// Dont do anything if we've already setup dropkick on this element
|
99 |
if (data.id) {
|
100 |
return $select; |
101 |
} else {
|
102 |
data.settings = settings; |
103 |
data.tabindex = tabindex; |
104 |
data.id = id; |
105 |
data.$original = $original; |
106 |
data.$select = $select; |
107 |
data.value = _notBlank($select.val()) || _notBlank($original.attr('value')); |
108 |
data.label = $original.text();
|
109 |
data.options = $options;
|
110 |
} |
111 |
|
112 |
// Build the dropdown HTML
|
113 |
$dk = _build(dropdownTemplate, data);
|
114 |
|
115 |
// Make the dropdown fixed width if desired
|
116 |
$dk.find('.dk_toggle').css({ |
117 |
'width' : width + 'px' |
118 |
}); |
119 |
|
120 |
// Hide the <select> list and place our new one in front of it
|
121 |
$select.before($dk); |
122 |
|
123 |
// Update the reference to $dk
|
124 |
$dk = $('#dk_container_' + id).fadeIn(settings.startSpeed); |
125 |
|
126 |
// Save the current theme
|
127 |
theme = settings.theme ? settings.theme : 'default';
|
128 |
$dk.addClass('dk_theme_' + theme); |
129 |
data.theme = theme; |
130 |
|
131 |
// Save the updated $dk reference into our data object
|
132 |
data.$dk = $dk; |
133 |
|
134 |
// Save the dropkick data onto the <select> element
|
135 |
$select.data('dropkick', data); |
136 |
|
137 |
// Do the same for the dropdown, but add a few helpers
|
138 |
$dk.data('dropkick', data); |
139 |
|
140 |
lists[lists.length] = $select;
|
141 |
|
142 |
// Focus events
|
143 |
$dk.bind('focus.dropkick', function (e) { |
144 |
$dk.addClass('dk_focus'); |
145 |
}).bind('blur.dropkick', function (e) { |
146 |
$dk.removeClass('dk_open dk_focus'); |
147 |
}); |
148 |
|
149 |
setTimeout(function () {
|
150 |
$select.hide();
|
151 |
}, 0);
|
152 |
}); |
153 |
}; |
154 |
|
155 |
// Allows dynamic theme changes
|
156 |
methods.theme = function (newTheme) { |
157 |
var
|
158 |
$select = $(this), |
159 |
list = $select.data('dropkick'), |
160 |
$dk = list.$dk, |
161 |
oldtheme = 'dk_theme_' + list.theme
|
162 |
; |
163 |
|
164 |
$dk.removeClass(oldtheme).addClass('dk_theme_' + newTheme); |
165 |
|
166 |
list.theme = newTheme; |
167 |
}; |
168 |
|
169 |
// Reset all <selects and dropdowns in our lists array
|
170 |
methods.reset = function () { |
171 |
for (var i = 0, l = lists.length; i < l; i++) { |
172 |
var
|
173 |
listData = lists[i].data('dropkick'),
|
174 |
$dk = listData.$dk, |
175 |
$current = $dk.find('li').first() |
176 |
; |
177 |
|
178 |
$dk.find('.dk_label').text(listData.label); |
179 |
$dk.find('.dk_options_inner').animate({ scrollTop: 0 }, 0); |
180 |
|
181 |
_setCurrent($current, $dk); |
182 |
_updateFields($current, $dk, true); |
183 |
} |
184 |
}; |
185 |
|
186 |
// Expose the plugin
|
187 |
$.fn.dropkick = function (method) { |
188 |
if (!ie6) {
|
189 |
if (methods[method]) {
|
190 |
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); |
191 |
} else if (typeof method === 'object' || ! method) { |
192 |
return methods.init.apply(this, arguments); |
193 |
} |
194 |
} |
195 |
}; |
196 |
|
197 |
// private
|
198 |
function _handleKeyBoardNav(e, $dk) { |
199 |
var
|
200 |
code = e.keyCode, |
201 |
data = $dk.data('dropkick'), |
202 |
options = $dk.find('.dk_options'), |
203 |
open = $dk.hasClass('dk_open'), |
204 |
current = $dk.find('.dk_option_current'), |
205 |
first = options.find('li').first(),
|
206 |
last = options.find('li').last(),
|
207 |
next, |
208 |
prev |
209 |
; |
210 |
|
211 |
switch (code) {
|
212 |
case keyMap.enter:
|
213 |
if (open) {
|
214 |
_updateFields(current.find('a'), $dk); |
215 |
_closeDropdown($dk);
|
216 |
} else {
|
217 |
_openDropdown($dk);
|
218 |
} |
219 |
e.preventDefault(); |
220 |
break;
|
221 |
|
222 |
case keyMap.up:
|
223 |
prev = current.prev('li');
|
224 |
if (open) {
|
225 |
if (prev.length) {
|
226 |
_setCurrent(prev, $dk);
|
227 |
} else {
|
228 |
_setCurrent(last, $dk);
|
229 |
} |
230 |
} else {
|
231 |
_openDropdown($dk);
|
232 |
} |
233 |
e.preventDefault(); |
234 |
break;
|
235 |
|
236 |
case keyMap.down:
|
237 |
if (open) {
|
238 |
next = current.next('li').first();
|
239 |
if (next.length) {
|
240 |
_setCurrent(next, $dk);
|
241 |
} else {
|
242 |
_setCurrent(first, $dk);
|
243 |
} |
244 |
} else {
|
245 |
_openDropdown($dk);
|
246 |
} |
247 |
e.preventDefault(); |
248 |
break;
|
249 |
|
250 |
default:
|
251 |
break;
|
252 |
} |
253 |
} |
254 |
|
255 |
// Update the <select> value, and the dropdown label
|
256 |
function _updateFields(option, $dk, reset) { |
257 |
var value, label, data;
|
258 |
|
259 |
value = option.attr('data-dk-dropdown-value');
|
260 |
label = option.text(); |
261 |
data = $dk.data('dropkick'); |
262 |
|
263 |
$select = data.$select; |
264 |
$select.val(value);
|
265 |
|
266 |
$dk.find('.dk_label').text(label); |
267 |
|
268 |
reset = reset || false;
|
269 |
|
270 |
if (data.settings.change && !reset) {
|
271 |
data.settings.change.call($select, value, label);
|
272 |
} |
273 |
} |
274 |
|
275 |
// Set the currently selected option
|
276 |
function _setCurrent($current, $dk) { |
277 |
$dk.find('.dk_option_current').removeClass('dk_option_current'); |
278 |
$current.addClass('dk_option_current'); |
279 |
|
280 |
_setScrollPos($dk, $current); |
281 |
} |
282 |
|
283 |
function _setScrollPos($dk, anchor) { |
284 |
var height = anchor.prevAll('li').outerHeight() * anchor.prevAll('li').length; |
285 |
$dk.find('.dk_options_inner').animate({ scrollTop: height + 'px' }, 0); |
286 |
} |
287 |
|
288 |
// Close a dropdown
|
289 |
function _closeDropdown($dk) { |
290 |
$dk.removeClass('dk_open'); |
291 |
} |
292 |
|
293 |
// Open a dropdown
|
294 |
function _openDropdown($dk) { |
295 |
var data = $dk.data('dropkick'); |
296 |
$dk.find('.dk_options').css({ top : $dk.find('.dk_toggle').outerHeight() - 1 }); |
297 |
$dk.toggleClass('dk_open'); |
298 |
|
299 |
} |
300 |
|
301 |
/**
|
302 |
* Turn the dropdownTemplate into a jQuery object and fill in the variables.
|
303 |
*/
|
304 |
function _build (tpl, view) { |
305 |
var
|
306 |
// Template for the dropdown
|
307 |
template = tpl, |
308 |
// Holder of the dropdowns options
|
309 |
options = [], |
310 |
$dk
|
311 |
; |
312 |
|
313 |
template = template.replace('{{ id }}', view.id);
|
314 |
template = template.replace('{{ label }}', view.label);
|
315 |
template = template.replace('{{ tabindex }}', view.tabindex);
|
316 |
|
317 |
if (view.options && view.options.length) {
|
318 |
for (var i = 0, l = view.options.length; i < l; i++) { |
319 |
var
|
320 |
$option = $(view.options[i]), |
321 |
current = 'dk_option_current',
|
322 |
oTemplate = optionTemplate |
323 |
; |
324 |
|
325 |
oTemplate = oTemplate.replace('{{ value }}', $option.val()); |
326 |
oTemplate = oTemplate.replace('{{ current }}', (_notBlank($option.val()) === view.value) ? current : ''); |
327 |
oTemplate = oTemplate.replace('{{ text }}', $option.text()); |
328 |
|
329 |
options[options.length] = oTemplate; |
330 |
} |
331 |
} |
332 |
|
333 |
$dk = $(template); |
334 |
$dk.find('.dk_options_inner').html(options.join('')); |
335 |
|
336 |
return $dk; |
337 |
} |
338 |
|
339 |
function _notBlank(text) { |
340 |
return ($.trim(text).length > 0) ? text : false; |
341 |
} |
342 |
|
343 |
$(function () { |
344 |
|
345 |
// Handle click events on the dropdown toggler
|
346 |
$('.dk_toggle').live('click', function (e) { |
347 |
var $dk = $(this).parents('.dk_container').first(); |
348 |
|
349 |
_openDropdown($dk);
|
350 |
|
351 |
if ("ontouchstart" in window) { |
352 |
$dk.addClass('dk_touch'); |
353 |
$dk.find('.dk_options_inner').addClass('scrollable vertical'); |
354 |
} |
355 |
|
356 |
e.preventDefault(); |
357 |
return false; |
358 |
}); |
359 |
|
360 |
// Handle click events on individual dropdown options
|
361 |
$('.dk_options a').live(($.browser.msie ? 'mousedown' : 'click'), function (e) { |
362 |
var
|
363 |
$option = $(this), |
364 |
$dk = $option.parents('.dk_container').first(), |
365 |
data = $dk.data('dropkick') |
366 |
; |
367 |
|
368 |
_closeDropdown($dk);
|
369 |
_updateFields($option, $dk); |
370 |
_setCurrent($option.parent(), $dk); |
371 |
|
372 |
e.preventDefault(); |
373 |
return false; |
374 |
}); |
375 |
|
376 |
// Setup keyboard nav
|
377 |
$(document).bind('keydown.dk_nav', function (e) { |
378 |
var
|
379 |
// Look for an open dropdown...
|
380 |
$open = $('.dk_container.dk_open'), |
381 |
|
382 |
// Look for a focused dropdown
|
383 |
$focused = $('.dk_container.dk_focus'), |
384 |
|
385 |
// Will be either $open, $focused, or null
|
386 |
$dk = null |
387 |
; |
388 |
|
389 |
// If we have an open dropdown, key events should get sent to that one
|
390 |
if ($open.length) { |
391 |
$dk = $open; |
392 |
} else if ($focused.length && !$open.length) { |
393 |
// But if we have no open dropdowns, use the focused dropdown instead
|
394 |
$dk = $focused; |
395 |
} |
396 |
|
397 |
if ($dk) { |
398 |
_handleKeyBoardNav(e, $dk);
|
399 |
} |
400 |
}); |
401 |
}); |
402 |
})(jQuery, window, document); |