github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/icheck/icheck.js (about)

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