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 |
* © 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); |