You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
8.4 KiB
387 lines
8.4 KiB
/** |
|
* Switchery 0.8.2 |
|
* http://abpetkov.github.io/switchery/ |
|
* |
|
* Authored by Alexander Petkov |
|
* https://github.com/abpetkov |
|
* |
|
* Copyright 2013-2015, Alexander Petkov |
|
* License: The MIT License (MIT) |
|
* http://opensource.org/licenses/MIT |
|
* |
|
*/ |
|
|
|
/** |
|
* External dependencies. |
|
*/ |
|
|
|
var transitionize = require('transitionize') |
|
, fastclick = require('fastclick') |
|
, classes = require('classes') |
|
, events = require('events'); |
|
|
|
/** |
|
* Expose `Switchery`. |
|
*/ |
|
|
|
module.exports = Switchery; |
|
|
|
/** |
|
* Set Switchery default values. |
|
* |
|
* @api public |
|
*/ |
|
|
|
var defaults = { |
|
color : '#64bd63' |
|
, secondaryColor : '#dfdfdf' |
|
, jackColor : '#fff' |
|
, jackSecondaryColor: null |
|
, className : 'switchery' |
|
, disabled : false |
|
, disabledOpacity : 0.5 |
|
, speed : '0.4s' |
|
, size : 'default' |
|
}; |
|
|
|
/** |
|
* Create Switchery object. |
|
* |
|
* @param {Object} element |
|
* @param {Object} options |
|
* @api public |
|
*/ |
|
|
|
function Switchery(element, options) { |
|
if (!(this instanceof Switchery)) return new Switchery(element, options); |
|
|
|
this.element = element; |
|
this.options = options || {}; |
|
|
|
for (var i in defaults) { |
|
if (this.options[i] == null) { |
|
this.options[i] = defaults[i]; |
|
} |
|
} |
|
|
|
if (this.element != null && this.element.type == 'checkbox') this.init(); |
|
if (this.isDisabled() === true) this.disable(); |
|
} |
|
|
|
/** |
|
* Hide the target element. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.hide = function() { |
|
this.element.style.display = 'none'; |
|
}; |
|
|
|
/** |
|
* Show custom switch after the target element. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.show = function() { |
|
var switcher = this.create(); |
|
this.insertAfter(this.element, switcher); |
|
}; |
|
|
|
/** |
|
* Create custom switch. |
|
* |
|
* @returns {Object} this.switcher |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.create = function() { |
|
this.switcher = document.createElement('span'); |
|
this.jack = document.createElement('small'); |
|
this.switcher.appendChild(this.jack); |
|
this.switcher.className = this.options.className; |
|
this.events = events(this.switcher, this); |
|
|
|
return this.switcher; |
|
}; |
|
|
|
/** |
|
* Insert after element after another element. |
|
* |
|
* @param {Object} reference |
|
* @param {Object} target |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.insertAfter = function(reference, target) { |
|
reference.parentNode.insertBefore(target, reference.nextSibling); |
|
}; |
|
|
|
/** |
|
* Set switch jack proper position. |
|
* |
|
* @param {Boolean} clicked - we need this in order to uncheck the input when the switch is clicked |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.setPosition = function (clicked) { |
|
var checked = this.isChecked() |
|
, switcher = this.switcher |
|
, jack = this.jack; |
|
|
|
if (clicked && checked) checked = false; |
|
else if (clicked && !checked) checked = true; |
|
|
|
if (checked === true) { |
|
this.element.checked = true; |
|
|
|
if (window.getComputedStyle) jack.style.left = parseInt(window.getComputedStyle(switcher).width) - parseInt(window.getComputedStyle(jack).width) + 'px'; |
|
else jack.style.left = parseInt(switcher.currentStyle['width']) - parseInt(jack.currentStyle['width']) + 'px'; |
|
|
|
if (this.options.color) this.colorize(); |
|
this.setSpeed(); |
|
} else { |
|
jack.style.left = 0; |
|
this.element.checked = false; |
|
this.switcher.style.boxShadow = 'inset 0 0 0 0 ' + this.options.secondaryColor; |
|
this.switcher.style.borderColor = this.options.secondaryColor; |
|
this.switcher.style.backgroundColor = (this.options.secondaryColor !== defaults.secondaryColor) ? this.options.secondaryColor : '#fff'; |
|
this.jack.style.backgroundColor = (this.options.jackSecondaryColor !== this.options.jackColor) ? this.options.jackSecondaryColor : this.options.jackColor; |
|
this.setSpeed(); |
|
} |
|
}; |
|
|
|
/** |
|
* Set speed. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.setSpeed = function() { |
|
var switcherProp = {} |
|
, jackProp = { |
|
'background-color': this.options.speed |
|
, 'left': this.options.speed.replace(/[a-z]/, '') / 2 + 's' |
|
}; |
|
|
|
if (this.isChecked()) { |
|
switcherProp = { |
|
'border': this.options.speed |
|
, 'box-shadow': this.options.speed |
|
, 'background-color': this.options.speed.replace(/[a-z]/, '') * 3 + 's' |
|
}; |
|
} else { |
|
switcherProp = { |
|
'border': this.options.speed |
|
, 'box-shadow': this.options.speed |
|
}; |
|
} |
|
|
|
transitionize(this.switcher, switcherProp); |
|
transitionize(this.jack, jackProp); |
|
}; |
|
|
|
/** |
|
* Set switch size. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.setSize = function() { |
|
var small = 'switchery-small' |
|
, normal = 'switchery-default' |
|
, large = 'switchery-large'; |
|
|
|
switch (this.options.size) { |
|
case 'small': |
|
classes(this.switcher).add(small) |
|
break; |
|
case 'large': |
|
classes(this.switcher).add(large) |
|
break; |
|
default: |
|
classes(this.switcher).add(normal) |
|
break; |
|
} |
|
}; |
|
|
|
/** |
|
* Set switch color. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.colorize = function() { |
|
var switcherHeight = this.switcher.offsetHeight / 2; |
|
|
|
this.switcher.style.backgroundColor = this.options.color; |
|
this.switcher.style.borderColor = this.options.color; |
|
this.switcher.style.boxShadow = 'inset 0 0 0 ' + switcherHeight + 'px ' + this.options.color; |
|
this.jack.style.backgroundColor = this.options.jackColor; |
|
}; |
|
|
|
/** |
|
* Handle the onchange event. |
|
* |
|
* @param {Boolean} state |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.handleOnchange = function(state) { |
|
if (document.dispatchEvent) { |
|
var event = document.createEvent('HTMLEvents'); |
|
event.initEvent('change', true, true); |
|
this.element.dispatchEvent(event); |
|
} else { |
|
this.element.fireEvent('onchange'); |
|
} |
|
}; |
|
|
|
/** |
|
* Handle the native input element state change. |
|
* A `change` event must be fired in order to detect the change. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.handleChange = function() { |
|
var self = this |
|
, el = this.element; |
|
|
|
if (el.addEventListener) { |
|
el.addEventListener('change', function() { |
|
self.setPosition(); |
|
}); |
|
} else { |
|
el.attachEvent('onchange', function() { |
|
self.setPosition(); |
|
}); |
|
} |
|
}; |
|
|
|
/** |
|
* Handle the switch click event. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.handleClick = function() { |
|
var switcher = this.switcher; |
|
|
|
fastclick = fastclick.bind(this); |
|
fastclick(switcher); |
|
this.events.bind('click', 'bindClick'); |
|
}; |
|
|
|
/** |
|
* Attach all methods that need to happen on switcher click. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.bindClick = function() { |
|
var parent = this.element.parentNode.tagName.toLowerCase() |
|
, labelParent = (parent === 'label') ? false : true; |
|
|
|
this.setPosition(labelParent); |
|
this.handleOnchange(this.element.checked); |
|
}; |
|
|
|
/** |
|
* Mark an individual switch as already handled. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.markAsSwitched = function() { |
|
this.element.setAttribute('data-switchery', true); |
|
}; |
|
|
|
/** |
|
* Check if an individual switch is already handled. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.markedAsSwitched = function() { |
|
return this.element.getAttribute('data-switchery'); |
|
}; |
|
|
|
/** |
|
* Initialize Switchery. |
|
* |
|
* @api private |
|
*/ |
|
|
|
Switchery.prototype.init = function() { |
|
this.hide(); |
|
this.show(); |
|
this.setSize(); |
|
this.setPosition(); |
|
this.markAsSwitched(); |
|
this.handleChange(); |
|
this.handleClick(); |
|
}; |
|
|
|
/** |
|
* See if input is checked. |
|
* |
|
* @returns {Boolean} |
|
* @api public |
|
*/ |
|
|
|
Switchery.prototype.isChecked = function() { |
|
return this.element.checked; |
|
}; |
|
|
|
/** |
|
* See if switcher should be disabled. |
|
* |
|
* @returns {Boolean} |
|
* @api public |
|
*/ |
|
|
|
Switchery.prototype.isDisabled = function() { |
|
return this.options.disabled || this.element.disabled || this.element.readOnly; |
|
}; |
|
|
|
/** |
|
* Destroy all event handlers attached to the switch. |
|
* |
|
* @api public |
|
*/ |
|
|
|
Switchery.prototype.destroy = function() { |
|
this.events.unbind(); |
|
}; |
|
|
|
/** |
|
* Enable disabled switch element. |
|
* |
|
* @api public |
|
*/ |
|
|
|
Switchery.prototype.enable = function() { |
|
if (!this.options.disabled) return; |
|
if (this.options.disabled) this.options.disabled = false; |
|
if (this.element.disabled) this.element.disabled = false; |
|
if (this.element.readOnly) this.element.readOnly = false; |
|
this.switcher.style.opacity = 1; |
|
this.events.bind('click', 'bindClick'); |
|
}; |
|
|
|
/** |
|
* Disable switch element. |
|
* |
|
* @api public |
|
*/ |
|
|
|
Switchery.prototype.disable = function() { |
|
if (this.options.disabled) return; |
|
if (!this.options.disabled) this.options.disabled = true; |
|
if (!this.element.disabled) this.element.disabled = true; |
|
if (!this.element.readOnly) this.element.readOnly = true; |
|
this.switcher.style.opacity = this.options.disabledOpacity; |
|
this.destroy(); |
|
};
|
|
|