CLIENT GUI Framework
[vnfsdk/refrepo.git] / portal-common / src / main / webapp / common / thirdparty / icheck / icheck.js
1 /*!\r
2  * iCheck v1.0.2, http://git.io/arlzeA\r
3  * ===================================\r
4  * Powerful jQuery and Zepto plugin for checkboxes and radio buttons customization\r
5  *\r
6  * (c) 2013 Damir Sultanov, http://fronteed.com\r
7  * MIT Licensed\r
8  */\r
9 \r
10 (function($) {\r
11 \r
12   // Cached vars\r
13   var _iCheck = 'iCheck',\r
14     _iCheckHelper = _iCheck + '-helper',\r
15     _checkbox = 'checkbox',\r
16     _radio = 'radio',\r
17     _checked = 'checked',\r
18     _unchecked = 'un' + _checked,\r
19     _disabled = 'disabled',\r
20     _determinate = 'determinate',\r
21     _indeterminate = 'in' + _determinate,\r
22     _update = 'update',\r
23     _type = 'type',\r
24     _click = 'click',\r
25     _touch = 'touchbegin.i touchend.i',\r
26     _add = 'addClass',\r
27     _remove = 'removeClass',\r
28     _callback = 'trigger',\r
29     _label = 'label',\r
30     _cursor = 'cursor',\r
31     _mobile = /ipad|iphone|ipod|android|blackberry|windows phone|opera mini|silk/i.test(navigator.userAgent);\r
32 \r
33   // Plugin init\r
34   $.fn[_iCheck] = function(options, fire) {\r
35 \r
36     // Walker\r
37     var handle = 'input[type="' + _checkbox + '"], input[type="' + _radio + '"]',\r
38       stack = $(),\r
39       walker = function(object) {\r
40         object.each(function() {\r
41           var self = $(this);\r
42 \r
43           if (self.is(handle)) {\r
44             stack = stack.add(self);\r
45           } else {\r
46             stack = stack.add(self.find(handle));\r
47           }\r
48         });\r
49       };\r
50 \r
51     // Check if we should operate with some method\r
52     if (/^(check|uncheck|toggle|indeterminate|determinate|disable|enable|update|destroy)$/i.test(options)) {\r
53 \r
54       // Normalize method's name\r
55       options = options.toLowerCase();\r
56 \r
57       // Find checkboxes and radio buttons\r
58       walker(this);\r
59 \r
60       return stack.each(function() {\r
61         var self = $(this);\r
62 \r
63         if (options == 'destroy') {\r
64           tidy(self, 'ifDestroyed');\r
65         } else {\r
66           operate(self, true, options);\r
67         }\r
68 \r
69         // Fire method's callback\r
70         if ($.isFunction(fire)) {\r
71           fire();\r
72         }\r
73       });\r
74 \r
75     // Customization\r
76     } else if (typeof options == 'object' || !options) {\r
77 \r
78       // Check if any options were passed\r
79       var settings = $.extend({\r
80           checkedClass: _checked,\r
81           disabledClass: _disabled,\r
82           indeterminateClass: _indeterminate,\r
83           labelHover: true\r
84         }, options),\r
85 \r
86         selector = settings.handle,\r
87         hoverClass = settings.hoverClass || 'hover',\r
88         focusClass = settings.focusClass || 'focus',\r
89         activeClass = settings.activeClass || 'active',\r
90         labelHover = !!settings.labelHover,\r
91         labelHoverClass = settings.labelHoverClass || 'hover',\r
92 \r
93         // Setup clickable area\r
94         area = ('' + settings.increaseArea).replace('%', '') | 0;\r
95 \r
96       // Selector limit\r
97       if (selector == _checkbox || selector == _radio) {\r
98         handle = 'input[type="' + selector + '"]';\r
99       }\r
100 \r
101       // Clickable area limit\r
102       if (area < -50) {\r
103         area = -50;\r
104       }\r
105 \r
106       // Walk around the selector\r
107       walker(this);\r
108 \r
109       return stack.each(function() {\r
110         var self = $(this);\r
111 \r
112         // If already customized\r
113         tidy(self);\r
114 \r
115         var node = this,\r
116           id = node.id,\r
117 \r
118           // Layer styles\r
119           offset = -area + '%',\r
120           size = 100 + (area * 2) + '%',\r
121           layer = {\r
122             position: 'absolute',\r
123             top: offset,\r
124             left: offset,\r
125             display: 'block',\r
126             width: size,\r
127             height: size,\r
128             margin: 0,\r
129             padding: 0,\r
130             background: '#fff',\r
131             border: 0,\r
132             opacity: 0\r
133           },\r
134 \r
135           // Choose how to hide input\r
136           hide = _mobile ? {\r
137             position: 'absolute',\r
138             visibility: 'hidden'\r
139           } : area ? layer : {\r
140             position: 'absolute',\r
141             opacity: 0\r
142           },\r
143 \r
144           // Get proper class\r
145           className = node[_type] == _checkbox ? settings.checkboxClass || 'i' + _checkbox : settings.radioClass || 'i' + _radio,\r
146 \r
147           // Find assigned labels\r
148           label = $(_label + '[for="' + id + '"]').add(self.closest(_label)),\r
149 \r
150           // Check ARIA option\r
151           aria = !!settings.aria,\r
152 \r
153           // Set ARIA placeholder\r
154           ariaID = _iCheck + '-' + Math.random().toString(36).substr(2,6),\r
155 \r
156           // Parent & helper\r
157           parent = '<div class="' + className + '" ' + (aria ? 'role="' + node[_type] + '" ' : ''),\r
158           helper;\r
159 \r
160         // Set ARIA "labelledby"\r
161         if (aria) {\r
162           label.each(function() {\r
163             parent += 'aria-labelledby="';\r
164 \r
165             if (this.id) {\r
166               parent += this.id;\r
167             } else {\r
168               this.id = ariaID;\r
169               parent += ariaID;\r
170             }\r
171 \r
172             parent += '"';\r
173           });\r
174         }\r
175 \r
176         // Wrap input\r
177         parent = self.wrap(parent + '/>')[_callback]('ifCreated').parent().append(settings.insert);\r
178 \r
179         // Layer addition\r
180         helper = $('<ins class="' + _iCheckHelper + '"/>').css(layer).appendTo(parent);\r
181 \r
182         // Finalize customization\r
183         self.data(_iCheck, {o: settings, s: self.attr('style')}).css(hide);\r
184         !!settings.inheritClass && parent[_add](node.className || '');\r
185         !!settings.inheritID && id && parent.attr('id', _iCheck + '-' + id);\r
186         parent.css('position') == 'static' && parent.css('position', 'relative');\r
187         operate(self, true, _update);\r
188 \r
189         // Label events\r
190         if (label.length) {\r
191           label.on(_click + '.i mouseover.i mouseout.i ' + _touch, function(event) {\r
192             var type = event[_type],\r
193               item = $(this);\r
194 \r
195             // Do nothing if input is disabled\r
196             if (!node[_disabled]) {\r
197 \r
198               // Click\r
199               if (type == _click) {\r
200                 if ($(event.target).is('a')) {\r
201                   return;\r
202                 }\r
203                 operate(self, false, true);\r
204 \r
205               // Hover state\r
206               } else if (labelHover) {\r
207 \r
208                 // mouseout|touchend\r
209                 if (/ut|nd/.test(type)) {\r
210                   parent[_remove](hoverClass);\r
211                   item[_remove](labelHoverClass);\r
212                 } else {\r
213                   parent[_add](hoverClass);\r
214                   item[_add](labelHoverClass);\r
215                 }\r
216               }\r
217 \r
218               if (_mobile) {\r
219                 event.stopPropagation();\r
220               } else {\r
221                 return false;\r
222               }\r
223             }\r
224           });\r
225         }\r
226 \r
227         // Input events\r
228         self.on(_click + '.i focus.i blur.i keyup.i keydown.i keypress.i', function(event) {\r
229           var type = event[_type],\r
230             key = event.keyCode;\r
231 \r
232           // Click\r
233           if (type == _click) {\r
234             return false;\r
235 \r
236           // Keydown\r
237           } else if (type == 'keydown' && key == 32) {\r
238             if (!(node[_type] == _radio && node[_checked])) {\r
239               if (node[_checked]) {\r
240                 off(self, _checked);\r
241               } else {\r
242                 on(self, _checked);\r
243               }\r
244             }\r
245 \r
246             return false;\r
247 \r
248           // Keyup\r
249           } else if (type == 'keyup' && node[_type] == _radio) {\r
250             !node[_checked] && on(self, _checked);\r
251 \r
252           // Focus/blur\r
253           } else if (/us|ur/.test(type)) {\r
254             parent[type == 'blur' ? _remove : _add](focusClass);\r
255           }\r
256         });\r
257 \r
258         // Helper events\r
259         helper.on(_click + ' mousedown mouseup mouseover mouseout ' + _touch, function(event) {\r
260           var type = event[_type],\r
261 \r
262             // mousedown|mouseup\r
263             toggle = /wn|up/.test(type) ? activeClass : hoverClass;\r
264 \r
265           // Do nothing if input is disabled\r
266           if (!node[_disabled]) {\r
267 \r
268             // Click\r
269             if (type == _click) {\r
270               operate(self, false, true);\r
271 \r
272             // Active and hover states\r
273             } else {\r
274 \r
275               // State is on\r
276               if (/wn|er|in/.test(type)) {\r
277 \r
278                 // mousedown|mouseover|touchbegin\r
279                 parent[_add](toggle);\r
280 \r
281               // State is off\r
282               } else {\r
283                 parent[_remove](toggle + ' ' + activeClass);\r
284               }\r
285 \r
286               // Label hover\r
287               if (label.length && labelHover && toggle == hoverClass) {\r
288 \r
289                 // mouseout|touchend\r
290                 label[/ut|nd/.test(type) ? _remove : _add](labelHoverClass);\r
291               }\r
292             }\r
293 \r
294             if (_mobile) {\r
295               event.stopPropagation();\r
296             } else {\r
297               return false;\r
298             }\r
299           }\r
300         });\r
301       });\r
302     } else {\r
303       return this;\r
304     }\r
305   };\r
306 \r
307   // Do something with inputs\r
308   function operate(input, direct, method) {\r
309     var node = input[0],\r
310       state = /er/.test(method) ? _indeterminate : /bl/.test(method) ? _disabled : _checked,\r
311       active = method == _update ? {\r
312         checked: node[_checked],\r
313         disabled: node[_disabled],\r
314         indeterminate: input.attr(_indeterminate) == 'true' || input.attr(_determinate) == 'false'\r
315       } : node[state];\r
316 \r
317     // Check, disable or indeterminate\r
318     if (/^(ch|di|in)/.test(method) && !active) {\r
319       on(input, state);\r
320 \r
321     // Uncheck, enable or determinate\r
322     } else if (/^(un|en|de)/.test(method) && active) {\r
323       off(input, state);\r
324 \r
325     // Update\r
326     } else if (method == _update) {\r
327 \r
328       // Handle states\r
329       for (var each in active) {\r
330         if (active[each]) {\r
331           on(input, each, true);\r
332         } else {\r
333           off(input, each, true);\r
334         }\r
335       }\r
336 \r
337     } else if (!direct || method == 'toggle') {\r
338 \r
339       // Helper or label was clicked\r
340       if (!direct) {\r
341         input[_callback]('ifClicked');\r
342       }\r
343 \r
344       // Toggle checked state\r
345       if (active) {\r
346         if (node[_type] !== _radio) {\r
347           off(input, state);\r
348         }\r
349       } else {\r
350         on(input, state);\r
351       }\r
352     }\r
353   }\r
354 \r
355   // Add checked, disabled or indeterminate state\r
356   function on(input, state, keep) {\r
357     var node = input[0],\r
358       parent = input.parent(),\r
359       checked = state == _checked,\r
360       indeterminate = state == _indeterminate,\r
361       disabled = state == _disabled,\r
362       callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled',\r
363       regular = option(input, callback + capitalize(node[_type])),\r
364       specific = option(input, state + capitalize(node[_type]));\r
365 \r
366     // Prevent unnecessary actions\r
367     if (node[state] !== true) {\r
368 \r
369       // Toggle assigned radio buttons\r
370       if (!keep && state == _checked && node[_type] == _radio && node.name) {\r
371         var form = input.closest('form'),\r
372           inputs = 'input[name="' + node.name + '"]';\r
373 \r
374         inputs = form.length ? form.find(inputs) : $(inputs);\r
375 \r
376         inputs.each(function() {\r
377           if (this !== node && $(this).data(_iCheck)) {\r
378             off($(this), state);\r
379           }\r
380         });\r
381       }\r
382 \r
383       // Indeterminate state\r
384       if (indeterminate) {\r
385 \r
386         // Add indeterminate state\r
387         node[state] = true;\r
388 \r
389         // Remove checked state\r
390         if (node[_checked]) {\r
391           off(input, _checked, 'force');\r
392         }\r
393 \r
394       // Checked or disabled state\r
395       } else {\r
396 \r
397         // Add checked or disabled state\r
398         if (!keep) {\r
399           node[state] = true;\r
400         }\r
401 \r
402         // Remove indeterminate state\r
403         if (checked && node[_indeterminate]) {\r
404           off(input, _indeterminate, false);\r
405         }\r
406       }\r
407 \r
408       // Trigger callbacks\r
409       callbacks(input, checked, state, keep);\r
410     }\r
411 \r
412     // Add proper cursor\r
413     if (node[_disabled] && !!option(input, _cursor, true)) {\r
414       parent.find('.' + _iCheckHelper).css(_cursor, 'default');\r
415     }\r
416 \r
417     // Add state class\r
418     parent[_add](specific || option(input, state) || '');\r
419 \r
420     // Set ARIA attribute\r
421     if (!!parent.attr('role') && !indeterminate) {\r
422       parent.attr('aria-' + (disabled ? _disabled : _checked), 'true');\r
423     }\r
424 \r
425     // Remove regular state class\r
426     parent[_remove](regular || option(input, callback) || '');\r
427   }\r
428 \r
429   // Remove checked, disabled or indeterminate state\r
430   function off(input, state, keep) {\r
431     var node = input[0],\r
432       parent = input.parent(),\r
433       checked = state == _checked,\r
434       indeterminate = state == _indeterminate,\r
435       disabled = state == _disabled,\r
436       callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled',\r
437       regular = option(input, callback + capitalize(node[_type])),\r
438       specific = option(input, state + capitalize(node[_type]));\r
439 \r
440     // Prevent unnecessary actions\r
441     if (node[state] !== false) {\r
442 \r
443       // Toggle state\r
444       if (indeterminate || !keep || keep == 'force') {\r
445         node[state] = false;\r
446       }\r
447 \r
448       // Trigger callbacks\r
449       callbacks(input, checked, callback, keep);\r
450     }\r
451 \r
452     // Add proper cursor\r
453     if (!node[_disabled] && !!option(input, _cursor, true)) {\r
454       parent.find('.' + _iCheckHelper).css(_cursor, 'pointer');\r
455     }\r
456 \r
457     // Remove state class\r
458     parent[_remove](specific || option(input, state) || '');\r
459 \r
460     // Set ARIA attribute\r
461     if (!!parent.attr('role') && !indeterminate) {\r
462       parent.attr('aria-' + (disabled ? _disabled : _checked), 'false');\r
463     }\r
464 \r
465     // Add regular state class\r
466     parent[_add](regular || option(input, callback) || '');\r
467   }\r
468 \r
469   // Remove all traces\r
470   function tidy(input, callback) {\r
471     if (input.data(_iCheck)) {\r
472 \r
473       // Remove everything except input\r
474       input.parent().html(input.attr('style', input.data(_iCheck).s || ''));\r
475 \r
476       // Callback\r
477       if (callback) {\r
478         input[_callback](callback);\r
479       }\r
480 \r
481       // Unbind events\r
482       input.off('.i').unwrap();\r
483       $(_label + '[for="' + input[0].id + '"]').add(input.closest(_label)).off('.i');\r
484     }\r
485   }\r
486 \r
487   // Get some option\r
488   function option(input, state, regular) {\r
489     if (input.data(_iCheck)) {\r
490       return input.data(_iCheck).o[state + (regular ? '' : 'Class')];\r
491     }\r
492   }\r
493 \r
494   // Capitalize some string\r
495   function capitalize(string) {\r
496     return string.charAt(0).toUpperCase() + string.slice(1);\r
497   }\r
498 \r
499   // Executable handlers\r
500   function callbacks(input, checked, callback, keep) {\r
501     if (!keep) {\r
502       if (checked) {\r
503         input[_callback]('ifToggled');\r
504       }\r
505 \r
506       input[_callback]('ifChanged')[_callback]('if' + capitalize(callback));\r
507     }\r
508   }\r
509 })(window.jQuery || window.Zepto);\r