/** @license jQuery Toggles v3.1.5 Copyright 2012 - 2015 Simon Tabor - MIT License https://github.com/simontabor/jquery-toggles / http://simontabor.com/labs/toggles */ (function(root) { var factory = function($) { var Toggles = root['Toggles'] = function(el, opts) { var self = this; if (typeof opts === 'boolean' && el.data('toggles')) { el.data('toggles').toggle(opts); return; } var dataAttr = [ 'on', 'drag', 'click', 'width', 'height', 'animate', 'easing', 'type', 'checkbox' ]; var dataOpts = {}; for (var i = 0; i < dataAttr.length; i++) { var opt = el.data('toggle-' + dataAttr[i]); if (typeof opt !== 'undefined') dataOpts[dataAttr[i]] = opt; } // extend default opts with the users options opts = self.opts = $.extend({ // can the toggle be dragged 'drag': true, // can it be clicked to toggle 'click': true, 'text': { // text for the ON/OFF position 'on': 'ON', 'off': 'OFF' }, // is the toggle ON on init 'on': false, // animation time (ms) 'animate': 250, // animation transition, 'easing': 'swing', // the checkbox to toggle (for use in forms) 'checkbox': null, // element that can be clicked on to toggle. removes binding from the toggle itself (use nesting) 'clicker': null, // width used if not set in css 'width': 50, // height if not set in css 'height': 20, // defaults to a compact toggle, other option is 'select' where both options are shown at once 'type': 'compact', // the event name to fire when we toggle 'event': 'toggle' }, opts || {}, dataOpts); self.el = el; el.data('toggles', self); self.selectType = opts['type'] === 'select'; // make checkbox a jquery element self.checkbox = $(opts['checkbox']); // leave as undefined if not set if (opts['clicker']) self.clicker = $(opts['clicker']); self.createEl(); self.bindEvents(); // set active to the opposite of what we want, so toggle will run properly self['active'] = !opts['on']; // toggle the toggle to the correct state with no animation and no event self.toggle(opts['on'], true, true); }; Toggles.prototype.createEl = function() { var self = this; var height = self.el.height(); var width = self.el.width(); // if the element doesnt have an explicit height/width in css, set them if (!height) self.el.height(height = self.opts['height']); if (!width) self.el.width(width = self.opts['width']); self.h = height; self.w = width; var div = function(name) { return $('
'); }; self.els = { // wrapper inside toggle slide: div('slide'), // inside slide, this bit moves inner: div('inner'), // the on/off divs on: div('on'), off: div('off'), // the grip to drag the toggle blob: div('blob') }; var halfHeight = height / 2; var onOffWidth = width - halfHeight; var isSelect = self.selectType; // set up the CSS for the individual elements self.els.on .css({ height: height, width: onOffWidth, textIndent: isSelect ? '' : -halfHeight, lineHeight: height + 'px' }) .html(self.opts['text']['on']); self.els.off .css({ height: height, width: onOffWidth, marginLeft: isSelect ? '' : -halfHeight, textIndent: isSelect ? '' : halfHeight, lineHeight: height + 'px' }) .html(self.opts['text']['off']); self.els.blob.css({ height: height, width: height, marginLeft: -halfHeight }); self.els.inner.css({ width: width * 2 - height, marginLeft: (isSelect || self['active']) ? 0 : -width + height }); if (self.selectType) { self.els.slide.addClass('toggle-select'); self.el.css('width', onOffWidth * 2); self.els.blob.hide(); } // construct the toggle self.els.inner.append(self.els.on, self.els.blob, self.els.off); self.els.slide.html(self.els.inner); self.el.html(self.els.slide); }; Toggles.prototype.bindEvents = function() { var self = this; // evt handler for click events var clickHandler = function(e) { // if the target isn't the blob or dragging is disabled, toggle! if (e['target'] !== self.els.blob[0] || !self.opts['drag']) { self.toggle(); } }; // if click is enabled and toggle isn't within the clicker element (stops double binding) if (self.opts['click'] && (!self.opts['clicker'] || !self.opts['clicker'].has(self.el).length)) { self.el.on('click', clickHandler); } // setup the clicker element if (self.opts['clicker']) { self.opts['clicker'].on('click', clickHandler); } // bind up dragging stuff if (self.opts['drag'] && !self.selectType) self.bindDrag(); }; Toggles.prototype.bindDrag = function() { var self = this; // time to begin the dragging parts/blob clicks var diff; var slideLimit = (self.w - self.h) / 4; // fired on mouseup and mouseleave events var upLeave = function(e) { self.el.off('mousemove'); self.els.slide.off('mouseleave'); self.els.blob.off('mouseup'); if (!diff && self.opts['click'] && e.type !== 'mouseleave') { self.toggle(); return; } var overBound = self['active'] ? diff < -slideLimit : diff > slideLimit; if (overBound) { // dragged far enough, toggle self.toggle(); } else { // reset to previous state self.els.inner.stop().animate({ marginLeft: self['active'] ? 0 : -self.w + self.h }, self.opts['animate'] / 2); } }; var wh = -self.w + self.h; self.els.blob.on('mousedown', function(e) { // reset diff diff = 0; self.els.blob.off('mouseup'); self.els.slide.off('mouseleave'); var cursor = e.pageX; self.el.on('mousemove', self.els.blob, function(e) { diff = e.pageX - cursor; var marginLeft; if (self['active']) { marginLeft = diff; // keep it within the limits if (diff > 0) marginLeft = 0; if (diff < wh) marginLeft = wh; } else { marginLeft = diff + wh; if (diff < 0) marginLeft = wh; if (diff > -wh) marginLeft = 0; } self.els.inner.css('margin-left',marginLeft); }); self.els.blob.on('mouseup', upLeave); self.els.slide.on('mouseleave', upLeave); }); }; Toggles.prototype.toggle = function(state, noAnimate, noEvent) { var self = this; // check we arent already in the desired state if (self['active'] === state) return; var active = self['active'] = !self['active']; self.el.data('toggle-active', active); self.els.off.toggleClass('active', !active); self.els.on.toggleClass('active', active); self.checkbox.prop('checked', active); if (!noEvent) self.el.trigger(self.opts['event'], active); if (self.selectType) return; var margin = active ? 0 : -self.w + self.h; // move the toggle! self.els.inner.stop().animate({ 'marginLeft': margin }, noAnimate ? 0 : self.opts['animate']); }; $.fn['toggles'] = function(opts) { return this.each(function() { new Toggles($(this), opts); }); }; }; if (typeof define === 'function' && define['amd']) { define(['jquery'], factory); } else { factory(root['jQuery'] || root['Zepto'] || root['ender'] || root['$'] || $); } })(this);