/*
EpsilonFramework Object
*/
var EpsilonFramework = 'undefined' === typeof( EpsilonFramework ) ? {} : EpsilonFramework;
/*
EpsilonFramework.Repeater Object
*/
EpsilonFramework.repeater = 'undefined' === typeof( EpsilonFramework.repeater ) ? {} : EpsilonFramework.repeater;
/*
EpsilonFramework.sectionRepeater Object
*/
EpsilonFramework.sectionRepeater = 'undefined' === typeof( EpsilonFramework.sectionRepeater ) ? {} : EpsilonFramework.sectionRepeater;
/**
* Improved Color Picker
*
* @type {{init: EpsilonFramework.colorPickers.init}}
*/
EpsilonFramework.colorPickers = {
/**
* Initiate a color picker
* @param selector
*/
init: function( selector ) {
var selector = jQuery( selector ).find( '.epsilon-color-picker' ),
self = this,
settings = {
changeDelay: 500,
theme: 'default',
change: self.changePallete
},
clear,
instance;
if ( 'function' !== typeof jQuery.fn.minicolors ) {
return;
}
if ( '' !== selector.attr( 'placeholder' ) ) {
settings.defaultValue = selector.attr( 'placeholder' );
}
if ( 'rgba' === selector.attr( 'data-attr-mode' ) ) {
settings.format = 'rgb';
settings.opacity = true;
}
selector.minicolors( settings );
clear = selector.parents( '.customize-control-epsilon-color-picker' ).find( 'a' );
if ( ! clear.length ) {
clear = selector.parents( '.repeater-field-epsilon-color-picker' ).find( 'a' );
}
clear.on( 'click', function( e ) {
e.preventDefault();
instance = jQuery( this ).parents( '.customize-control-epsilon-color-picker' ).find( 'input.epsilon-color-picker' );
if ( ! instance.length ) {
instance = jQuery( this ).parents( '.repeater-field-epsilon-color-picker' ).find( 'input.epsilon-color-picker' );
}
instance.minicolors( 'value', jQuery( this ).attr( 'data-default' ) );
instance.trigger( 'change' );
} );
},
/**
* Real time changes to the "pallete"
*
* @param value
* @param opacity
*/
changePallete: function( value, opacity ) {
jQuery( '.epsilon-color-scheme-selected' ).find( '*[data-field-id="' + jQuery( this ).attr( 'data-customize-setting-link' ) + '"]' ).css( 'background-color', value );
}
};
/**
* Color scheme generator
*/
EpsilonFramework.colorSchemes = {
/**
* Init wrapper
*/
init: function() {
/**
* Set variables
*/
var context = jQuery( '.epsilon-color-scheme' ), options, input, json, api,
colorSettings = [], css = {};
if ( ! context.length ) {
return;
}
options = context.find( '.epsilon-color-scheme-option' );
input = context.parent().find( '[data-customize-setting-link]' ).first();
json = jQuery.parseJSON( options.first().find( 'input' ).val() );
api = wp.customize;
colorSettings = [];
css = {
'action': 'epsilon_generate_color_scheme_css',
'class': 'Epsilon_Color_Scheme',
'id': '',
'data': {}
};
jQuery.each( json, function( index, value ) {
colorSettings.push( index );
} );
_.each( colorSettings, function( setting ) {
css.data[ setting ] = api( setting )();
if ( 'undefined' !== typeof(api.control( setting )) ) {
api.control( setting ).container.on( 'change', 'input.epsilon-color-picker', _.debounce( function() {
context.siblings( '.epsilon-color-scheme-selected' ).
find( '.epsilon-color-scheme-palette' ).
find( '*[data-field-id="' + setting + '"]' ).
css( 'background', jQuery( this ).attr( 'value' ) );
css.data[ setting ] = api( setting )();
api.previewer.send( 'update-inline-color-schemes-css', css );
}, 800 ) );
}
} );
/**
* On clicking a color scheme, update the color pickers
*/
jQuery( '.epsilon-color-scheme-option' ).on( 'click', function() {
var val = jQuery( this ).attr( 'data-color-id' ),
json = jQuery.parseJSON( jQuery( this ).find( 'input' ).val() );
/**
* Find the customizer options
*/
jQuery.each( json, function( index, value ) {
/**
* Set values
*/
jQuery( '#customize-control-' + index + ' .epsilon-color-picker' ).minicolors( 'value', value );
api( index ).set( value );
context.siblings( '.epsilon-color-scheme-selected' ).find( '.epsilon-color-scheme-palette' ).find( '*[data-field-id="' + index + '"]' ).css( 'background', value );
} );
/**
* Remove the selected class from siblings
*/
jQuery( this ).siblings( '.epsilon-color-scheme-option' ).removeClass( 'selected' );
/**
* Make active the current selection
*/
jQuery( this ).addClass( 'selected' );
/**
* Trigger change
*/
input.val( val ).trigger( 'change' );
} );
/**
* Advanced toggler
*/
jQuery( '.epsilon-control-dropdown' ).on( 'click', function() {
jQuery( this ).toggleClass( 'active' );
jQuery( this ).find( 'span' ).toggleClass( 'dashicons-arrow-down dashicons-arrow-up' );
context.slideToggle();
} );
}
};
/**
* Customizer navigation
* @type {{}}
*/
EpsilonFramework.customizerNavigation = {
/**
* Initiate customizer navigation
*
* @param selector
*/
init: function( selector ) {
selector.find( '.epsilon-customizer-navigation' ).on( 'click', function( e ) {
e.preventDefault();
if ( 'undefined' !== typeof( wp.customize.section( jQuery( this ).attr( 'data-customizer-section' ) ) ) ) {
if ( jQuery( this ).attr( 'data-doubled' ) ) {
wp.customize.section( jQuery( this ).attr( 'data-customizer-section' ) ).headContainer.trigger( 'click' );
} else {
wp.customize.section( jQuery( this ).attr( 'data-customizer-section' ) ).focus();
}
}
} );
}
};
/**
* Icon Picker Initiator
*
* @type {{init: EpsilonFramework.iconPickers.init}}
*/
EpsilonFramework.iconPickers = {
/**
* Context
*/
control: null,
/**
* Init the icon picker
*
* @param control
* @param inRepeater
*/
init: function( control, inRepeater ) {
this.control = control;
var icon, label, filter, temp, collection = control.container.find( '.epsilon-icons > i' ), input = control.container.find( '.search-container input' );
/**
* Icon container toggler
*/
control.container.on( 'click', '.epsilon-open-icon-picker', function( e ) {
e.preventDefault();
jQuery( this ).toggleClass( 'opened-icon-picker' );
control.container.find( '.epsilon-icon-picker-container' ).toggleClass( 'opened' );
} );
/**
* Icon selection
*/
control.container.on( 'click', '.epsilon-icons-container .epsilon-icons > i', function( e ) {
control.container.find( '.epsilon-icons > i.selected' ).removeClass( 'selected' );
icon = jQuery( this ).addClass( 'selected' ).attr( 'data-icon' );
label = jQuery( this ).addClass( 'selected' ).attr( 'data-search' );
control.container.find( '.epsilon-icon-name > i' ).removeClass().addClass( icon );
control.container.find( '.epsilon-icon-name > .icon-label' ).html( label );
/**
* Set value
*/
if ( ! inRepeater ) {
control.setting.set( icon );
} else {
control.container.find( '.epsilon-icon-picker' ).attr( 'value', icon ).trigger( 'change' );
}
} );
/**
* Search functionality
*/
control.container.on( 'keyup change', '.search-container input', _.debounce( function( e ) {
filter = input.val().toLowerCase();
jQuery.each( collection, function() {
temp = jQuery( this ).attr( 'data-search' ).toLowerCase();
jQuery( this )[ temp.indexOf( filter ) !== - 1 ? 'show' : 'hide' ]();
} );
}, 1000 ) );
}
};
/**
* Initiate the Image Control
*/
EpsilonFramework.image = {
/**
* Initiator
*/
init: function( control ) {
var self = this,
image,
temp,
size,
setting = {},
thumb;
/**
* Image selection
*/
control.container.on( 'click', '.image-upload-button', function( e ) {
/**
* Open the wp.media frame
*/
image = wp.media( {
multiple: false,
} ).open();
/**
* On selection, save the data in a JSON
*/
image.on( 'select', function() {
temp = image.state().get( 'selection' ).first();
size = input.attr( 'data-size' );
if ( 'undefined' === typeof (temp.toJSON().sizes[ size ]) ) {
size = 'full';
}
setting.id = temp.id;
setting.url = temp.toJSON().sizes[ size ].url;
self.saveValue( control, setting );
self.setImage( control, setting.url );
/**
* Show buttons
*/
control.container.find( '.actions .image-upload-remove-button' ).show();
if ( ! _.isEmpty( control.params.default ) ) {
control.container.find( '.actions .image-default-button' ).show();
}
} );
} );
/**
* Image deletion
*/
control.container.on( 'click', '.image-upload-remove-button', function( e ) {
e.preventDefault();
thumb = control.container.find( '.epsilon-image' );
self.saveValue( control, '' );
if ( thumb.length ) {
thumb.find( 'img' ).fadeOut( 200, function() {
thumb.removeClass( 'epsilon-image' ).addClass( 'placeholder' ).html( EpsilonTranslations.selectFile );
} );
}
/**
* If we don`t have an image, we can hide these buttons
*/
jQuery( this ).hide();
if ( ! _.isEmpty( control.params.default ) ) {
control.container.find( '.actions .image-default-button' ).show();
}
} );
control.container.on( 'click', '.image-default-button', function( e ) {
e.preventDefault();
thumb = control.container.find( '.epsilon-image' );
self.saveValue( control, control.params.default );
self.setImage( control, control.params.default.url );
control.container.find( '.actions .image-upload-remove-button' ).show();
} );
},
/**
* Set image in the customizer option control
*
* @param control
* @param image
*/
setImage: function( control, image ) {
/**
* If we already have an image, we need to return that div, else we grab the placeholder
*
* @type {*}
*/
var thumb = control.container.find( '.epsilon-image' ).length ? control.container.find( '.epsilon-image' ) : control.container.find( '.placeholder' );
/**
* We "reload" the image container
*/
if ( thumb.length ) {
thumb.removeClass( 'epsilon-image placeholder' ).addClass( 'epsilon-image' );
thumb.html( '' );
thumb.append( '
' );
thumb.find( 'img' ).fadeIn( 200 );
}
},
/**
* Save value in database
*
* @param control
* @param val
*/
saveValue: function( control, val ) {
var input = control.container.find( '.epsilon-controller-image-container > input' );
if ( 'object' === typeof(val) ) {
control.setting.set( JSON.stringify( val ) );
jQuery( input ).attr( 'value', JSON.stringify( val ) ).trigger( 'change' );
} else {
control.setting.set( '' );
jQuery( input ).attr( 'value', '' ).trigger( 'change' );
}
},
};
/**
* Initiate the Layouts Control
*
* jQuery Events {
* epsilon_column_count_change <-- Happens before the changes are made to the columns
* epsilon_column_count_changed <-- Happens right after the columns are changed, save is bound to it
* epsilon_column_size_changed <-- Happens right after a column is resized, save is bound to it
* }
*
* @type {{}}
*/
EpsilonFramework.layouts = {
/**
* Redundant constant for columns
*/
colClasses: 'col12 col11 col10 col9 col8 col7 col6 col5 col4 col3 col2 col1',
/**
* Buttons
*/
html: {
buttonLeft: ' ',
buttonRight: ' '
},
instance: function( context ) {
/**
* Variables
*/
this.context = context;
this.layoutButtons = this.context.find( '.epsilon-control-group > a' );
this.resizeButtons = this.context.find( '.epsilon-layouts-setup > .epsilon-column > a' );
this.maxColumns = this.layoutButtons.length;
this.minSpan = parseFloat( this.context.attr( 'data-min-span' ) );
this.activeColumns = null;
this.lastColumnsState = null;
/**
* Handle actions per instance
*/
EpsilonFramework.layouts.handle_actions( this );
/**
* Whenever the column count or size changes, we save data to the hidden field
*/
this.context.on( 'epsilon_column_count_changed epsilon_column_size_changed', EpsilonFramework.layouts._save );
},
/**
* Initiate the layouts functionality (constructor)
*/
init: function( selector ) {
new EpsilonFramework.layouts.instance( jQuery( selector ).find( '.epsilon-layouts-container' ) );
},
/**
* Save state in a json
* @private
*/
_save: function( e ) {
var json = {
'columnsCount': e.instance.activeColumns,
'columns': {}
};
jQuery.each( e.instance.context.find( '.epsilon-column' ), function( index ) {
json.columns[ index + 1 ] = {
'index': index + 1,
'span': jQuery( this ).attr( 'data-columns' )
};
} );
if ( null === json.columnsCount ) {
json.columnsCount = e.instance.context.find( '.epsilon-column' ).length;
}
e.instance.context.find( 'input' ).val( JSON.stringify( json ) ).trigger( 'change' );
},
/**
* Handle the click events in the control
*/
handle_actions: function( instance ) {
/**
* Hide / show columns
*/
this._advanced_toggler( instance );
/**
* Column resize event ( + / - buttons )
*/
this._column_resize( instance );
/**
* Addition removal of columns events
*/
this._column_recount( instance );
this._layout_select( instance );
this._equalize_columns( instance );
},
/**
* When selecting a layout, recalc/remove/readd divs in the container
*
* @private
*/
_layout_select: function( instance ) {
var self = this,
columns;
instance.layoutButtons.on( 'click', function( e ) {
e.preventDefault();
/**
* Handle addition/deletion through jQuery events
*/
jQuery( instance.context ).trigger( {
'type': 'epsilon_column_count_change',
'columns': {
'selected': parseFloat( jQuery( this ).attr( 'data-button-value' ) ),
'beforeSelection': instance.context.find( '.epsilon-layouts-setup > .epsilon-column' ).length
}
} );
/**
* Visual changes
*/
jQuery( this ).
addClass( 'active' ).
siblings( 'a' ).
removeClass( 'active' );
} );
},
/**
* Handle addition/removal of columns
* @private
*/
_column_recount: function( instance ) {
var context = instance.context,
self = this,
columns, operation, i, j;
jQuery( instance.context ).on( 'epsilon_column_count_change', function( e ) {
/**
* Update instance variables
*/
instance.activeColumns = e.columns.selected;
instance.lastColumnsState = e.columns.beforeSelection;
/**
* In case we don't have anything to modify, we can terminate here
*/
if ( instance.activeColumns === instance.lastColumnsState ) {
return;
}
/**
* Are we adding or subtrating?
*/
operation = instance.lastColumnsState < instance.activeColumns ? 'adding' : 'subtracting';
i = instance.activeColumns - instance.lastColumnsState;
if ( 'subtracting' === operation ) {
instance.context.find( '.epsilon-layouts-setup > .epsilon-column' ).
slice( - ( instance.lastColumnsState - instance.activeColumns ) ).
remove();
} else {
for ( j = 0; j < i; j ++ ) {
instance.context.find( '.epsilon-layouts-setup' ).
append(
'
' +
self.html.buttonLeft +
self.html.buttonRight +
'
' );
}
}
/**
* Trigger event to changed
*/
jQuery( instance.context ).trigger( {
'type': 'epsilon_column_count_changed',
'instance': instance
} );
} );
},
/**
* Handle the resize event in the control
*
* @private
*/
_column_resize: function( instance ) {
var self = this,
position,
elementToSubtractFrom,
elementToAddOn;
instance.context.find( '.epsilon-layouts-setup' ).on( 'click', '.epsilon-column > a', function( e ) {
elementToAddOn = jQuery( this ).parent();
position = elementToAddOn.index();
if ( 'right' === jQuery( this ).attr( 'data-action' ) ) {
elementToSubtractFrom = instance.context.find( '.epsilon-layouts-setup > .epsilon-column' ).eq( position + 1 );
} else {
elementToSubtractFrom = instance.context.find( '.epsilon-layouts-setup > .epsilon-column' ).eq( position - 1 );
}
self.calc_column_resize( elementToSubtractFrom, elementToAddOn, instance );
} );
},
/**
* Change spans accordingly
*
* @param subtract
* @param add
*/
calc_column_resize: function( subtract, add, instance ) {
if ( parseFloat( subtract.attr( 'data-columns' ) ) === instance.minSpan ) {
return;
}
subtract.attr( 'data-columns',
parseFloat( subtract.attr( 'data-columns' ) ) - 1 ).
removeClass( this.colClasses ).
addClass( 'col' + subtract.attr( 'data-columns' ) );
add.attr( 'data-columns',
parseFloat( add.attr( 'data-columns' ) ) + 1 ).
removeClass( this.colClasses ).
addClass( 'col' + add.attr( 'data-columns' ) );
/**
* Trigger event to change
*/
jQuery( instance.context ).trigger( {
'type': 'epsilon_column_size_changed',
'instance': instance
} );
},
/**
* Equalize coolumns, this is happening after a new layout is selected
* @private
*/
_equalize_columns: function( instance ) {
var context = instance.context,
self = this;
jQuery( instance.context ).on( 'epsilon_column_count_changed', function( e ) {
switch ( instance.activeColumns ) {
case 2:
instance.context.find( '.epsilon-column' ).removeClass( self.colClasses );
instance.context.find( '.epsilon-column' ).first().addClass( 'col8' ).attr( 'data-columns', ( 8 ) );
instance.context.find( '.epsilon-column' ).last().addClass( 'col4' ).attr( 'data-columns', ( 4 ) );
break;
default:
instance.context.find( '.epsilon-column' ).
removeClass( self.colClasses ).
addClass( 'col' + ( 12 / instance.activeColumns ) ).
attr( 'data-columns', ( 12 / instance.activeColumns ) );
break;
}
} );
},
/**
* Advanced options toggler ( for column resize )
*
* @private
*/
_advanced_toggler: function( instance ) {
/**
* On clicking the advanced options toggler,
*/
instance.context.on( 'click', '.epsilon-control-advanced', function( e ) {
e.preventDefault();
jQuery( this ).toggleClass( 'active' );
jQuery( '#' + jQuery( this ).attr( 'data-unique-id' ) ).slideToggle().addClass( 'active' );
} );
}
};
/**
* Range Slider Initiator
*
* @type {{init: EpsilonFramework.rangeSliders.init}}
*/
EpsilonFramework.rangeSliders = {
/**
* Init wrapper
*
* @param selector
*/
init: function( selector ) {
var context = jQuery( selector ).hasClass( 'slider-container' ) ? jQuery( selector ) : jQuery( selector ).find( '.slider-container' ),
slider = context.find( '.ss-slider' ),
input = context.find( '.rl-slider' ),
inputId = input.attr( 'id' ),
id = slider.attr( 'id' );
if ( ! context.length ) {
return;
}
jQuery( '#' + id ).slider( {
value: parseFloat( jQuery( '#' + inputId ).attr( 'value' ) ),
range: 'min',
min: parseFloat( jQuery( '#' + id ).attr( 'data-attr-min' ) ),
max: parseFloat( jQuery( '#' + id ).attr( 'data-attr-max' ) ),
step: parseFloat( jQuery( '#' + id ).attr( 'data-attr-step' ) ),
/**
* Removed Change event because server was flooded with requests from
* javascript, sending changesets on each increment.
*
* @param event
* @param ui
*/
slide: function( event, ui ) {
jQuery( '#' + inputId ).attr( 'value', ui.value );
},
/**
* Bind the change event to the "actual" stop
* @param event
* @param ui
*/
stop: function( event, ui ) {
jQuery( '#' + inputId ).trigger( 'change' );
}
} );
jQuery( input ).on( 'focus', function() {
jQuery( this ).blur();
} );
jQuery( '#' + inputId ).attr( 'value', ( jQuery( '#' + id ).slider( 'value' ) ) );
jQuery( '#' + inputId ).on( 'change', function() {
jQuery( '#' + id ).slider( {
value: jQuery( this ).val()
} );
} );
},
};
/**
* Helper object, we can keep here functions that render content or help with UI interaction
*/
EpsilonFramework.repeater.base = {
/**
* Deletes a row from the control
*
* @param index
*/
delete: function( rowInstance, index, control ) {
var currentSettings = EpsilonFramework.repeater.base.getValue( control ),
row,
i,
prop;
if ( currentSettings[ index ] ) {
// Find the row
row = control.rows[ index ];
if ( row ) {
// Remove the row settings
delete currentSettings[ index ];
// Remove the row from the rows collection
delete control.rows[ index ];
}
}
currentSettings = EpsilonFramework.repeater.base.cleanArray( currentSettings );
control.rows = EpsilonFramework.repeater.base.cleanArray( control.rows );
jQuery.each( control.rows, function( index, element ) {
EpsilonFramework.repeater.base.setRowIndex( element, index, control );
} );
// Update the new setting values
EpsilonFramework.repeater.base.setValue( control, currentSettings, true );
// Remap the row numbers
i = 1;
for ( prop in control.rows ) {
if ( control.rows.hasOwnProperty( prop ) && control.rows[ prop ] ) {
EpsilonFramework.repeater.base.updateLabel( control.rows[ prop ], control );
i ++;
}
}
control.currentIndex--;
},
/**
* Add a new Row to the customizer
*
* @param instance
* @param data
* @returns {EpsilonFramework.repeater.row.constructor}
*/
add: function( instance, data ) {
var control = instance,
template = _.memoize( EpsilonFramework.repeater.base.repeaterTemplate( control ) ),
settingValue = EpsilonFramework.repeater.base.getValue( control ),
newRowSetting = {},
templateData,
newRow,
i;
/**
* In case we don`t have a template, we terminate here
*/
if ( ! template ) {
return;
}
/**
* Extend template data with what we passed in PHP
*/
templateData = jQuery.extend( true, {}, control.params.fields );
/**
* In case we added the row with "known" data, we need to overwrite the array
*/
if ( data ) {
for ( i in data ) {
if ( data.hasOwnProperty( i ) && templateData.hasOwnProperty( i ) ) {
templateData[ i ][ 'default' ] = data[ i ];
}
}
}
/**
* Add an index
*
* @type {number}
*/
templateData.index = control.currentIndex;
/**
* Render the HTML template with underscores
*/
template = template( templateData );
/**
* Initiate a new ROW
*
* @type {*}
*/
newRow = new EpsilonFramework.repeater.row.constructor(
control.currentIndex,
jQuery( template ).appendTo( control.repeaterContainer ),
control.params.rowLabel,
control
);
/**
* Bind events
*
* 1. Remove row event
*/
newRow.container.on( 'row:remove', function( e, rowIndex ) {
EpsilonFramework.repeater.base.delete( this, rowIndex, control );
} );
/**
* 2. Update row event
*/
newRow.container.on( 'row:update', function( e, rowIndex, fieldName, element, control ) {
EpsilonFramework.repeater.base.updateField.call( e, rowIndex, fieldName, element, control );
EpsilonFramework.repeater.base.updateLabel( newRow, control );
} );
/**
* 3. Initiate sortable script
*/
newRow.header.on( 'mousedown', function() {
newRow.container.trigger( 'row:start-dragging' );
} );
/**
* Register the new row in the control
*
* @type {*}
*/
control.rows[ control.currentIndex ] = newRow;
/**
* Add a new "index" to the setting ( easier to render in the frontend )
*/
for ( i in templateData ) {
if ( templateData.hasOwnProperty( i ) ) {
newRowSetting[ i ] = templateData[ i ][ 'default' ];
}
}
/**
* Add a value to the setting
* @type {{}}
*/
settingValue[ control.currentIndex ] = newRowSetting;
/**
* Set it
*/
if ( ! data ) {
EpsilonFramework.repeater.base.setValue( control, settingValue, true );
}
/**
* Update index
*/
control.currentIndex ++;
/**
* Return constructor
*/
return newRow;
},
/**
* Set the value of the customizer option
*
* @param instance
* @param newValue
*/
setValue: function( instance, newValue ) {
instance.setting.set( [] );
instance.setting.set( newValue );
},
/**
* Get the setting value
*
* @param instance
*/
getValue: function( instance ) {
return instance.setting.get();
},
/**
* Update a single field inside a row.
* Triggered when a field has changed
*
* @param rowIndex
* @param fieldId
* @param element
* @param control
*/
updateField: function( rowIndex, fieldId, element, control ) {
var row, currentSettings;
if ( ! control.rows[ rowIndex ] ) {
return;
}
if ( ! control.params.fields[ fieldId ] ) {
return;
}
row = control.rows[ rowIndex ];
currentSettings = EpsilonFramework.repeater.base.getValue( control );
if ( _.isUndefined( currentSettings[ row.rowIndex ][ fieldId ] ) ) {
return;
}
switch ( control.params.fields[ fieldId ].type ) {
case 'checkbox':
case 'epsilon-toggle':
currentSettings[ row.rowIndex ][ fieldId ] = jQuery( element ).prop( 'checked' );
break;
default:
currentSettings[ row.rowIndex ][ fieldId ] = jQuery( element ).val();
break;
}
EpsilonFramework.repeater.base.setValue( control, currentSettings );
},
/**
* Drag and drop functionality
* @param control
*/
sort: function( control, data ) {
var rows = control.repeaterContainer.find( '.repeater-row' ),
settings = EpsilonFramework.repeater.base.getValue( control ),
newOrder = [],
newRows = [],
newSettings = [];
rows.each( function( i, element ) {
newOrder.push( jQuery( element ).data( 'row' ) );
} );
jQuery.each( newOrder, function( newPosition, oldPosition ) {
newRows[ newPosition ] = control.rows[ oldPosition ];
EpsilonFramework.repeater.base.setRowIndex( newRows[ newPosition ], newPosition, control );
newSettings[ newPosition ] = settings[ oldPosition ];
} );
/**
* Text editor needs to be reinitiated after sorting (else it loses the "visual" part)
*/
EpsilonFramework.repeater.base.reinitTexteditor( control, data.item );
control.rows = newRows;
EpsilonFramework.repeater.base.setValue( control, newSettings );
},
/**
* Handle image uploading in a repeater field
*
* @param instance
* @param container
*/
handleImageUpload: function( instance, container ) {
var self = this,
setting = {},
temp,
size,
input,
image = wp.media( {
multiple: false,
} ).open();
/**
* On selection, save the data in a JSON
*/
image.on( 'select', function() {
input = container.find( 'input' );
temp = image.state().get( 'selection' ).first();
size = input.attr( 'data-size' );
if ( 'undefined' === typeof (temp.toJSON().sizes[ size ]) ) {
size = 'full';
}
setting.id = temp.id;
setting.url = temp.toJSON().sizes[ size ].url;
self._setImage( container, setting.url );
input.attr( 'value', ( 'url' === input.attr( 'data-save-mode' ) ? setting.url : setting.id ) ).trigger( 'change' );
container.find( '.actions .image-upload-remove-button' ).show();
} );
},
/**
* Handle Image Removal in a repeater field
*
* @param instance
* @param container
*/
handleImageRemoval: function( instance, container ) {
var self = this,
setting = {},
thumb = container.find( '.epsilon-image' );
if ( thumb.length ) {
thumb.find( 'img' ).fadeOut( 200, function() {
thumb.removeClass( 'epsilon-image' ).addClass( 'placeholder' ).html( EpsilonTranslations.selectFile );
} );
}
container.find( '.actions .image-upload-remove-button' ).hide();
container.find( 'input' ).attr( 'value', '' ).trigger( 'change' );
},
/**
* Set image in the customizer option control
*
* @param control
* @param image
*
* @access private
*/
_setImage: function( container, image ) {
/**
* If we already have an image, we need to return that div, else we grab the placeholder
*
* @type {*}
*/
var thumb = container.find( '.epsilon-image' ).length ? container.find( '.epsilon-image' ) : container.find( '.placeholder' );
/**
* We "reload" the image container
*/
if ( thumb.length ) {
thumb.removeClass( 'epsilon-image placeholder' ).addClass( 'epsilon-image' );
thumb.html( '' );
thumb.append( '
' );
thumb.find( 'img' ).fadeIn( 200 );
}
},
/**
* Load Underscores template
*
* @since 1.2.0
* @returns {Function}
*/
repeaterTemplate: function() {
var compiled,
options = {
evaluate: /<#([\s\S]+?)#>/g,
interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
escape: /\{\{([^\}]+?)\}\}(?!\})/g,
variable: 'data'
};
return function( data ) {
compiled = _.template( jQuery( '.customize-control-epsilon-repeater-content' ).html(), null, options );
return compiled( data );
};
},
/**
* Set row's index
*
* @param rowIndex
*/
setRowIndex: function( rowInstance, rowIndex, control ) {
rowInstance.rowIndex = rowIndex;
rowInstance.container.attr( 'data-row', rowIndex );
rowInstance.container.data( 'row', rowIndex );
EpsilonFramework.repeater.base.updateLabel( rowInstance, control );
},
/**
* Toggle vizibility
*
* @param instance
*/
toggleMinimize: function( instance ) {
// Store the previous state.
instance.container.find( '.repeater-row-content' ).slideToggle( 300, function() {
instance.container.toggleClass( 'minimized' );
instance.header.find( '.dashicons' ).toggleClass( 'dashicons-arrow-up' ).toggleClass( 'dashicons-arrow-down' );
} );
},
/**
* Remove a row from the instance
*
* @param instance
*/
removeRow: function( instance ) {
instance.container.slideUp( 300, function() {
jQuery( this ).detach();
} );
instance.container.trigger( 'row:remove', [ instance.rowIndex ] );
},
/**
* Update label
*
* @param instance
* @param control
*/
updateLabel: function( instance, control ) {
var rowLabelField,
rowLabel,
rowLabelSelector;
if ( 'field' === instance.label.type ) {
rowLabelField = instance.container.find( '.repeater-field [data-field="' + instance.label.field + '"]' );
if ( _.isFunction( rowLabelField.val ) ) {
rowLabel = rowLabelField.val();
if ( '' !== rowLabel ) {
if ( ! _.isUndefined( control.params.fields[ instance.label.field ] ) ) {
if ( ! _.isUndefined( control.params.fields[ instance.label.field ].type ) ) {
if ( 'select' === control.params.fields[ instance.label.field ].type ) {
if ( ! _.isUndefined( control.params.fields[ instance.label.field ].choices ) &&
! _.isUndefined( control.params.fields[ instance.label.field ].choices[ rowLabelField.val() ] ) ) {
rowLabel = control.params.fields[ instance.label.field ].choices[ rowLabelField.val() ];
}
} else if ( 'radio' === control.params.fields[ instance.label.field ].type || 'radio-image' === control.params.fields[ instance.label.field ].type ) {
rowLabelSelector = control.selector + ' [data-row="' + instance.rowIndex + '"] .repeater-field [data-field="' + instance.label.field + '"]:checked';
rowLabel = jQuery( rowLabelSelector ).val();
}
}
}
instance.header.find( '.repeater-row-label' ).text( rowLabel );
return;
}
}
}
instance.header.find( '.repeater-row-label' ).text( instance.label.value + ' ' + ( instance.rowIndex + 1 ) );
},
/**
* Handle the icon picker field
*
* @param instance
* @param container
*/
handleIconPickerToggle: function( instance, container ) {
container.find( '.epsilon-icon-picker-container' ).toggleClass( 'opened' );
},
/**
* Handle the selection of the icon picker
*
* @param instance
* @param container
*/
handleIconPickerSelection: function( instance, clicked, container ) {
var icon, label;
container.find( '.epsilon-icons > i.selected' ).removeClass( 'selected' );
icon = jQuery( clicked ).addClass( 'selected' ).attr( 'data-icon' );
icon = jQuery( clicked ).addClass( 'selected' ).attr( 'data-icon' );
container.find( '.epsilon-icon-name > i' ).removeClass().addClass( icon );
container.find( '.epsilon-icon-name > .icon-label' ).html( label );
/**
* Set value
*/
container.find( '.epsilon-icon-picker' ).attr( 'value', icon ).trigger( 'change' );
},
/**
* Handle the Filtering of the icons
*
* @param instance
* @param input
* @param container
*/
handleIconPickerFiltering: function( instance, input, container ) {
var filter, temp,
collection = jQuery( container ).find( '.epsilon-icons > i' );
filter = jQuery( input ).val().toLowerCase();
jQuery.each( collection, function() {
temp = jQuery( this ).attr( 'data-search' ).toLowerCase();
jQuery( this )[ temp.indexOf( filter ) !== - 1 ? 'show' : 'hide' ]();
} );
},
/**
* Initiate the text editor in the repeater field
*
* @param container
*/
initTexteditor: function( container ) {
var textarea = container.find( 'textarea' ),
editorId;
jQuery.each( textarea, function() {
editorId = jQuery( this ).attr( 'id' );
wp.editor.initialize( editorId, {
tinymce: {
wpautop: true,
setup: function( editor ) {
editor.on( 'change', function( e ) {
editor.save();
jQuery( editor.getElement() ).trigger( 'change' );
} );
}
},
quicktags: true
} );
} );
},
/**
* Remove the editor so we can add it again
*
* @param container
*/
reinitTexteditor: function( instance, container ) {
var self = this,
textarea = container.find( 'textarea' );
jQuery.each( textarea, function() {
wp.editor.remove( jQuery( this ).attr( 'id' ) );
wp.editor.initialize( jQuery( this ).attr( 'id' ), {
tinymce: {
wpautop: true,
setup: function( editor ) {
editor.on( 'change', function( e ) {
editor.save();
jQuery( editor.getElement() ).trigger( 'change' );
} );
}
},
quicktags: true
} );
} );
},
/**
* Cleans an array (undefined values), returns value
*
* @param actual
* @returns {Array}
*/
cleanArray: function( actual ) {
var newArray = [],
self = this;
for ( var i = 0; i < actual.length; i ++ ) {
if ( actual[ i ] ) {
newArray.push( actual[ i ] );
}
}
return newArray;
},
};
/**
* Row object
*/
EpsilonFramework.repeater.row = {
/**
* Trigger a new row
*
* @param rowIndex
* @param container
* @param label
* @param control
*/
constructor: function( rowIndex, container, label, control ) {
var self = this;
this.rowIndex = rowIndex;
this.container = container;
this.label = label;
this.header = this.container.find( '.repeater-row-header' );
/**
* Events
*/
this.header.on( 'click', function() {
EpsilonFramework.repeater.base.toggleMinimize( self );
} );
this.container.on( 'click', '.repeater-row-minimize', function() {
EpsilonFramework.repeater.base.toggleMinimize( self );
} );
this.container.on( 'click', '.repeater-row-remove', function() {
EpsilonFramework.repeater.base.removeRow( self );
} );
this.container.on( 'keyup change', 'input, select, textarea', function( e ) {
self.container.trigger( 'row:update', [ self.rowIndex, jQuery( e.target ).data( 'field' ), e.target, control ] );
} );
EpsilonFramework.repeater.base.updateLabel( self, control );
}
};
/**
* Section Repeater object
*
* @type {{}}
*/
EpsilonFramework.sectionRepeater.base = {
/**
* Deletes a section from the control
*
* @param index
*/
delete: function( sectionInstance, index, control ) {
var self = this,
currentSettings = self.getValue( control ),
section,
i,
prop;
if ( currentSettings[ index ] ) {
// Find the row
section = control.sections[ index ];
if ( section ) {
// Remove the sections settings
delete currentSettings[ index ];
// Remove the sections from the rows collection
delete control.sections[ index ];
currentSettings = EpsilonFramework.sectionRepeater.base.cleanArray( currentSettings );
control.sections = EpsilonFramework.sectionRepeater.base.cleanArray( control.sections );
// Update the new setting values
self.setValue( control, currentSettings, true );
}
}
jQuery.each( control.sections, function( index, element ) {
EpsilonFramework.sectionRepeater.base.setSectionIndex( element, index, control );
} );
// Remap the row numbers
i = 1;
for ( prop in control.sections ) {
if ( control.sections.hasOwnProperty( prop ) && control.sections[ prop ] ) {
self.updateLabel( control.sections[ prop ], control );
i ++;
}
}
control.currentIndex --;
},
/**
* Add a new section handler
*/
add: function( control, type, data ) {
var self = this,
template = _.memoize( EpsilonFramework.repeater.base.repeaterTemplate() ),
settingValue = self.getValue( control ),
newSectionSetting = {},
templateData,
newSection,
i;
/**
* In case we don`t have a template, we terminate here
*/
if ( ! template ) {
return;
}
/**
* Extend template data with what we passed in PHP
*/
if ( 'undefined' === typeof ( control.params.sections[ type ] ) ) {
return;
}
templateData = jQuery.extend( true, {}, control.params.sections[ type ].fields );
/**
* In case we added the row with "known" data, we need to overwrite the array
*/
if ( data ) {
for ( i in data ) {
if ( data.hasOwnProperty( i ) && templateData.hasOwnProperty( i ) ) {
templateData[ i ][ 'default' ] = data[ i ];
}
}
}
/**
* Add an index
*
* @type {number}
*/
templateData.index = control.currentIndex;
/**
* Render the HTML template with underscores
*/
template = template( templateData );
/**
* Initiate a new ROW
*
* @type {*}
*/
newSection = new EpsilonFramework.sectionRepeater.section.constructor(
control.currentIndex,
jQuery( template ).appendTo( control.repeaterContainer ),
control.params.sections[ type ].id,
control.params.sections[ type ].title,
control
);
/**
* 1. Remove row event
*/
newSection.container.on( 'section:remove', function( e, sectionIndex ) {
self.delete( this, sectionIndex, control );
} );
/**
* 2. Update row event
*/
newSection.container.on( 'section:update', function( e, sectionIndex, type, fieldName, element, control ) {
self.updateField.call( e, sectionIndex, type, fieldName, element, control );
self.updateLabel( newSection );
} );
/**
* Register the new row in the control
*
* @type {*}
*/
control.sections[ control.currentIndex ] = newSection;
/**
* Add a new "index" to the setting ( easier to render in the frontend )
*/
for ( i in templateData ) {
if ( templateData.hasOwnProperty( i ) ) {
newSectionSetting[ i ] = templateData[ i ][ 'default' ];
}
}
newSectionSetting.type = type;
/**
* Add a value to the setting
* @type {{}}
*/
settingValue[ control.currentIndex ] = newSectionSetting;
if ( ! data ) {
/**
* Set it
*/
self.setValue( control, settingValue );
}
/**
* Update index
*/
control.currentIndex ++;
/**
* Return constructor
*/
return newSection;
},
/**
* Handle the adding section button
*
* @private
*/
handleAddButton: function( context ) {
var isAddBtn,
self = this,
body = jQuery( 'body' );
/**
* Get a reference for the parent section, if we close it. we must close the Section sidebar as well
*/
wp.customize[ 'section' ]( context.params.section, function( instance ) {
instance.container.find( '.accordion-section-title, .customize-section-back' ).on( 'click keydown', function( event ) {
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
/**
* In case we left the "sections" screen, let's close all the repeatable sections
*/
_.each( context.sections, function( sect ) {
if ( ! sect.container.hasClass( 'minimized' ) ) {
self.toggleMinimize( sect );
}
} );
body.find( '.doubled-section-opened' ).removeClass( 'doubled-section-opened' );
} );
} );
context.container.find( '.epsilon-add-new-section' ).on( 'click keydown', function( e ) {
if ( jQuery( 'body' ).hasClass( 'adding-doubled-section' ) ) {
return;
}
isAddBtn = jQuery( e.target ).is( '.epsilon-add-new-section' );
body.toggleClass( 'adding-section' );
if ( body.hasClass( 'adding-section' ) && ! isAddBtn ) {
context.close();
}
} );
},
/**
* Set the value of the customizer option
*
* @param instance
* @param newValue
*/
setValue: function( instance, newValue ) {
instance.setting.set( [] );
instance.setting.set( newValue );
},
/**
* Get the value of the customizer option
*
* @param instance
*/
getValue: function( instance ) {
return instance.setting.get();
},
/**
* Update the label of the section
*
* @param section
* @param control
*/
updateLabel: function( section, control ) {
section.header.find( '.repeater-row-label' ).html( '#' + ( section.sectionIndex + 1 ) + ' - ' + section.label );
},
/**
* Update a single field inside a row.
* Triggered when a field has changed
*
* @param e Event Object
*/
updateField: function( sectionIndex, sectionType, fieldId, element, control ) {
var section,
currentSettings;
if ( ! control.sections[ sectionIndex ] ) {
return;
}
if ( ! control.params.sections[ sectionType ].fields[ fieldId ] ) {
return;
}
section = control.sections[ sectionIndex ];
currentSettings = EpsilonFramework.sectionRepeater.base.getValue( control );
element = jQuery( element );
if ( _.isUndefined( currentSettings[ section.sectionIndex ][ fieldId ] ) ) {
return;
}
switch ( control.params.sections[ sectionType ].fields[ fieldId ].type ) {
case 'checkbox':
case 'epsilon-toggle':
currentSettings[ section.sectionIndex ][ fieldId ] = element.prop( 'checked' );
break;
default:
currentSettings[ section.sectionIndex ][ fieldId ] = element.val();
break;
}
EpsilonFramework.sectionRepeater.base.setValue( control, currentSettings, true );
},
/**
* Remove a row from the instance
*
* @param instance
*/
removeSection: function( instance ) {
instance.container.slideUp( 300, function() {
jQuery( this ).detach();
} );
instance.container.trigger( 'section:remove', [ instance.sectionIndex ] );
},
/**
* Set section's index
*
* @param rowIndex
*/
setSectionIndex: function( sectionInstance, sectionIndex, control ) {
sectionInstance.sectionIndex = sectionIndex;
sectionInstance.container.attr( 'data-row', sectionIndex );
sectionInstance.container.data( 'row', sectionIndex );
EpsilonFramework.sectionRepeater.base.updateLabel( sectionInstance, control );
},
/**
* Drag and drop functionality
* @param control
*/
sort: function( control, data ) {
var sections = control.repeaterContainer.find( '.repeater-row' ),
settings = EpsilonFramework.sectionRepeater.base.getValue( control ),
newOrder = [],
newSections = [],
newSettings = [];
sections.each( function( i, element ) {
newOrder.push( jQuery( element ).data( 'row' ) );
} );
jQuery.each( newOrder, function( newPosition, oldPosition ) {
newSections[ newPosition ] = control.sections[ oldPosition ];
EpsilonFramework.sectionRepeater.base.setSectionIndex( newSections[ newPosition ], newPosition, control );
newSettings[ newPosition ] = settings[ oldPosition ];
} );
EpsilonFramework.sectionRepeater.base.reinitTexteditor( control, data.item );
control.sections = newSections;
EpsilonFramework.sectionRepeater.base.setValue( control, newSettings );
},
/**
* Handle image uploading in a repeater field
*
* @param instance
* @param container
*/
handleImageUpload: function( instance, container ) {
var self = this,
setting = {},
size,
temp,
input,
image = wp.media( {
multiple: false,
} ).open();
/**
* On selection, save the data in a JSON
*/
image.on( 'select', function() {
input = container.find( 'input' );
temp = image.state().get( 'selection' ).first();
size = input.attr( 'data-size' );
if ( 'undefined' === typeof (temp.toJSON().sizes[ size ]) ) {
size = 'full';
}
setting.id = temp.id;
setting.url = temp.toJSON().sizes[ size ].url;
self._setImage( container, setting.url );
input.attr( 'value', ( 'url' === input.attr( 'data-save-mode' ) ? setting.url : setting.id ) ).trigger( 'change' );
container.find( '.actions .image-upload-remove-button' ).show();
} );
},
/**
* Handle Image Removal in a repeater field
*
* @param instance
* @param container
*/
handleImageRemoval: function( instance, container ) {
var self = this,
setting = {},
thumb = container.find( '.epsilon-image' );
if ( thumb.length ) {
thumb.find( 'img' ).fadeOut( 200, function() {
thumb.removeClass( 'epsilon-image' ).addClass( 'placeholder' ).html( EpsilonTranslations.selectFile );
} );
}
container.find( '.actions .image-upload-remove-button' ).hide();
container.find( 'input' ).attr( 'value', '' ).trigger( 'change' );
},
/**
* Set image in the customizer option control
*
* @param control
* @param image
*
* @access private
*/
_setImage: function( container, image ) {
/**
* If we already have an image, we need to return that div, else we grab the placeholder
*
* @type {*}
*/
var thumb = container.find( '.epsilon-image' ).length ? container.find( '.epsilon-image' ) : container.find( '.placeholder' );
/**
* We "reload" the image container
*/
if ( thumb.length ) {
thumb.removeClass( 'epsilon-image placeholder' ).addClass( 'epsilon-image' );
thumb.html( '' );
thumb.append( '
' );
thumb.find( 'img' ).fadeIn( 200 );
}
},
/**
* Handle the icon picker field
*
* @param instance
* @param container
*/
handleIconPickerToggle: function( instance, container ) {
container.find( '.epsilon-icon-picker-container' ).toggleClass( 'opened' );
},
/**
* Handle the selection of the icon picker
*
* @param instance
* @param container
*/
handleIconPickerSelection: function( instance, clicked, container ) {
var icon, label;
container.find( '.epsilon-icons > i.selected' ).removeClass( 'selected' );
icon = jQuery( clicked ).addClass( 'selected' ).attr( 'data-icon' );
label = jQuery( clicked ).addClass( 'selected' ).attr( 'data-search' );
container.find( '.epsilon-icon-name > i' ).removeClass().addClass( icon );
container.find( '.epsilon-icon-name > .icon-label' ).html( label );
/**
* Set value
*/
container.find( '.epsilon-icon-picker' ).attr( 'value', icon ).trigger( 'change' );
},
/**
* Handle the Filtering of the icons
*
* @param instance
* @param input
* @param container
*/
handleIconPickerFiltering: function( instance, input, container ) {
var filter, temp,
collection = jQuery( container ).find( '.epsilon-icons > i' );
filter = jQuery( input ).val().toLowerCase();
jQuery.each( collection, function() {
temp = jQuery( this ).attr( 'data-search' ).toLowerCase();
jQuery( this )[ temp.indexOf( filter ) !== - 1 ? 'show' : 'hide' ]();
} );
},
/**
* Remove the editor so we can add it again
*
* @param instance
* @param container
*/
reinitTexteditor: function( instance, container ) {
var self = this,
textarea = container.find( 'textarea' ),
editorId;
jQuery.each( textarea, function() {
wp.editor.remove( jQuery( this ).attr( 'id' ) );
wp.editor.initialize( jQuery( this ).attr( 'id' ), {
tinymce: {
wpautop: true,
setup: function( editor ) {
editor.on( 'change', function( e ) {
editor.save();
jQuery( editor.getElement() ).trigger( 'change' );
} );
}
},
quicktags: true
} );
} );
},
/**
* Initiate the text editor in the repeater field
*
* @param instance
* @param container
*/
initTexteditor: function( instance, container ) {
var textarea = container.find( 'textarea' ),
editorId;
jQuery.each( textarea, function() {
editorId = jQuery( this ).attr( 'id' );
wp.editor.initialize( editorId, {
tinymce: {
wpautop: true,
setup: function( editor ) {
editor.on( 'change', function( e ) {
editor.save();
jQuery( editor.getElement() ).trigger( 'change' );
} );
}
},
quicktags: true
} );
} );
},
/**
* Toggle vizibility
*
* @param instance
*/
toggleMinimize: function( instance ) {
instance.container.find( '.repeater-row-content' ).slideToggle( 300, function() {
instance.container.toggleClass( 'minimized' );
instance.header.find( '.dashicons' ).toggleClass( 'dashicons-arrow-up' ).toggleClass( 'dashicons-arrow-down' );
jQuery('body').removeClass( 'adding-section' );
jQuery('body').removeClass( 'adding-doubled-section' );
jQuery.each( instance.container.siblings(), function( index, element ) {
if ( ! jQuery( element ).hasClass( 'minimized' ) ) {
jQuery( element ).addClass( 'minimized' );
jQuery( element ).find( '.repeater-row-content' ).slideToggle( 300, function() {
jQuery( element ).find( 'repeater-row-header' ).addClass( 'minimized' ).find( '.dashicons' ).toggleClass( 'dashicons-arrow-up' ).toggleClass( 'dashicons-arrow-down' );
} );
}
} );
} );
},
/**
* Cleans an array (undefined values), returns value
*
* @param actual
* @returns {Array}
*/
cleanArray: function( actual ) {
var newArray = [],
self = this;
for ( var i = 0; i < actual.length; i ++ ) {
if ( actual[ i ] ) {
newArray.push( actual[ i ] );
}
}
return newArray;
},
};
EpsilonFramework.sectionRepeater.section = {
/**
* Basic section constructor
*
* @param sectionIndex
* @param container
* @param label
* @param control
*/
constructor: function( sectionIndex, container, type, label, control ) {
var self = this;
this.sectionIndex = sectionIndex;
this.container = container;
this.label = label;
this.type = type;
this.header = this.container.find( '.repeater-row-header' );
/**
* Events
*/
this.header.on( 'click', function() {
EpsilonFramework.sectionRepeater.base.toggleMinimize( self );
} );
this.container.on( 'click', '.repeater-row-minimize', function() {
EpsilonFramework.sectionRepeater.base.toggleMinimize( self );
} );
this.container.on( 'keyup change', 'input, select, textarea', function( e ) {
self.container.trigger( 'section:update', [ self.sectionIndex, self.type, jQuery( e.target ).data( 'field' ), e.target, control ] );
} );
/**
* Remove event
*/
this.container.on( 'click', '.repeater-row-remove', function() {
EpsilonFramework.sectionRepeater.base.removeSection( self );
} );
EpsilonFramework.sectionRepeater.base.updateLabel( self, control );
},
};
/**
* Icon Picker Initiator
*
* @type {{init: EpsilonFramework.iconPickers.init}}
*/
EpsilonFramework.textEditor = {
init: function( selector ) {
var context = jQuery( selector ),
editorId = jQuery( context.find( 'textarea' ) ).attr( 'id' );
wp.editor.initialize( editorId, {
tinymce: {
wpautop: true,
setup: function( editor ) {
editor.on( 'change', function( e ) {
editor.save();
jQuery( editor.getElement() ).trigger( 'change' );
} );
}
},
quicktags: true
} );
}
};
/**
* Typography functions
*
* @type {{_selectize: null, _linkedFonts: {}, init: EpsilonFramework.typography.init, _resetDefault: EpsilonFramework.typography._resetDefault, _parseJson:
* EpsilonFramework.typography._parseJson}}
*/
EpsilonFramework.typography = {
/**
* Selectize instance
*/
_selectize: null,
/**
* K/V Pair
*/
_linkedFonts: {},
/**
* Initiate function
*/
init: function( control ) {
var self = this,
sliders,
container = control.container.find( '.epsilon-typography-container' ),
uniqueId = container.attr( 'data-unique-id' ),
selects = container.find( 'select' ),
inputs = container.find( '.epsilon-typography-input' );
/**
* Instantiate the selectize javascript plugin
* and the input type number
*/
try {
self._selectize = selects.selectize();
}
catch ( err ) {
/**
* In case the selectize plugin is not loaded, raise an error
*/
console.warn( 'selectize not yet loaded' );
}
/**
* On triggering the change event, create a json with the values and
* send it to the preview window
*/
inputs.on( 'change', function() {
var val = EpsilonFramework.typography._parseJson( inputs, uniqueId, control );
jQuery( '#hidden_input_' + uniqueId ).val( val ).trigger( 'change' );
} );
/**
* On clicking the advanced options toggler,
*/
container.find( '.epsilon-typography-advanced-options-toggler' ).on( 'click', function( e ) {
var toggle = jQuery( this ).attr( 'data-toggle' );
e.preventDefault();
jQuery( this ).toggleClass( 'active' ).parent().toggleClass( 'active' );
jQuery( '#' + toggle ).slideToggle().addClass( 'active' );
} );
/**
* Great use of the EpsilonFramework, ahoy!
*/
sliders = jQuery( '.epsilon-typography-container' ).find( '.slider-container' );
jQuery.each( sliders, function() {
EpsilonFramework.rangeSliders.init( this );
} );
/**
* Reset button
*/
jQuery( '.epsilon-typography-default' ).on( 'click', function( e ) {
e.preventDefault();
EpsilonFramework.typography._resetDefault( jQuery( this ) );
} );
},
/**
* Reset defaults
*
* @param element
* @private
*/
_resetDefault: function( element ) {
var container = jQuery( element ).parent(),
uniqueId = container.attr( 'data-unique-id' ),
selects = container.find( 'select' ),
inputs = container.find( 'inputs' ),
val,
control = wp.customize.control( uniqueId );
var fontFamily = selects[ 0 ].selectize;
var object = {
'action': 'epsilon_generate_typography_css',
'class': 'Epsilon_Typography',
'id': uniqueId,
'data': {
'selectors': control.params.selectors,
'stylesheet': control.params.stylesheet,
'json': {}
}
},
api = wp.customize;
fontFamily.setValue( 'default_font' );
if ( jQuery( '#' + uniqueId + '-font-size' ).length ) {
val = jQuery( '#' + uniqueId + '-font-size' ).
attr( 'data-default-font-size' );
jQuery( '#' + uniqueId + '-font-size' ).
val( val ).
trigger( 'change' ).
trigger( 'blur' );
object.data.json[ 'font-size' ] = '';
}
if ( jQuery( '#' + uniqueId + '-line-height' ).length ) {
val = jQuery( '#' + uniqueId + '-line-height' ).
attr( 'data-default-line-height' );
jQuery( '#' + uniqueId + '-line-height' ).
val( val ).
trigger( 'change' ).
trigger( 'blur' );
object.data.json[ 'line-height' ] = '';
}
if ( jQuery( '#' + uniqueId + '-letter-spacing' ).length ) {
val = jQuery( '#' + uniqueId + '-letter-spacing' ).
attr( 'data-default-letter-spacing' );
jQuery( '#' + uniqueId + '-letter-spacing' ).
val( val ).
trigger( 'change' ).
trigger( 'blur' );
object.data.json[ 'letter-spacing' ] = '';
}
object.data.json[ 'font-family' ] = 'default_font';
object.data.json[ 'font-weight' ] = '';
object.data.json[ 'font-style' ] = '';
api.previewer.send( 'update-inline-typography-css', object );
},
/**
* Parse/create the json and send it to the preview window
*
* @param inputs
* @param id
* @private
*/
_parseJson: function( inputs, id, control ) {
var object = {
'action': 'epsilon_generate_typography_css',
'class': 'Epsilon_Typography',
'id': id,
'data': {
'selectors': control.params.selectors,
'stylesheet': control.params.stylesheet,
'json': {}
}
},
api = wp.customize;
jQuery.each( inputs, function( index, value ) {
var key = jQuery( value ).attr( 'id' ),
replace = id + '-',
type = jQuery( this ).attr( 'type' );
key = key.replace( replace, '' );
if ( 'checkbox' === type ) {
object.data.json[ key ] = jQuery( this ).prop( 'checked' ) ? jQuery( value ).val() : '';
} else {
object.data.json[ key ] = jQuery( value ).val();
}
} );
api.previewer.send( 'update-inline-typography-css', object );
return JSON.stringify( object.data );
}
};
/**
* Recommended action section scripting
*
* @type {{_init: _init, dismissActions: dismissActions, dismissPlugins:
* dismissPlugins}}
*/
/*jshint -W065 */
EpsilonFramework.recommendedActions = {
/**
* Initiate the click actions
*/
init: function() {
var context = jQuery( '.control-section-epsilon-section-recommended-actions' ),
dismissPlugin = context.find( '.epsilon-recommended-plugin-button' ),
dismissAction = context.find( '.epsilon-dismiss-required-action' );
/**
* Dismiss actions
*/
this.dismissActions( dismissAction );
/**
* Dismiss plugins
*/
this.dismissPlugins( dismissPlugin );
jQuery( '.epsilon-close-recommended-section' ).on( 'click', function( e ) {
e.preventDefault();
jQuery( this ).find( 'span' ).toggleClass( 'dashicons-arrow-down-alt2' );
jQuery( '.recommended-actions_container' ).slideToggle( 200 );
} );
jQuery( document ).on( 'epsilon-plugin-activated', function( event, data ) {
var container = jQuery( 'span#' + data.plugin ).parents( '.epsilon-recommended-plugins' ),
next = container.next();
container.fadeOut( '200', function() {
next.css( { opacity: 1, height: 'initial' } ).fadeIn( '200' );
} );
} );
},
/**
* Dismiss actions function, hides the container and shows the next one
* while changing the INDEX in the title
* @param selectors
*/
dismissActions: function( selectors ) {
selectors.on( 'click', function() {
/**
* During ajax, we lose scope - so declare "self"
* @type {*}
*/
var self = jQuery( this ),
/**
* Get the container
*/
container = self.parents(
'.epsilon-recommended-actions-container' ),
/**
* Get the current index
*
* @type {Number}
*/
index = parseInt( container.attr( 'data-index' ) ),
/**
* Get the title
*
* @type {*}
*/
title = container.parents(
'.control-section-epsilon-section-recommended-actions' ).
find( 'h3' ),
/**
* Get the indew from the notice
*
* @type {*}
*/
notice = title.find( '.epsilon-actions-count > .current-index' ),
/**
* Get the total
*
* @type {Number}
*/
total = parseInt( notice.attr( 'data-total' ) ),
/**
* Get the next element ( this will be shown next )
*/
next = container.next(),
/**
* Create the args object for the AJAX call
*
* action [ Class, Method Name ]
* args [ parameters to be sent to method ]
*
* @type {{action: [*], args: {id: *, option: *}}}
*/
args = {
'action': [ 'Epsilon_Notify_System', 'dismiss_required_action' ],
'nonce': EpsilonWPUrls.ajax_nonce,
'args': {
'id': jQuery( this ).attr( 'id' ),
'option': jQuery( this ).attr( 'data-option' )
}
},
replace, plugins, replaceText;
/**
* Initiate the AJAX function
*
* Note that the Epsilon_Framework class, has the following method :
*
* public function epsilon_framework_ajax_action(){};
*
* which is used as a proxy to gather jQuery_POST data, verify it
* and call the needed function, in this case :
* Epsilon_Framework::dismiss_required_action()
*
*/
jQuery.ajax( {
type: 'POST',
data: { action: 'epsilon_framework_ajax_action', args: args },
dataType: 'json',
url: ajaxurl,
success: function( data ) {
/**
* In case everything is ok, we start changing things
*/
if ( data.status && 'ok' === data.message ) {
/**
* If it's the last element, show plugins
*/
if ( total <= index ) {
replace = title.find( '.section-title' );
plugins = jQuery( '.epsilon-recommended-plugins' );
replaceText = replace.attr( 'data-social' );
if ( plugins.length ) {
replaceText = replace.attr( 'data-plugin_text' );
}
title.find( '.epsilon-actions-count' ).remove();
replace.text( replaceText );
}
/**
* Else, just change the index
*/
else {
notice.text( index + 1 );
}
/**
* Fade the current element and show the next one.
* We don't need to remove it at this time. Leave it to for
* server side
*/
container.fadeOut( '200', function() {
next.css( { opacity: 1, height: 'initial' } ).fadeIn( '200' );
} );
}
},
/**
* Throw errors
*
* @param jqXHR
* @param textStatus
* @param errorThrown
*/
error: function( jqXHR, textStatus, errorThrown ) {
console.log( jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown );
}
} );
} );
},
/**
* Dismiss plugins function, hides the container and shows the next one
* while changing the INDEX in the title
* @param selectors
*/
dismissPlugins: function( selectors ) {
selectors.on( 'click', function() {
/**
* During ajax, we lose scope - so declare "self"
* @type {*}
*/
var self = jQuery( this ),
/**
* Get the container
*/
container = self.parents( '.epsilon-recommended-plugins' ),
/**
* Get the next element (this will be shown next)
*/
next = container.next(),
/**
* Get the title
*
* @type {*}
*/
title = container.parents(
'.control-section-epsilon-section-recommended-actions' ).
find( 'h3' ),
/**
* Create the args object for the AJAX call
*
* action [ Class, Method Name ]
* args [ parameters to be sent to method ]
*
* @type {{action: [*], args: {id: *, option: *}}}
*/
args = {
'action': [ 'Epsilon_Notify_System', 'dismiss_required_action' ],
'nonce': EpsilonWPUrls.ajax_nonce,
'args': {
'id': jQuery( this ).attr( 'id' ),
'option': jQuery( this ).attr( 'data-option' )
}
},
replace, replaceText;
jQuery.ajax( {
type: 'POST',
data: { action: 'epsilon_framework_ajax_action', args: args },
dataType: 'json',
url: ajaxurl,
success: function( data ) {
/**
* In case everything is ok, we start changing things
*/
if ( data.status && 'ok' === data.message ) {
/**
* Fade the current element and show the next one.
* We don't need to remove it at this time. Leave it to for
* server side
*/
container.fadeOut( '200', function() {
if ( next.is( 'p' ) ) {
replace = title.find( '.section-title' );
replaceText = replace.attr( 'data-social' );
replace.text( replaceText );
}
next.css( { opacity: 1, height: 'initial' } ).fadeIn( '200' );
} );
}
},
/**
* Throw errors
*
* @param jqXHR
* @param textStatus
* @param errorThrown
*/
error: function( jqXHR, textStatus, errorThrown ) {
console.log( jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown );
}
} );
} );
}
};
/**
* Doubled section
*
*
*/
/*jshint -W065 */
EpsilonFramework.sectionDoubled = {
/**
* Section instance
*/
section: null,
/**
* Parent container
*/
parent: null,
/**
* Initiator
*
* @param selector
*/
init: function( section ) {
/**
* save instance of section
*/
this.section = section;
/**
* Move out of the ugly list, this has overflow hidden and we can`t display it properly
*/
this.createParent();
/**
* Append new sections to parent
*/
section.container.appendTo( this.parent );
/**
* Handle events
*/
this.handleEvents();
},
/**
* Create a parent container
*/
createParent: function() {
var parent = jQuery( '.wp-full-overlay' ).find( '.doubled-section-parent' );
if ( ! parent.length ) {
jQuery( '.wp-full-overlay' ).append( '' );
parent = jQuery( '.wp-full-overlay' ).find( '.doubled-section-parent' );
this.parent = parent;
}
this.parent = parent;
},
/**
* Event Handlers
*
* @param section
*/
handleEvents: function() {
var section = this.section,
self = this;
/**
* Close sections
*/
this.section.container.on( 'click', '.epsilon-close-doubled-section', function( e ) {
e.preventDefault();
jQuery( 'body' ).removeClass( 'adding-doubled-section' );
jQuery( 'body' ).find( '.doubled-section-opened' ).removeClass( 'doubled-section-opened' );
} );
/**
* Open sections
*/
this.section.headContainer.on( 'click', function( e ) {
var opened,
strippedIdHead,
strippedIdContainer;
e.preventDefault();
if ( jQuery( 'body' ).hasClass( 'adding-section' ) ) {
return;
}
/**
* We need to close everything on click
* @type {*|{}}
*/
opened = self.parent.find( '.doubled-section-opened' );
if ( opened.length ) {
opened.removeClass( 'doubled-section-opened' );
}
if ( jQuery( 'body' ).hasClass( 'adding-doubled-section' ) ) {
strippedIdHead = jQuery( this ).attr( 'id' ).replace( 'accordion-section-', '' );
strippedIdContainer = opened.attr( 'id' ).replace( 'sub-accordion-section-', '' );
if ( strippedIdContainer === strippedIdHead ) {
jQuery( 'body' ).removeClass( 'adding-doubled-section' );
}
} else {
jQuery( 'body' ).toggleClass( 'adding-doubled-section' );
}
jQuery.each( section.container, function( e ) {
if ( jQuery( this ).is( 'li' ) ) {
return;
}
jQuery( this ).addClass( 'doubled-section-opened' );
} );
} );
}
};
/**
* Epsilon Color Picker Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-color-picker' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.colorPickers.init( this.container );
control.container.on( 'change', 'input.epsilon-color-picker',
function() {
control.setting.set( jQuery( this ).val() );
}
);
}
} );
/**
* Epsilon Color Schemes Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-color-scheme' ] = wp.customize.Control.extend( {
ready: function() {
var control = this, section, instance;
jQuery( this.container ).find( '.epsilon-color-scheme-input' ).on( 'change', function() {
control.setting.set( jQuery( this ).val() );
} );
}
} );
/**
* Epsilon Customizer Navigation Constructor
*/
wp.customize.controlConstructor[ 'epsilon-customizer-navigation' ] = wp.customize.Control.extend( {
ready: function() {
EpsilonFramework.customizerNavigation.init( this.container );
}
} );
/**
* Epsilon Icon Picker Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-icon-picker' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.iconPickers.init( control, false );
control.container.on( 'change', 'input.epsilon-icon-picker',
function() {
control.setting.set( jQuery( this ).val() );
}
);
}
} );
/**
* Epsilon Image Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-image' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.image.init( this );
}
} );
/**
* Epsilon Layouts Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-layouts' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.layouts.init( this.container );
/**
* Save the layout
*/
jQuery( this.container ).find( 'input' ).on( 'change', function() {
control.setting.set( jQuery( this ).val() );
} );
}
} );
/**
* Epsilon Range Slider Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-slider' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.rangeSliders.init( this.container );
control.container.on( 'change', 'input.rl-slider',
function() {
control.setting.set( jQuery( this ).val() );
}
);
}
} );
/**
* Epsilon Repeater Field Constructor
*/
wp.customize.controlConstructor[ 'epsilon-repeater' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
this.initRepeater();
},
/**
* Initiator
*/
initRepeater: function() {
var control = this,
newRow;
/**
* Setting field reference
*/
this.settingField = this.container.find( '[data-customize-setting-link]' ).first();
/**
* Create a reference of the container
*/
this.repeaterContainer = this.container.find( '.repeater-fields' ).first();
/**
* Start incrementing an index
*
* @type {number}
*/
this.currentIndex = 0;
/**
* Start saving rows
* @type {Array}
*/
this.rows = [];
/**
* Initiate the adding/removing events
*/
this.handleEvents();
/**
* Initiate Custom Controls
*/
this.initIconPicker();
this.initImageControls();
/**
* Create the existing rows
*/
this.createExistingRows();
/**
* Start sorting
*/
this.initSortable();
},
/**
* Create existing rows
*/
createExistingRows: function() {
var control = this,
newRow;
if ( this.params.value.length ) {
_.each( this.params.value, function( subValue ) {
newRow = EpsilonFramework.repeater.base.add( control, subValue );
/**
* init range sliders, color pickers
*/
EpsilonFramework.rangeSliders.init( newRow.container );
EpsilonFramework.colorPickers.init( newRow.container );
EpsilonFramework.repeater.base.initTexteditor( newRow.container );
} );
}
},
/**
* Init events
*/
handleEvents: function() {
var control = this,
limit = false,
newRow;
/**
* Setup Limit
*
* @type {boolean}
*/
if ( ! _.isUndefined( this.params.choices.limit ) ) {
limit = ( 0 >= this.params.choices.limit ) ? false : parseInt( this.params.choices.limit );
}
/**
* Bind events for adding and removing
*
* 1. Click event on the ADD Row button
*/
this.container.on( 'click', 'button.epsilon-repeater-add', function( e ) {
e.preventDefault();
if ( ! limit || control.currentIndex < limit ) {
newRow = EpsilonFramework.repeater.base.add( control );
/**
* init range sliders, color pickers
*/
EpsilonFramework.rangeSliders.init( newRow.container );
EpsilonFramework.colorPickers.init( newRow.container );
EpsilonFramework.repeater.base.initTexteditor( newRow.container );
} else {
jQuery( control.selector + ' .limit' ).addClass( 'highlight' );
}
} );
/**
* 2. REMOVE Row button
*/
this.container.on( 'click', '.repeater-row-remove', function() {
control.currentIndex --;
if ( ! limit || control.currentIndex < limit ) {
jQuery( control.selector + ' .limit' ).removeClass( 'highlight' );
}
} );
},
/**
* Init the image controls (adding removing)
*/
initImageControls: function() {
var control = this,
temp;
/**
* Image controls - Upload
*/
this.container.on( 'click keypress', '.epsilon-controller-image-container .image-upload-button', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-controller-image-container' );
EpsilonFramework.repeater.base.handleImageUpload( control, temp );
} );
/**
* Image Controls - Removal
*/
this.container.on( 'click keypress', '.epsilon-controller-image-container .image-upload-remove-button', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-controller-image-container' );
EpsilonFramework.repeater.base.handleImageRemoval( control, temp );
} );
},
/**
* Initiate sortable functionality
*/
initSortable: function() {
var control = this;
this.repeaterContainer.sortable( {
handle: '.repeater-row-header',
axis: 'y',
distance: 15,
update: function( e, data ) {
EpsilonFramework.repeater.base.sort( control, data );
}
} );
},
/**
* Init icon pickers
*/
initIconPicker: function() {
var control = this, temp, filter, input;
this.container.on( 'click keypress', '.epsilon-icon-picker-repeater-container .epsilon-open-icon-picker', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
jQuery( this ).toggleClass( 'opened-icon-picker' );
temp = jQuery( this ).parents( '.epsilon-icon-picker-repeater-container' );
EpsilonFramework.repeater.base.handleIconPickerToggle( control, temp );
} );
this.container.on( 'click keypress', '.epsilon-icon-picker-repeater-container .epsilon-icons-container .epsilon-icons > i', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-icon-picker-repeater-container' );
EpsilonFramework.repeater.base.handleIconPickerSelection( control, this, temp );
} );
this.container.on( 'keyup change', '.epsilon-icon-picker-repeater-container .search-container input', _.debounce( function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-icon-picker-repeater-container' );
EpsilonFramework.repeater.base.handleIconPickerFiltering( control, this, temp );
}, 1000 ) );
}
} );
/**
* Epsilon Section Repeater Constructor
*/
wp.customize.controlConstructor[ 'epsilon-section-repeater' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
/**
* We need to move this element to the bottom of the page so it renders properly
*/
jQuery( '#sections-left-' + this.params.id ).appendTo( jQuery( '.wp-full-overlay' ) );
/**
* Initiate search functionality
*/
this.initSearch( this, jQuery( '#sections-left-' + this.params.id ) );
/**
* Get a reference to the setting field
*/
this.settingField = this.container.find( '[data-customize-setting-link]' ).first();
/**
* Repeater container reference
*/
this.repeaterContainer = this.container.find( '.repeater-sections' ).first();
/**
* Start incrementing sections
*
* @type {number}
*/
this.currentIndex = 0;
/**
* Start saving rows
* @type {Array}
*/
this.sections = [];
/**
* Initiate the adding/removing events
*/
this.handleEvents();
/**
* Icon Picker Events
*/
this.initIconPicker();
this.initImageControls();
/**
* Create existing sections
*/
this.createExistingSections();
/**
* Start sorting
*/
if ( this.params.sortable ) {
this.initSortable();
}
/**
* Event that fires from the main page
* so we can focus our panel and repeatable section
*/
wp.customize.previewer.bind( 'epsilon-section-edit', function( data ) {
/**
* In case the section does not exist, we can terminate
*/
if ( 'undefined' === typeof( wp.customize.section( data.customizerSection ) ) ) {
return false;
}
/**
* Iterate over the controls, minimize everything
*/
_.each( control.sections, function( sect, index ) {
if ( ! sect.container.hasClass( 'minimized' ) && index !== data.section ) {
EpsilonFramework.sectionRepeater.base.toggleMinimize( sect );
}
} );
wp.customize.section( data.customizerSection ).focus();
/**
* Focus repeatable section
*/
if ( ! _.isUndefined( control.sections[ data.section ] ) && control.sections[ data.section ].container.hasClass( 'minimized' ) ) {
EpsilonFramework.sectionRepeater.base.toggleMinimize( control.sections[ data.section ] );
}
} );
},
/**
* Handle Addition/Removal of sections
*/
handleEvents: function() {
var control = this,
newSection,
limit = false;
/**
* Add new repeater section handler
*/
EpsilonFramework.sectionRepeater.base.handleAddButton( this );
/**
* Setup Limit
*
* @type {boolean}
*/
if ( ! _.isUndefined( this.params.choices.limit ) ) {
limit = ( 0 >= this.params.choices.limit ) ? false : parseInt( this.params.choices.limit );
}
/**
* Addition of sections
*/
jQuery( '#sections-left-' + this.params.id ).on( 'click', '.epsilon-section', function( e ) {
e.preventDefault();
if ( ! limit || control.currentIndex < limit ) {
newSection = EpsilonFramework.sectionRepeater.base.add( control, jQuery( this ).attr( 'data-id' ) );
jQuery( 'body' ).removeClass( 'adding-section' );
/**
* init range sliders, color pickers
*/
EpsilonFramework.rangeSliders.init( newSection.container );
EpsilonFramework.colorPickers.init( newSection.container );
EpsilonFramework.customizerNavigation.init( newSection.container );
EpsilonFramework.sectionRepeater.base.initTexteditor( control, newSection.container );
newSection.container.find( '.epsilon-selectize' ).selectize( {
plugins: [ 'remove_button' ],
} );
} else {
jQuery( control.selector + ' .limit' ).addClass( 'highlight' );
}
} );
},
/**
* Create existing sections
*/
createExistingSections: function() {
var control = this, newSection;
if ( this.params.value.length ) {
/**
* If we have saved rows, we need to display them
*/
_.each( this.params.value, function( subValue ) {
newSection = EpsilonFramework.sectionRepeater.base.add( control, subValue[ 'type' ], subValue );
if ( 'undefined' !== typeof newSection ) {
EpsilonFramework.rangeSliders.init( newSection.container );
EpsilonFramework.colorPickers.init( newSection.container );
EpsilonFramework.customizerNavigation.init( newSection.container );
EpsilonFramework.sectionRepeater.base.initTexteditor( control, newSection.container );
newSection.container.find( '.epsilon-selectize' ).selectize( {
plugins: [ 'remove_button' ],
} );
}
} );
}
},
/**
* Initiate sortable functionality
*/
initSortable: function() {
var control = this;
this.repeaterContainer.sortable( {
handle: '.repeater-row-header',
axis: 'y',
distance: 15,
update: function( e, data ) {
EpsilonFramework.sectionRepeater.base.sort( control, data );
}
} );
},
/**
* Initiate Image Controls (Upload/Remove)
*/
initImageControls: function() {
var control = this, temp;
/**
* Image controls - Upload
*/
this.container.on( 'click keypress', '.epsilon-controller-image-container .image-upload-button', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-controller-image-container' );
EpsilonFramework.sectionRepeater.base.handleImageUpload( control, temp );
} );
/**
* Image Controls - Removal
*/
this.container.on( 'click keypress', '.epsilon-controller-image-container .image-upload-remove-button', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-controller-image-container' );
EpsilonFramework.sectionRepeater.base.handleImageRemoval( control, temp );
} );
},
/**
* Search functionality in the sections library
*
* @param selector
*/
initSearch: function( instance, selector ) {
var input = selector.find( '.sections-search-input' ),
val, collection, id,
self = this;
input.on( 'keyup change', _.debounce( function( e ) {
val = input.val().toLowerCase();
collection = selector.find( '.epsilon-section' );
jQuery.each( collection, function() {
id = jQuery( this ).attr( 'data-id' ).toLowerCase();
jQuery( this )[ id.indexOf( val ) !== - 1 ? 'show' : 'hide' ]();
} );
}, 1000 ) );
},
/**
* Icon Picker Functionality
*/
initIconPicker: function() {
var control = this, temp, filter, input;
this.container.on( 'click keypress', '.epsilon-icon-picker-repeater-container .epsilon-open-icon-picker', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
jQuery( this ).toggleClass( 'opened-icon-picker' );
temp = jQuery( this ).parents( '.epsilon-icon-picker-repeater-container' );
EpsilonFramework.sectionRepeater.base.handleIconPickerToggle( control, temp );
} );
this.container.on( 'click keypress', '.epsilon-icon-picker-repeater-container .epsilon-icons-container .epsilon-icons > i', function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-icon-picker-repeater-container' );
EpsilonFramework.sectionRepeater.base.handleIconPickerSelection( control, this, temp );
} );
this.container.on( 'keyup change', '.epsilon-icon-picker-repeater-container .search-container input', _.debounce( function( e ) {
e.preventDefault();
if ( wp.customize.utils.isKeydownButNotEnterEvent( e ) ) {
return;
}
temp = jQuery( this ).parents( '.epsilon-icon-picker-repeater-container' );
EpsilonFramework.sectionRepeater.base.handleIconPickerFiltering( control, this, temp );
}, 1000 ) );
}
} );
/**
* Epsilon Text Editor Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-text-editor' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.textEditor.init( this.container );
control.container.on( 'change keyup', 'textarea', function() {
control.setting.set( jQuery( this ).val() );
} );
}
} );
/**
* Epsilon Toggle Constructor
*/
wp.customize.controlConstructor[ 'epsilon-toggle' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
control.container.on( 'change', 'input.onoffswitch-checkbox',
function() {
control.setting.set( jQuery( this ).prop( 'checked' ) );
}
);
}
} );
/**
* Epsilon Typography Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-typography' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
EpsilonFramework.typography.init( this );
/**
* Save the typography
*/
jQuery( this.container ).find( '.customize-control-content > .epsilon-typography-input' ).on( 'change', function() {
control.setting.set( jQuery( this ).val() );
} );
}
} );
/**
* Epsilon Upsell Control Constructor
*/
wp.customize.controlConstructor[ 'epsilon-upsell' ] = wp.customize.Control.extend( {
ready: function() {
var control = this;
control.container.on( 'click', '.epsilon-upsell-label', function( e ) {
e.preventDefault();
jQuery( this ).toggleClass( 'opened' ).find('i').toggleClass('dashicons-arrow-down-alt2 dashicons-arrow-up-alt2');
control.container.find( '.epsilon-upsell-container' ).slideToggle( 200 );
} );
}
} );
/**
* Nestable Regular Panels Constructor
*/
wp.customize.panelConstructor[ 'epsilon-panel-regular' ] = wp.customize.Panel.extend( {
/**
* Embed Panel
*/
_panelEmbed: wp.customize.Panel.prototype.embed,
/**
* Check if is contextually active
*/
_panelIsContextuallyActive: wp.customize.Panel.prototype.isContextuallyActive,
/**
* Attach Events
*/
_panelAttachEvents: wp.customize.Panel.prototype.attachEvents,
/**
* Ready event
*/
ready: function() {
/**
* Hide the panel
*/
if ( this.params.hidden ) {
this.container.addClass( 'epsilon-hidden' );
}
wp.customize.bind( 'pane-contents-reflowed', function() {
// Reflow panels
var panels = [];
wp.customize.panel.each( function( panel ) {
if ( 'epsilon-panel-regular' !== panel.params.type || 'undefined' === typeof panel.params.panel ) {
return;
}
panels.push( panel );
} );
panels.sort( wp.customize.utils.prioritySort ).reverse();
jQuery.each( panels, function( i, panel ) {
var parentContainer = jQuery( '#sub-accordion-panel-' + panel.params.panel );
parentContainer.children( '.panel-meta' ).after( panel.headContainer );
} );
jQuery( document ).trigger( 'epsilon-reflown-panels' );
} );
},
/**
* Attach events
*/
attachEvents: function() {
var panel = this;
if ( 'epsilon-panel-regular' !== this.params.type || 'undefined' === typeof this.params.panel ) {
this._panelAttachEvents.call( this );
return;
}
this._panelAttachEvents.call( this );
panel.expanded.bind( function( expanded ) {
var parent = wp.customize.panel( panel.params.panel );
if ( expanded ) {
parent.contentContainer.addClass( 'current-panel-parent' );
} else {
parent.contentContainer.removeClass( 'current-panel-parent' );
}
} );
panel.container.find( '.customize-panel-back' ).off( 'click keydown' ).on( 'click keydown', function( event ) {
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
event.preventDefault();
if ( panel.expanded() ) {
wp.customize.panel( panel.params.panel ).expand();
}
} );
},
/**
* Is contextually active
* @returns {*}
*/
isContextuallyActive: function() {
var panel = this,
children = this._children( 'panel', 'section' ),
activeCount = 0;
if ( 'epsilon-panel-regular' !== this.params.type ) {
return this._panelIsContextuallyActive.call( this );
}
wp.customize.panel.each( function( child ) {
if ( ! child.params.panel ) {
return;
}
if ( child.params.panel !== panel.id ) {
return;
}
children.push( child );
} );
children.sort( wp.customize.utils.prioritySort );
_( children ).each( function( child ) {
if ( child.active() && child.isContextuallyActive() ) {
activeCount += 1;
}
} );
return ( 0 !== activeCount );
},
/**
* Embed
*/
embed: function() {
var panel = this,
parentContainer = jQuery( '#sub-accordion-panel-' + this.params.panel );
if ( 'epsilon-panel-regular' !== this.params.type || 'undefined' === typeof this.params.panel ) {
this._panelEmbed.call( this );
return;
}
this._panelEmbed.call( this );
parentContainer.append( panel.headContainer );
},
} );
/**
* Recommended Section Constructor
*/
wp.customize.sectionConstructor[ 'epsilon-section-recommended-actions' ] = wp.customize.Section.extend( {
ready: function() {
EpsilonFramework.recommendedActions.init();
},
attachEvents: function() {
},
isContextuallyActive: function() {
return true;
}
} );
/**
* Doubled Section Constructor
*/
wp.customize.sectionConstructor[ 'epsilon-section-doubled' ] = wp.customize.Section.extend( {
ready: function() {
EpsilonFramework.sectionDoubled.init( this );
},
attachEvents: function() {
},
isContextuallyActive: function() {
return true;
}
} );
/**
* Pro Section Constructor
*/
wp.customize.sectionConstructor[ 'epsilon-section-pro' ] = wp.customize.Section.extend( {
attachEvents: function() {
},
isContextuallyActive: function() {
return true;
}
} );
/**
* Epsilon Framework Initiator
*/
/**
* Load the range sliders for the widget updates
*/
jQuery( document ).on( 'widget-updated widget-added', function( a, selector ) {
if ( jQuery().slider ) {
EpsilonFramework.rangeSliders.init( selector );
}
} );
wp.customize.bind( 'ready', function() {
EpsilonFramework.colorSchemes.init();
} );