123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708 |
- /**
- * JQuery rcSwitcher plugin
- *
- * rcSwitcher plugin referes to 'Radio Checkbox Switcher'
- * it let you transform radio and checkbox inputs into a nice switch button
- * without requirement of a specific html syntax, it simply takes your existed basic input
- * and do the magic with many customizations and supports 4 themes
- *
- *
- * @package rcSwitcher
- * @name rcSwitcher
- * @version 4.1 < 18 Feb 2017 >
- * @changes 4.1 - Add feature that input shold only have on switcher
- * - Add rcSwitcher Object on input as property
- * - Add attribute 'data-has-rcswitcher="1"' on input to mark that input has rcswitcher
- * - Enhance Auto Stick
- * @author ahmed saad <a7mad.sa3d.2014@gmail.com><ahmedfadlshaker@gmail.com>
- * @copyright ahmed saad april 2015
- * @link http://plus.google.com/+AhmedSaadGmail
- * @license http://choosealicense.com/licenses/gpl-3.0/ GNU GPL V3.0
- *
- */
- (function($){
- /**
- * Defining Static variables
- */
- var templates = {
-
- $switcher : $( '<span>', {'class': 'swraper'} ).hide(),
- $toggler: $( '<span>', {'class': 'stoggler' } ),
- $on: $( '<span>', {'class': 'slabel-on'} ),
- $off: $( '<span>', {'class': 'slabel-off'} ),
- $blob: $( '<span>', {'class': 'sblob'} ),
- // Allowed Themes
- themes: [ 'light', 'modern', 'dark', 'flat', 'yellowish-green' ],
- };
-
- /**
- * All Switcher methods goes here
- *
- * here all logic of switcher plugin
- */
- var switcherM = {
- /**
- * Prepare Switches
- *
- * @param {Object} switcherP switcher plugin properties
- * @param {Object} options switcher plugin options object
- * @return void
- */
- start: function( switcherP, options )
- {
- // Set Templates and one runtime calculations
- this.setTemplateStyle( options, switcherP );
-
- // prepare and create switches
- switcherP.$this.each( function( i, input )
- {
- // console.log( $input.type );
- if( input.hasOwnProperty( 'rcSwitcher' ) )
- {
- console.warn( 'already has instance' );
- return;
- }
- this.makeSwitcher( $( input ), switcherP, options );
- }.bind( this ) );
- // ADD EVENT BEHAVIOUR
- this.behaviour( switcherP );
- },
- /**
- * Make a switch
- *
- * @param {jQ Obj} $input input object to make switch for
- * @param {Object} switcherP switcher plugin propertirs
- * @param {Object} options switcher plugin options
- * @return void
- */
- makeSwitcher: function( $input, switcherP, options )
- {
- // console.log( $input.attr('name') )
- var inputName = $input.attr( 'name' ).replace( /(\[\])+$/, '' ), // remove input name array signs
- inputValue = $input.attr('value') || '',
- type = $input.attr('type'),
- cat = ( type == 'checkbox' ) ? switcherP.checkboxs : switcherP.radios ,
- data = { components: {}, '$input': $input };
- data.$switcher = templates.$switcher.clone().attr( { 'input-name': inputName, 'input-value': inputValue, 'input-type': type } );
- if( switcherP.cssValues.dir == 'rtl' ) data.$switcher.addClass( 'rtl' );
-
- data.components.$toggler = templates.$toggler.clone();
-
- data.components.$on = templates.$on.clone().html( $input.attr('data-ontext') || options.onText );
- data.components.$off = templates.$off.clone().html( $input.attr('data-offtext') || options.offText );
- data.components.$blob = templates.$blob.clone();
-
- // Build switch according to direction order
- if( options.reverse )
- data.components.$toggler.append( data.components.$off, data.components.$blob, data.components.$on )
- .appendTo( data.$switcher );
-
- else
- data.components.$toggler.append( data.components.$on, data.components.$blob, data.components.$off )
- .appendTo( data.$switcher );
-
-
- // Insert to DOM
- $input.before( data.$switcher );
- // Set On Off Style
- if( $input[ 0 ].checked )
- {
- data.switcherChecked = true;
- //|-> outside change
- //| //|-> style only
- //| //|
- this.turnOn( data, switcherP, false, true );
- }
- else
- {
- data.switcherChecked = false;
- this.turnOff( data, switcherP, false, true );
- }
- // Set Disabled Style
- inputDisabled = $input[ 0 ].disabled;
-
- if( inputDisabled )
- {
- data.switcherDisabled = true;
- data.$switcher.addClass( 'disabled' ).attr( 'title', 'switch is disabled!' );
- }
- else
- {
- data.switcherDisabled = false;
- }
-
- // Use family to be aliase for current radio name family
- // all radios with the same name has the same family
-
- // Check if family already exists
- if( family = cat.group[ inputName ] )
- {
- family.group[ inputValue ] = data;
- // update length.
- // represents how many input for the same radio name
- family.length++;
- }
- else
- {
- // create new family with radio name
- cat.group[ inputName ] = family = { group: {}, length: 1 }//, enabled: 0, disabled: 0, switchable: false };
-
- family.group[ inputValue ] = data;
- // Update groupLength property
- cat.groupLength++;
- // add radio specific properties
- if( type == 'radio' )
- {
- family.enabled = 0;
- family.disabled = 0;
- family.switchable = false;
- }
- }
-
- // Specifiuc radio properties
- if( type == 'radio' )
- {
- // Status
- if( inputDisabled )
- family.disabled++;
- else
- family.enabled++;
- // set current checked radio input
- if( $input[ 0 ].checked )
- family.checkedKey = inputValue;
- // Set switchable property
- family.switchable = ( family.enabled >= 2 ) ? true : false;
- }
-
- // Add to switchers collections
- switcherP.$switchers = switcherP.$switchers.add( data.$switcher );
- // Store In Element Input JS
- $input[0].rcSwitcher = data;
- // Add attribute to mark this input that it has rcswitcher
- $input.attr( 'data-has-rcswitcher', 1 );
- // Update input type length
- cat.length++;
- // show
- data.$switcher.show();
-
- // attach Outside Change Event
- $input.on( 'change', function(e)
- {
- this.trackChanges({
- type: type,
- name: inputName,
- value: inputValue,
- }, switcherP );
- }.bind(this));
- },
- /**
- * set plugin templates according to current set options
- *
- * @param {Object} options switcher plugin options object
- * @param {Object} switcherP switcher plugin properties
- * @return void
- */
- setTemplateStyle: function( options, switcherP ){
- // Switcher
- templates.$switcher.css( { 'width': [ options.width, 'px' ].join(''), 'line-height': [ options.height, 'px' ].join('') } )
- .removeClass( templates.themes.join(' ') ).addClass( options.theme );
-
- switcherP.cssValues.switcherWidth = options.width;
- switcherP.cssValues.switcherHeight = options.height;
-
- // Blob
- switcherP.cssValues.blobOffset = options.blobOffset;
- switcherP.cssValues.blobWidth = switcherP.cssValues.blobHeight = switcherP.cssValues.switcherHeight - options.blobOffset * 2;
- templates.$blob.css( { 'width': switcherP.cssValues.blobWidth, 'height': switcherP.cssValues.blobHeight } );
- // Set Transform Property EX, translateX( 10px )
- if( options.reverse )
- {
- switcherP.transformOff = ['translateX(', switcherP.transformDir , switcherP.cssValues.blobWidth / 2 + switcherP.cssValues.blobOffset, 'px)' ].join('');
-
- switcherP.transformOn = ['translateX(', switcherP.transformDir , switcherP.cssValues.switcherWidth - switcherP.cssValues.blobWidth / 2 - switcherP.cssValues.blobOffset, 'px)' ].join('');
- }
- else
- {
- switcherP.transformOn = ['translateX(', switcherP.transformDir , switcherP.cssValues.blobWidth / 2 + switcherP.cssValues.blobOffset, 'px)' ].join('');
-
- switcherP.transformOff = ['translateX(', switcherP.transformDir , switcherP.cssValues.switcherWidth - switcherP.cssValues.blobWidth / 2 - switcherP.cssValues.blobOffset, 'px)' ].join('');
- }
- switcherP.transformOn = {
- '-webkit-transform': switcherP.transformOn,
- '-moz-transform': switcherP.transformOn,
- '-o-transform': switcherP.transformOn,
- '-ms-transform': switcherP.transformOn,
- 'transform': switcherP.transformOn
- }
- switcherP.transformOff = {
- '-webkit-transform': switcherP.transformOff,
- '-moz-transform': switcherP.transformOff,
- '-o-transform': switcherP.transformOff,
- '-ms-transform': switcherP.transformOff,
- 'transform': switcherP.transformOff
- }
- // console.log( switcherP.transformOn )
-
- // Remove any applied font-size from previous initializaing
- templates.$toggler.css( 'font-size', '' );
- // Automatic fit font size in low heights or on autoFontSize
- if( options.height < 20 || options.autoFontSize ) templates.$toggler.css( { 'font-size': [ options.height / 2, 'px' ].join('') } );
- // console.log( 'calculated once' )
-
-
- // Auto Stick
- templates.$switcher.css( 'margin', '' );
- if( options.autoStick )
- {
- var $fInput = switcherP.$this.first(),
- $label = $fInput.prev('label'),
- parentAW;
-
- if( $label )
- {
- parentAW = $fInput.parent().width();
- // subtract input width if visible
- parentAW -= ( options.inputs ) ? $fInput.outerWidth( true ) : 0;
- // subtract label width
- parentAW -= $label.outerWidth( true );
- // subtract switch width
- var margin = parentAW - options.width;
- // remove border width if exists
- switch( options.theme )
- {
- case 'dark':
- margin -= 2;
- break;
- case 'yellowish-green':
- margin -= 4;
- break;
- }
-
- // Left OR Right margin
- if( switcherP.cssValues.dir == 'rtl' )
-
- templates.$switcher.css( 'margin-right', margin );
- else
- templates.$switcher.css( 'margin-left', margin );
- }
- }
- },
- /**
- * Toggle switch status
- *
- * @param {Object} info switcher information object
- * @param {Object} switcherP switcher plugin properties
- * @param {Boolean} outsideChange if toggle according to outside check change or not
- * @return void
- */
- toggle: function( info, switcherP, outsideChange ){
- // Aliases
- var family, data;
- if( info.type == 'checkbox' )
- {
- // Checkbox
- family = switcherP.checkboxs.group[ info.name ];
- data = family.group[ info.value ];
- if( !data.$input[ 0 ].disabled )
- {
- // console.log( 'clicked checkbox' )
- if( outsideChange )
- status = data.$input[ 0 ].checked ? 'turnOn' : 'turnOff';
- else
- status = data.$input[ 0 ].checked ? 'turnOff' : 'turnOn';
- this[ status ]( data, switcherP, outsideChange );
- }
- }
- else
- {
- // Radio
- family = switcherP.radios.group[ info.name ];
- // console.log( family );
- data = family.group[ info.value ] ;
- if( outsideChange && data.$input[0].checked == data.switcherChecked )
- return;
- // console.log( data );
- // if Outside request is to turnoff ( uncheck ), then don't do any thing and recheck radio
- if( outsideChange && !data.$input[ 0 ].checked )
- {
- // canot disable
- console.log( 'can not disable radio button, try to activate another sibiling one to deactivate current.' );
- data.$input.prop( 'checked', true );
- return;
- }
- if( !data.$input[ 0 ].disabled && family.switchable )
- {
- // change only if it is not currently selected
- if( family.checkedKey != info.name )
- {
- // turnon
- this.turnOff( family.group[ family.checkedKey ], switcherP, outsideChange );
- this.turnOn( data, switcherP, outsideChange );
- family.checkedKey = info.value;
- }
- }
- }
- },
- /**
- * Track Input Changes
- *
- * This Method Will Check And Apply Any Changes Happens To Original Input
- * Those Changes Are Checked And Disabled Status
- *
- * This Method Also Handles Disabled Changes Mechanism
- *
- * Fires : enable.rcSwitcher AND disable.rcSwitcher according To Change Status
- *
- * @param {Object Literal} info Input Name, Value, Type
- * @param {Switcher Properties Object} switcherP All Switchers Properties Object
- * @return {undefined} Doesnot Return Any Thing
- */
- trackChanges: function( info, switcherP )
- {
- // On Input Change Event
- var family, data;
-
- if( info.type == 'checkbox' )
- family = switcherP.checkboxs.group[ info.name ];
- else
- family = switcherP.radios.group[ info.name ];
- data = family.group[ info.value ];
- // Track Checked Status Changes
- if( data.$input[0].checked != data.switcherChecked )
- {
- if( data.switcherDisabled )
- {
- // Revert Changes
- data.$input.prop( 'checked', data.switcherChecked );
-
- if( info.type == 'radio' )
- family.group[ family.checkedKey ].$input.prop( 'checked', true );
- }
- else
- this.toggle( info, switcherP, true );
- }
- // Track Disabled Status Changes
- if( data.$input[0].disabled != data.switcherDisabled )
- {
- if( data.$input[0].disabled )
- {
- if( !data.$switcher.hasClass( 'disabled' ) )
- data.$switcher.addClass( 'disabled' );
- if( info.type == 'radio' )
- {
- family.disabled++;
- family.enabled--;
- // If Checked, Disable All Group
- if( data.$input[0].checked == true )
- family.switchable = false;
- // console.log( family );
- }
- data.switcherDisabled = true;
- // Fire Event and pass data object to event handler
- data.$input.trigger( 'disable.rcSwitcher', data );
- }
- else
- {
- data.$switcher.removeClass( 'disabled' );
-
- data.$input.trigger( 'enable.rcSwitcher', data );
- if( info.type == 'radio' )
- {
- --family.disabled;
- ++family.enabled;
- if( family.enabled - family.disabled >= 2 )
- family.switchable = true;
- // console.log( family );
- }
- data.switcherDisabled = false;
- }
- }
- },
-
- /**
- * Turn Off switch
- *
- * it also fire 'switcher.turnoff' custom event
- *
- * @param {Object} data data object represents switch entry in switcher properties
- * @param {Object} switcherP switcher plugin properties
- * @param {Boolean} styleOnly turnoff style only
- * @return void
- */
- turnOff: function( data, switcherP, outsideChange, styleOnly ){
- // console.log( 'calculated on eventOFF' )
- data.components.$toggler.css( switcherP.transformOff ).removeClass( 'on' ).addClass('off');
- data.switcherChecked = false;
- if( styleOnly ) return;
-
- // Set Input To Off
- if( !outsideChange )
- data.$input.prop( 'checked', false );
- // Fire Event and pass data object to event handler
- // Wait Transition 500ms Time
- setTimeout( function(){
- data.$input.trigger( 'turnoff.rcSwitcher', data );
- data.$input.trigger( 'toggle.rcSwitcher', [ data, 'turnoff' ] );
- }, 500 );
- },
- /**
- * Turn On switch
- *
- * it also fire 'switcher.turnon' custom event
- *
- * @param {Object} data data object represents switch entry in switcher properties
- * @param {Object} switcherP switcher plugin properties
- * @param {Boolean} styleOnly turnon style only
- * @return void
- */
- turnOn: function( data, switcherP, outsideChange, styleOnly ){
- // console.log( 'calculated on eventOn' )
-
- data.components.$toggler.css( switcherP.transformOn ).addClass( 'on' ).removeClass('off');
-
- data.switcherChecked = true;
- if( styleOnly ) return;
-
- // Set To ON and trigger original change event
- // auto set checked property doesnot fire toggle event, so we need to trigger event manually
- if( !outsideChange )
- data.$input.prop( 'checked', true );
- // Wait Transition 500ms Time
- setTimeout( function(){
- data.$input.trigger( 'turnon.rcSwitcher', data );
- data.$input.trigger( 'toggle.rcSwitcher', [ data, 'turnon' ] );
- }, 500 );
- },
- /**
- * Set Switcher Plugin Events
- *
- * @param {Object} switcherP plugin properties
- * @return void
- */
- behaviour: function( switcherP ){
- // behaviour: function( switcherP, $switcher ){
- // Disable click for input
- switcherP.$this.on( 'click', function( e )
- {
- e.preventDefault();
- e.stopPropagation();
- }.bind( this ) );
- // On Click on switchers
- switcherP.$switchers.on( 'click', function( e )
- {
- var obj = {};
- obj.type = e.currentTarget.getAttribute( 'input-type' );
- obj.name = e.currentTarget.getAttribute( 'input-name' );
- obj.value = e.currentTarget.getAttribute( 'input-value' );
- // Toggle
- this.toggle( obj, switcherP );
- e.preventDefault();
- e.stopPropagation();
- }.bind( this ) );
- },
- };
-
-
-
-
- /**
- * SWITCHER PLUGIN
- * @param {Object} options switcher options
- * @return {jQ Obj} this
- */
- $.fn.rcSwitcher = function( options ){
- // Defining Properties
- var switcherP = {
- checkboxs: {
- group:{},
- groupLength: 0,
- length: 0,
- },
- radios: {
- group:{},
- groupLength: 0,
- length: 0,
- },
- // $this: this,
- $switchers: $([]),
- cssValues:{},
- };
- // Filter this
- // Get Only Checkbox and Radio inputs only
- switcherP.$this = this.filter( 'input[type=checkbox], input[type=radio]' ).not( '[data-has-rcswitcher]' );
- // Stop if we havenot any checkboxs or radios
- if( switcherP.$this.length == 0 )
- return this;
- switcherP.cssValues.dir = window.getComputedStyle( switcherP.$this[0], null ).direction || 'ltr';
- // Detect Transform direction
- switcherP.transformDir = ( switcherP.cssValues.dir == 'rtl' ) ? '' : '-';
-
- // Set Options
- options = $.extend(
- {
- onText: 'ON',
- offText: 'OFF',
- reverse: false,
- inputs: false,
- width: 56,
- height: 20,
- blobOffset: 1,
- autoFontSize: false,
- theme: 'light',
- autoStick: false,
- },
- options || {} );
- // Hide Them ( selected inputs ) All
- if( !options.inputs ) switcherP.$this.css( 'display', 'none' );
- // Make Sure that Theme is Supported
- if( templates.themes.indexOf( options.theme ) == -1 ) options.theme = 'light';
-
-
- // Start
- switcherM.start( switcherP, options );
- // Return selected jquery object to allow chaining
- return this;
- };
- })(jQuery);
- // الحمد لله
|