jQuery(document).ready(function(){ var repeaterObj = { init : function(){ this.hideShowContent(); this.sortRepeatableSections(); this.deleteRepeaterSection(); this.addNewRepeater(); this.saveValueOnChangeEvent(); this.initializeSelect2( '.kar_select:not(.kar_hide)' ); this.initializeFontawesomeSelect2( '.kar_fontawesome:not(.kar_hide)' ); this.initializeColorPicker( '.kar_color:not(.kar_hide)' ); this.showImageUploadModal(); this.removeImage(); this.repeaterActiveCallback(); this.initializeDatePicker( ".kar_date.datepicker:not(.kar_hide)" ); this.initializeTimepicker( '.kar_time_hr:not(.kar_hide),.kar_time_min:not(.kar_hide)' ); }, initializeTimepicker : function( selector ){ jQuery( selector ).select2(); }, initializeDatePicker : function( selector ){ var $this = this; jQuery( selector ).datepicker({ dateFormat : "yy-mm-dd", onSelect: function(dateText, inst) { jQuery(this).attr( 'data-value', dateText ); $this.sortValues( jQuery(this).closest('.kar_wrapper') ); // Save the values var id = '#' + jQuery(this).closest('li.customize-control').attr('id'); $this.checkActiveCallbackToHideShow( $this, id ); } }); }, /** * Check if the data is json or not */ checkJsonData : function( tester ){ if(/^\s*$|undefined/.test(tester) || !(/number|object|array|string|boolean/.test(typeof tester))) { return false; }; return true; }, /** * Check all the active_callback to hide/show the fields */ checkActiveCallbackToHideShow : function( $this, id ){ jQuery(id).find('.fields').each(function(){ // Loop all the fields section var thisField = jQuery(this); if( thisField.data('active-callback') != undefined ){ var json_str = thisField.data('active-callback'); if( $this.checkJsonData( json_str ) ){ // If valid json var parse_json = JSON.parse( JSON.stringify( json_str ) ); // return array var relation,flag = []; // Check for relation if( parse_json.relation && parse_json.relation !== undefined ){ relation = parse_json.relation.toLowerCase(); } else { relation = 'and'; } jQuery.each(parse_json, function (key, data) { // Can be multiple conditions, loop through all var setting = parse_json[key].setting; var operator = parse_json[key].operator; var value = parse_json[key].value; var selected = thisField.closest('.kar_repeater_section').find('.fields[data-key="' + setting + '"]'); var valueToCheckWith, valueToCheckFrom; switch( selected.data('type') ){ case 'radio': valueToCheckWith = selected.find('.kar_radio:checked').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'checkbox': if( selected.find('.kar_checkbox').is(":checked") ){ valueToCheckWith = true; } else { valueToCheckWith = false; } valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'image': valueToCheckWith = selected.find('.kar_image').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'color': valueToCheckWith = selected.find('.kar_color').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'select': valueToCheckWith = selected.find('.kar_select').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'fontawesome': valueToCheckWith = selected.find('.kar_fontawesome').val().replace(/\s/g, ''); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'textarea': valueToCheckWith = selected.find('.kar_textarea').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'text': valueToCheckWith = selected.find('.kar_text').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'number': valueToCheckWith = selected.find('.kar_number').val(); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; case 'date': valueToCheckWith = selected.find('.kar_date').attr('data-value'); valueToCheckFrom = value; flag[key] = $this.checkWithOperator( valueToCheckWith, valueToCheckFrom, operator ); break; } }); if( relation == 'or' ){ // If one value is true if( flag.includes(true) ){ thisField.slideDown(); } else { thisField.slideUp(); } } else { // if all values are true then show the field if( flag.every(v => v === true) == true ){ thisField.slideDown(); } else { thisField.slideUp(); } } } } }) }, /** * Get all the controls and check the active_callback */ repeaterActiveCallback : function(){ var $this = this; wp.customize.control.each( function( control ) { if( control.params && control.params.type && control.params.type === 'advanced-repeater' ) { var id = '#customize-control-' + control.params.id; $this.checkActiveCallbackToHideShow( $this, id ); } }); }, checkWithOperator : function( valueToCheckWith, valueToCheckFrom, operator ){ switch( operator ){ case '==': case '=': case 'equals': case 'equal': return valueToCheckWith == valueToCheckFrom; break; case '===': return valueToCheckWith === valueToCheckFrom; break; case '!==': return valueToCheckWith !== valueToCheckFrom; break; case '!=': case 'not equal': return valueToCheckWith != valueToCheckFrom; break; case '>=': case 'greater or equal': case 'equal or greater': return valueToCheckWith >= valueToCheckFrom; break; case '<=': case 'smaller or equal': case 'equal or smaller': return valueToCheckWith <= valueToCheckFrom; break; case '>': case 'greater': return valueToCheckWith > valueToCheckFrom; break; case '<': case 'smaller': return valueToCheckWith < valueToCheckFrom; break; case 'contains': case 'in': return valueToCheckFrom.some( ele => valueToCheckWith.includes(ele) ); break; } }, /** * When click on remove image button remove the image and refresh the previewer */ removeImage : function(){ jQuery(document).on( 'click' , '.kar_remove_image' , function(e){ var id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); var parent = jQuery( e.target ).closest('.fields'); parent.find( '.kar_image_preview' ).show(); parent.find( 'img' ).removeAttr('src').hide(); parent.find( '.kar_image' ).val(''); jQuery( e.target ).hide(); // Refresh the previewer this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); }, /** * Open the image popup to select the image */ showImageUploadModal : function(){ var $thisObj = this; jQuery(document).on( 'click' , '.kar_select_image' , function(e){ e.preventDefault(); var $this = jQuery(this); var frame = wp.media({ title : 'Choose Image', frame: 'select', library : { type : 'image', }, button : { text : 'Insert' } }); frame.on( 'select' , function() { var selection = frame.state().get('selection').first(); // Get image attributes var image_link = selection.attributes.url; // Get image full url var image_id = selection.id; // Get image id var id = '#' + $this.closest('li.customize-control').attr('id'); $this.closest('.fields').find('.kar_image').val( image_id ); $this.closest('.fields').find('img').attr( 'src' , image_link ).show(); $this.closest('.fields').find('.kar_image_preview').hide(); $this.closest('.fields').find('.kar_remove_image').show(); // Refresh the previewer $thisObj.sortValues( $this.closest('.kar_wrapper') ); $thisObj.checkActiveCallbackToHideShow( $thisObj, id ); }); frame.on('open',function() { //Preselect attachements from my hidden input var selection = frame.state().get('selection'); id = $this.closest('.fields').find('.kar_image').val(); attachment = wp.media.attachment(id); attachment.fetch(); selection.add( attachment ? [ attachment ] : [] ); }); frame.open(); }); }, initializeColorPicker : function( selector ){ var $this = this; var id; jQuery( selector ).wpColorPicker({ change: function(event, ui) { var $this2 = jQuery(this); setTimeout(function(){ $this.sortValues( $this2.closest('.kar_wrapper') ); id = '#' + $this2.closest('li.customize-control').attr('id'); $this.checkActiveCallbackToHideShow( $this, id ); }, 100); }, clear: function() { var $this2 = jQuery(this); setTimeout(function(){ $this.sortValues( $this2.closest('.kar_wrapper') ); id = '#' + $this2.closest('li.customize-control').attr('id'); $this.checkActiveCallbackToHideShow( $this, id ); }, 100); } }); }, formatText : function(icon) { return jQuery('').append(' ').append(icon.text); }, initializeFontawesomeSelect2 : function( selector ){ var $this = this; jQuery( selector ).select2({ templateResult: $this.formatText // To show icons 'templateResult' is needed }); }, initializeSelect2 : function( selector ){ jQuery( selector ).select2(); }, /** * When same change event happens in the field, save the values */ saveValueOnChangeEvent : function(){ var id; // For input text jQuery(document).on( 'input', '.kar_text, .kar_number', function(e){ id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); // For textarea jQuery(document).on( 'input propertychange', '.kar_textarea', function(e){ id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); // For select2 jQuery(document).on( 'select2:select select2:unselect select2-removed', '.kar_select', function(e){ id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); // For select2 timepicker jQuery(document).on( 'select2:select select2:unselect select2-removed', '.kar_time_hr, .kar_time_min', function(e){ id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); // For select2 fontawesome jQuery(document).on( 'select2:select', '.kar_fontawesome', function(e){ id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); // For radio & checkbox button jQuery(document).on( 'change' , '.kar_radio,.kar_checkbox' , function(e){ id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); // For date jQuery(document).on( 'input', '.kar_date', function(e){ // Save only empty data from this event if( jQuery( e.target ).val().trim() == '' ){ jQuery( e.target ).attr( 'data-value', '' ); } id = '#' + jQuery( e.target ).closest('li.customize-control').attr('id'); this.sortValues( jQuery( e.target ).closest('.kar_wrapper') ); // Save the values this.checkActiveCallbackToHideShow( this, id ); }.bind(this)); }, /** * Stop adding repeater when it reaches the limit */ checkRepeaterLimit : function( parent ){ var count_repeater = parent.find('.kar_repeater_section').length; var limit = parent.data('limit'); if( limit != 0 && count_repeater >= limit ){ parent.nextAll('.kar_repeater_limit').addClass('active'); return true; } parent.nextAll('.kar_repeater_limit').removeClass('active'); return false; }, /** * When clicked on add new button, add new content */ addNewRepeater : function(){ jQuery(document).on( 'click', '.kar_add_new_section' , function(e){ // Check for limit var flag = this.checkRepeaterLimit( jQuery( e.target ).prevAll('.kar_wrapper') ); if( flag == true ){ // IF limit exceeded donot add new row return; } var content = jQuery( e.target ).prevAll('.kar_new_repeater').html(); // Select content jQuery( e.target ).prevAll('.kar_wrapper').append( content ); // Paste the selected content jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last .kar_fields_wrapper').show(); // Open the section by default // Change the arrow var select_anchor = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last a'); this.changeArrow( select_anchor ); // Initialize select2 on new repeater var dropdown_select = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last select.kar_select'); this.initializeSelect2( dropdown_select ); // Initialize select2 timepicker on new repeater var dropdown_select_hr = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last select.kar_time_hr'); this.initializeTimepicker( dropdown_select_hr ); var dropdown_select_min = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last select.kar_time_min'); this.initializeTimepicker( dropdown_select_min ); // Initialize select2 fontawesome on new repeater var dropdown_select = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last select.kar_fontawesome'); this.initializeFontawesomeSelect2( dropdown_select ); // For Colorpicker var colorpicker = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last input.kar_color'); this.initializeColorPicker( colorpicker ); // For radio buttons var last_repeater = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last'); this.regenerateRadioInputNames( last_repeater ); // For datepicker var date_field = jQuery( e.target ).prevAll('.kar_wrapper').find('.kar_repeater_section:last input.kar_date'); this.initializeDatePicker( date_field ); this.sortValues( jQuery( e.target ).prevAll('.kar_wrapper') ); // Save the values }.bind(this)); }, /** * Generate new names for radio input, if not it will not work */ regenerateRadioInputNames : function( last_repeater ){ var $this = this; last_repeater.find('.radio_fields').each( function(){ var name = 'radio_' + Math.floor((Math.random() * 100000) + 1); jQuery(this).find('input.kar_radio').attr( 'name' , name ); }); }, /** * When clicked on remove button, remove section */ deleteRepeaterSection : function(){ jQuery(document).on( 'click' , '.kar_remove_section' , function(e){ var parent_div = jQuery( e.target ).closest( '.kar_wrapper' ); var toRemove = jQuery( e.target ).closest('.kar_repeater_section'); var scrollToId = '#' + parent_div.prevAll('.kar_title_description_wrapper').attr('id'); // Remove section with fadeout effect toRemove.fadeOut( 500 , function() { toRemove.remove(); // Scroll to div jQuery( scrollToId )[0].scrollIntoView({ behavior: 'smooth', block: 'start' }); this.sortValues( parent_div ); this.checkRepeaterLimit( parent_div ); // Check limit to remove class 'active' }.bind(this)); }.bind(this)); }, /** * Change the values and refresh the previewer */ sortValues : function( parent_div ){ var toStoreValue = []; parent_div.find('.kar_repeater_section').each(function( index, e ){ // Loop all sections toStoreValue[index] = {}; jQuery(e).find('.count').text(index+1); // Rearrange numbers jQuery(e).find('.kar_fields_wrapper .fields').each(function( index2 ,e2 ){ // Loop all fields inside section var type = jQuery(e2).data('type'); // Text, textarea .... etc var key = jQuery(e2).data('key'); // Value will be saved in this key switch( type ){ case 'number': toStoreValue[index][key] = jQuery(e2).find('.kar_number').val(); break; case 'text': toStoreValue[index][key] = jQuery(e2).find('.kar_text').val().trim(); break; case 'textarea': toStoreValue[index][key] = jQuery(e2).find('.kar_textarea').val().trim(); break; case 'select': toStoreValue[index][key] = jQuery(e2).find('.kar_select').val(); break; case 'time': toStoreValue[index][key] = {}; toStoreValue[index][key]['h'] = jQuery(e2).find('.kar_time_hr').val(); toStoreValue[index][key]['m'] = jQuery(e2).find('.kar_time_min').val(); break; case 'fontawesome': toStoreValue[index][key] = jQuery(e2).find('.kar_fontawesome').val(); break; case 'color': toStoreValue[index][key] = jQuery(e2).find('.kar_color').val(); break; case 'image': toStoreValue[index][key] = jQuery(e2).find('.kar_image').val(); break; case 'radio': toStoreValue[index][key] = jQuery(e2).find('.kar_radio:checked').val(); break; case 'date': toStoreValue[index][key] = jQuery(e2).find('.kar_date').attr('data-value'); break; case 'checkbox': if( jQuery(e2).find('.kar_checkbox').is(":checked") ){ toStoreValue[index][key] = 'true'; } else { toStoreValue[index][key] = 'false'; } break; } }); }.bind(this)); parent_div.find('.kar_repeater_save_db').val( JSON.stringify( toStoreValue ) ).change(); }, /** * Initialize sortable library */ sortRepeatableSections : function(){ var $this = this; jQuery( ".kar_wrapper" ).sortable({ handle: ".kar_label_wrapper", update: function(ev) { $this.sortValues( jQuery( ev.originalEvent.target ).closest( '.kar_wrapper' ) ); } }); }, /** * When click on title, show/hide the content */ hideShowContent : function(){ jQuery(document).on( 'click' , '.kar_label_wrapper', function(e){ jQuery(e.target).closest('.kar_repeater_section').find('.kar_fields_wrapper').slideToggle('fast'); this.changeArrow( jQuery(e.target) ); }.bind(this)); }, /** * When click on title, change the arrow(up/down) */ changeArrow : function( $this ){ var icon_select = $this.closest('.kar_repeater_section').find('a .icon'); if( icon_select.hasClass('active') ){ icon_select.removeClass('active'); } else { icon_select.addClass('active'); } } } repeaterObj.init(); });