wp.customize.controlConstructor['css_tool'] = wp.customize.kirkiDynamicControl.extend({
// When we're finished loading continue processing.
initKirkiControl: function() {
'use strict';
var control = this;
// Save the value
console.log('u fut ktu');
control.container.on( 'input keyup', 'input', function(e) {
console.log('modify');
var value = ( _.isObject( control.setting.get() ) ? control.setting.get() : JSON.parse( control.setting.get() ) ),
el = jQuery(this).data('name'),
new_value = jQuery(this).val();
if ( false === kirki.util.validate.cssValue( new_value ) && new_value != '' ) {
jQuery(this).addClass('invalid');
return;
}else{
if(!_.isObject(value))
value = {};
value = Object.assign({},value);
jQuery(this).removeClass('invalid')
value[el] = new_value;
// Update the value in the customizer.
control.setting.set( JSON.stringify(value) );
}
});
}
});
wp.customize.controlConstructor['grouptitle'] = wp.customize.kirkiDynamicControl.extend({});
wp.customize.controlConstructor['groupdivider'] = wp.customize.kirkiDynamicControl.extend({});
wp.customize.controlConstructor['clelement'] = wp.customize.Control.extend({
ready: function() {
'use strict';
var control = this,
limit;
this.element_values = {};
//this.element_id = this.container.data('id');
this.selects = [];
this.active.set(false);
// The DIV that holds all the rows
this.elementsFieldsContainer = this.container.find( '.fields' ).first();
// Set number of rows to 0
this.currentIndex = 0;
// Default limit choice
limit = false;
if ( undefined !== this.params.choices.limit ) {
limit = ( 0 >= this.params.choices.limit ) ? false : parseInt( this.params.choices.limit );
}
this.buildDependeciens();
this.container.on( 'click keypress', '.element-field-image .image-upload-button,.element-field-cropped_image .iamge-upload-button,.element-field-upload .image-upload-button', function( e ) {
e.preventDefault();
control.$thisButton = jQuery( this );
control.openFrame( e );
});
this.container.on( 'click keypress', '.element-field-image .image-upload-remove-button,.element-field-cropped_image .image-upload-remove-button', function( e ) {
e.preventDefault();
control.$thisButton = jQuery( this );
control.removeImage( e );
});
this.container.on( 'click keypress', '.element-field-upload .image-upload-remove-button', function( e ) {
e.preventDefault();
control.$thisButton = jQuery( this );
control.removeFile( e );
});
/**/
/*this.container.on('mousemove', 'input[type=range]', function(e) {
});*/
/*this.container.on('focusout', 'input[type="text"]', function(e){
control.setting.previewer.send('cl_focusout', 'cl_header_menu-1');
});*/
/**
* Function that loads the Mustache template
*/
this.elementTemplate = _.memoize( function( element_id ) {
var compiled,
/*
* Underscore's default ERB-style templates are incompatible with PHP
* when asp_tags is enabled, so WordPress uses Mustache-inspired templating syntax.
*
* @see trac ticket #22344.
*/
options = {
evaluate: /<#([\s\S]+?)#>/g,
interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
escape: /\{\{([^\}]+?)\}\}(?!\})/g,
variable: 'data'
};
return function( data ) {
compiled = _.template( jQuery( '#tmpl-'+element_id ).first().html(), null, options );
return compiled( data );
};
});
// When we load the control, the fields have not been filled up
// This is the first time that we create all the rows
//this.createEl();
},
galleryReady: function(id){
var control = this;
// Shortcut so that we don't have to use _.bind every time we add a callback.
_.bindAll( control, 'galleryOpenFrame', 'gallerySelect' );
/**
* Set gallery data and render content.
*/
// Ensure attachment data is initially set.
control.setGalleryDataAndRenderContent(id);
// Bind events.
control.container.on( 'click keydown', '.image-upload-button', control.galleryOpenFrame );
},
setGalleryDataAndRenderContent: function(id) {
var control = this;
var value = control.getValue();
if( !_.isUndefined(value[id]) && value[id].length ){
value = JSON.parse( value[id].replace('__array__', '[').replace('__array__end__', ']') );
}else
value = [];
control.openedGallery = id;
control.gallerySetAttachmentsData( value ).done( function() {
control.galleryRenderAttachments();
control.gallerySetupSortable();
} );
},
galleryRenderAttachments: function(){
var inner_container, control;
control = this;
inner_container = control.container.find('[data-field="'+control.openedGallery+'"]').closest('.image-gallery-attachments');
inner_container.html('');
_.each(control.params.fields[control.openedGallery].attachments, function(attachment){
inner_container.append('

');
} );
control.gallerySetupSortable();
},
/**
* Open the media modal.
*/
galleryOpenFrame: function( event ) {
event.preventDefault();
if ( ! this.frame ) {
this.galleryInitFrame();
}
this.frame.open();
},
/**
* Initiate the media modal select frame.
* Save it for using later in case needed.
*/
galleryInitFrame: function() {
var control = this, galleryPreSelectImages;
this.frame = wp.media({
button: {
text: 'Choose Images'
},
states: [
new wp.media.controller.Library({
title: 'Select Gallery Images',
library: wp.media.query({ type: 'image' }),
multiple: 'add'
})
]
});
/**
* Pre-select images according to saved settings.
*/
galleryPreSelectImages = function() {
var selection, ids, attachment, library;
library = control.frame.state().get( 'library' );
selection = control.frame.state().get( 'selection' );
ids = control.getValue();
if( !_.isUndefined(ids[control.openedGallery]) && ids[control.openedGallery].length )
ids = JSON.parse( ids[control.openedGallery].replace('{', '[').replace('}', ']') );
else
ids = [];
// Sort the selected images to top when opening media modal.
library.comparator = function( a, b ) {
var hasA = true === this.mirroring.get( a.cid ),
hasB = true === this.mirroring.get( b.cid );
if ( ! hasA && hasB ) {
return -1;
} else if ( hasA && ! hasB ) {
return 1;
} else {
return 0;
}
};
_.each( ids, function( id ) {
attachment = wp.media.attachment( id );
selection.add( attachment ? [ attachment ] : [] );
library.add( attachment ? [ attachment ] : [] );
});
};
control.frame.on( 'open', galleryPreSelectImages );
control.frame.on( 'select', control.gallerySelect );
},
/**
* Callback for selecting attachments.
*/
gallerySelect: function() {
var control = this, attachments, attachmentIds, fieldId, newValue;
attachments = control.frame.state().get( 'selection' ).toJSON();
control.params.fields[control.openedGallery].attachments = attachments;
attachmentIds = control.galleryGetAttachmentIds( attachments );
fieldId = control.container.find('.image-gallery-attachments').data('field');
newValue = JSON.stringify(attachmentIds).replace('[', '__array__').replace(']', '__array__end__');
control.setValue( newValue, true, false, fieldId, 'image_gallery', '', '');
control.container.focus();
control.setGalleryDataAndRenderContent(fieldId);
},
/**
* Get array of attachment id-s from attachment objects.
*
* @param {Array} attachments Attachments.
* @returns {Array}
*/
galleryGetAttachmentIds: function( attachments ) {
var ids = [], i;
for ( i in attachments ) {
ids.push( attachments[ i ].id );
}
return ids;
},
gallerySetAttachmentsData: function( value ) {
var control = this,
promises = [];
control.params.fields[control.openedGallery].attachments = [];
_.each( value, function( id, index ) {
var hasAttachmentData = new jQuery.Deferred();
wp.media.attachment( id ).fetch().done( function() {
control.params.fields[control.openedGallery].attachments[ index ] = this.attributes;
hasAttachmentData.resolve();
} );
promises.push( hasAttachmentData );
} );
return jQuery.when.apply( undefined, promises ).promise();
},
gallerySetupSortable: function() {
var control = this,
list = jQuery( '.image-gallery-attachments' );
list.sortable({
items: '.image-gallery-thumbnail-wrapper',
tolerance: 'pointer',
stop: function() {
var selectedValues = [];
list.find( '.image-gallery-thumbnail-wrapper' ).each( function() {
var id;
id = parseInt( jQuery( this ).data( 'postId' ), 10 );
selectedValues.push( id );
} );
var fieldId = control.container.find('.image-gallery-attachments').data('field');
var newValue = JSON.stringify(selectedValues).replace('[', '__array__').replace(']', '__array__end__');
control.setValue( newValue, true, false, fieldId, 'image_gallery', '', '');
}
});
},
buildDependeciens: function(){
this.active_callback = {};
var control = this;
if(_.isUndefined(control.cl_required))
control.cl_required = {};
_.each(control.params.fields, function(field, key){
if(!_.isUndefined(field['cl_required']) && field['cl_required'].length){
_.each(field['cl_required'], function(req, index){
if(_.isUndefined(control.cl_required[req['setting']]))
control.cl_required[req['setting']] = [];
var opt = req['setting'];
req['setting'] = key;
control.cl_required[opt].push(req);
});
}
});
},
createEl: function(data, first){
var control = this;
if(first){
this.final_value = '';
this.element_id = data.id;
this.container.attr('data-model-id', this.element_id);
}
this.addElements(data.options);
var control = this;
this.container.on( 'click', '.tooltip-trigger', function(e) {
e.preventDefault();
var $parent = $(this).closest('.tooltip-wrapper');
$parent.find( '.tooltip-content' ).toggleClass( 'hidden' );
});
jQuery( document ).mouseup( function( e ) {
if ( ! jQuery( '.tooltip-content', this.container ).is( e.target ) ) {
jQuery( '.tooltip-content', this.container ).addClass( 'hidden' );
}
});
_.each( control.params.fields, function( subValue, index ){
control.checkDependecies(index, control.element_values[index]);
if( control.params.fields[index]['type'] == 'image_gallery')
control.galleryReady(index);
} );
control.initColorPicker();
control.initKirkiSortable();
control.initSelect();
this.activeTabs();
this.container.on( 'click', '.change_icon', function(e){
e.preventDefault();
if(jQuery(this).parent().find('.icons_div').hasClass('hidden'))
jQuery(this).parent().find('.icons_div').removeClass('hidden');
else
jQuery(this).parent().find('.icons_div').addClass('hidden');
});
this.container.on( 'click keypress', '.element-field-image .image-upload-button,.element-field-cropped_image .upload-button,.element-field-upload .image-upload-button', function( e ) {
e.preventDefault();
control.$thisButton = jQuery( this );
control.openFrame( e );
});
this.container.on( 'click keypress', '.element-field-image .image-remove-button,.element-field-cropped_image .iamge-remove-button', function( e ) {
e.preventDefault();
control.$thisButton = jQuery( this );
control.removeImage( e );
});
this.container.on( 'click keypress', '.element-field-upload .image-remove-button', function( e ) {
e.preventDefault();
control.$thisButton = jQuery( this );
control.removeFile( e );
});
var typingTimer;
var doneTypingInterval = 1000;
this.container.on( 'change paste keyup ', 'input:not([type="range"]), select, textarea', function( e ) {
var element = jQuery( this );
/*if( jQuery(e.target).parent('span.value').length > 0 )
return true;*/
if( jQuery(e.target).closest('.element-field-css_tool').length == 0 && ( jQuery(e.target).is('[multiple="multiple"]') || jQuery(e.target).is('[type="text"]') ) ){
clearTimeout(typingTimer);
typingTimer = setTimeout(function(){ executeChange(e, element) }, doneTypingInterval);
}else{
setTimeout(function(){
executeChange(e, element);
}, 100);
}
});
// Only Slider Elements
this.container.on( 'input', 'input[type="range"]', function( e ) {
var element = jQuery( this );
if( jQuery(e.target).parent('span.value').length > 0 )
return true;
if( jQuery(e.target).closest('.element-field-css_tool').length == 0 && ( jQuery(e.target).is('[multiple="multiple"]') || jQuery(e.target).is('[type="text"]') ) ){
clearTimeout(typingTimer);
typingTimer = setTimeout(function(){ executeChange(e, element) }, doneTypingInterval);
}else{
setTimeout(function(){
executeChange(e, element);
}, 100);
}
});
var executeChange = function(e, element){
e.stopImmediatePropagation();
if(jQuery(e.target).is('[type="search"]') && jQuery(e.target).hasClass('search_icons')){
control.searchIcons( jQuery(e.target) );
}
var el = e.target;
/*if( jQuery(el).is('input') && jQuery(el).parent('.selectize-input').length > 0 ){
var el_correct = jQuery(el).closest('.element-wrapper').find('select');
el = el_correct;
}*/
if( control.element_id == jQuery( el ).closest('.customize-control-clelement').attr('data-model-id') ){
var currentElementId = control.element_id;
control.updateField.call(control, e, jQuery( el ).closest('.element-field').data( 'field' ), el, currentElementId );
}
if(jQuery(e.target).is('[type="range"]')){
element.closest( 'label' ).find( '.value input' ).prop( "value", jQuery(e.target).attr('value') );
}
}
this.container.on( 'keydown', 'input, select', function( e ) {
clearTimeout(typingTimer);
});
},
searchIcons: function( target ){
var icons_wrapper = target.parent().find('.icons-wrapper');
var val = target.val();
var selected = icons_wrapper.children("[id*='"+val+"']");
icons_wrapper.children( '.icon' ).not(selected).css('display', 'none');
selected.css('display', 'inline-block');
if( val == '' )
icons_wrapper.children( '.icon' ).css('display', 'inline-block');
},
/**
* Open the media modal.
*/
activeTabs: function(){
var $actived = this.container.find('.tab_sections .active');
var actived_id = $actived.data('tab');
var control = this;
control.container.find('#tab-'+actived_id).css({display:'block'}).addClass('active');
control.container.find('.tab_sections a').on('click', function(){
var $actived = jQuery(this);
var actived_id = $actived.data('tab');
control.container.find('.tab_sections a').removeClass('active');
$actived.addClass('active');
control.container.find('.tab_section.active').removeClass('active').css({display:'none'});
control.container.find('#tab-'+actived_id).css({display:'block'}).addClass('active');
control.container.on( 'click', '.tooltip-trigger', function(e) {
e.preventDefault();
var $parent = $(this).closest('.tooltip-wrapper');
$parent.find( '.tooltip-content' ).toggleClass( 'hidden' );
});
jQuery( document ).mouseup( function( e ) {
if ( ! jQuery( '.tooltip-content', control.container ).is( e.target ) ) {
jQuery( '.tooltip-content', control.container ).addClass( 'hidden' );
}
});
});
},
openFrame: function( event ) {
'use strict';
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
if ( this.$thisButton.closest( '.element-field' ).hasClass( 'element-field-cropped_image' ) ) {
this.initCropperFrame();
} else {
this.initFrame();
}
this.frame.open();
},
initFrame: function() {
'use strict';
var libMediaType = this.getMimeType();
if ( typeof this.frame != 'undefined' ) {
this.frame.close();
}
if( ! _.isUndefined(wp.media.view.MediaFrame.CodelessPost) )
this.frame = new wp.media.view.MediaFrame.CodelessPost({
multiple:false,
});
else{
this.frame = wp.media({
multiple:false
});
this.frame.on( 'select', this.onSelect, this );
}
// When a file is selected, run a callback.
this.frame.on( 'insert', this.onSelect, this );
},
/**
* Create a media modal select frame, and store it so the instance can be reused when needed.
* This is mostly a copy/paste of Core api.CroppedImageControl in /wp-admin/js/customize-control.js
*/
initCropperFrame: function() {
'use strict';
// We get the field id from which this was called
var currentFieldId = this.$thisButton.siblings( 'input.hidden-field' ).attr( 'data-field' ),
attrs = [ 'width', 'height', 'flex_width', 'flex_height' ], // A list of attributes to look for
libMediaType = this.getMimeType();
// Make sure we got it
if ( 'string' === typeof currentFieldId && '' !== currentFieldId ) {
// Make fields is defined and only do the hack for cropped_image
if ( 'object' === typeof this.params.fields[ currentFieldId ] && 'cropped_image' === this.params.fields[ currentFieldId ].type ) {
//Iterate over the list of attributes
attrs.forEach( function( el, index ) {
// If the attribute exists in the field
if ( 'undefined' !== typeof this.params.fields[ currentFieldId ][ el ] ) {
// Set the attribute in the main object
this.params[ el ] = this.params.fields[ currentFieldId ][ el ];
}
}.bind( this ) );
}
}
this.frame = wp.media({
button: {
text: 'Select and Crop',
close: false
},
states: [
new wp.media.controller.Library({
library: wp.media.query({ type: libMediaType }),
multiple: false,
date: false,
suggestedWidth: this.params.width,
suggestedHeight: this.params.height
}),
new wp.media.controller.CustomizeImageCropper({
imgSelectOptions: this.calculateImageSelectOptions,
control: this
})
]
});
this.frame.on( 'select', this.onSelectForCrop, this );
this.frame.on( 'cropped', this.onCropped, this );
this.frame.on( 'skippedcrop', this.onSkippedCrop, this );
},
onSelect: function() {
'use strict';
var sel = this.frame.state().get( 'selection' ).first();
var attachment = !_.isUndefined(sel) ? sel.toJSON() : '';
var mime = attachment.mime,
regex = /^image\/(?:jpe?g|png|url|gif|x-icon)$/i;
if (mime.match(regex)) {
this.setImageInRepeaterField( attachment );
} else {
this.setOembed( attachment );
}
},
/**
* After an image is selected in the media modal, switch to the cropper
* state if the image isn't the right size.
*/
onSelectForCrop: function() {
'use strict';
var attachment = this.frame.state().get( 'selection' ).first().toJSON();
if ( this.params.width === attachment.width && this.params.height === attachment.height && ! this.params.flex_width && ! this.params.flex_height ) {
this.setImageInRepeaterField( attachment );
} else {
this.frame.setState( 'cropper' );
}
},
/**
* After the image has been cropped, apply the cropped image data to the setting.
*
* @param {object} croppedImage Cropped attachment data.
*/
onCropped: function( croppedImage ) {
'use strict';
this.setImageInRepeaterField( croppedImage );
},
/**
* Returns a set of options, computed from the attached image data and
* control-specific data, to be fed to the imgAreaSelect plugin in
* wp.media.view.Cropper.
*
* @param {wp.media.model.Attachment} attachment
* @param {wp.media.controller.Cropper} controller
* @returns {Object} Options
*/
calculateImageSelectOptions: function( attachment, controller ) {
'use strict';
var control = controller.get( 'control' ),
flexWidth = !! parseInt( control.params.flex_width, 10 ),
flexHeight = !! parseInt( control.params.flex_height, 10 ),
realWidth = attachment.get( 'width' ),
realHeight = attachment.get( 'height' ),
xInit = parseInt( control.params.width, 10 ),
yInit = parseInt( control.params.height, 10 ),
ratio = xInit / yInit,
xImg = realWidth,
yImg = realHeight,
x1,
y1,
imgSelectOptions;
controller.set( 'canSkipCrop', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );
if ( xImg / yImg > ratio ) {
yInit = yImg;
xInit = yInit * ratio;
} else {
xInit = xImg;
yInit = xInit / ratio;
}
x1 = ( xImg - xInit ) / 2;
y1 = ( yImg - yInit ) / 2;
imgSelectOptions = {
handles: true,
keys: true,
instance: true,
persistent: true,
imageWidth: realWidth,
imageHeight: realHeight,
x1: x1,
y1: y1,
x2: xInit + x1,
y2: yInit + y1
};
if ( false === flexHeight && false === flexWidth ) {
imgSelectOptions.aspectRatio = xInit + ':' + yInit;
}
if ( false === flexHeight ) {
imgSelectOptions.maxHeight = yInit;
}
if ( false === flexWidth ) {
imgSelectOptions.maxWidth = xInit;
}
return imgSelectOptions;
},
/**
* Return whether the image must be cropped, based on required dimensions.
*
* @param {bool} flexW
* @param {bool} flexH
* @param {int} dstW
* @param {int} dstH
* @param {int} imgW
* @param {int} imgH
* @return {bool}
*/
mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) {
'use strict';
if ( true === flexW && true === flexH ) {
return false;
}
if ( true === flexW && dstH === imgH ) {
return false;
}
if ( true === flexH && dstW === imgW ) {
return false;
}
if ( dstW === imgW && dstH === imgH ) {
return false;
}
if ( imgW <= dstW ) {
return false;
}
return true;
},
/**
* If cropping was skipped, apply the image data directly to the setting.
*/
onSkippedCrop: function() {
'use strict';
var attachment = this.frame.state().get( 'selection' ).first().toJSON();
this.setImageInRepeaterField( attachment );
},
/**
* Updates the setting and re-renders the control UI.
*
* @param {object} attachment
*/
setImageInRepeaterField: function( attachment ) {
'use strict';
var control = this;
var $targetDiv = this.$thisButton.closest( '.element-field-image,.element-field-cropped_image' );
$targetDiv.find( '.image-wrapper .placeholder' ).html( '
' );
$targetDiv.find( '.image-wrapper' ).addClass("added_image");
control.updateField(null, $targetDiv.data('field'), null );
//$targetDiv.find( '.hidden-field' ).val( attachment.id );
this.$thisButton.text( this.$thisButton.data( 'alt-label' ) );
$targetDiv.find( '.image-upload-remove-button' ).show();
//This will activate the save button
$targetDiv.find( 'input, textarea, select' ).trigger( 'change' );
this.frame.close();
},
setOembed: function( attachment ) {
'use strict';
var that = this;
var $targetDiv = this.$thisButton.closest( '.element-field-image,.element-field-cropped_image' );
$targetDiv.find( '.kirki-image-attachment' ).html( ''+attachment.title+'
' );
$targetDiv.find( '.kirki-image-attachment' ).addClass("added_image");
$targetDiv.find( '.hidden-field' ).val( attachment.id );
this.$thisButton.text( this.$thisButton.data( 'alt-label' ) );
$targetDiv.find( '.remove-button' ).show();
//This will activate the save button
$targetDiv.find( 'input, textarea, select' ).trigger( 'change' );
this.frame.close();
},
/**
* Updates the setting and re-renders the control UI.
*
* @param {object} attachment
*/
setFileInRepeaterField: function( attachment ) {
'use strict';
var $targetDiv = this.$thisButton.closest( '.element-field-upload' );
$targetDiv.find( '.kirki-file-attachment' ).html( ' ' + attachment.filename + '' ).hide().slideDown( 'slow' );
$targetDiv.find( '.hidden-field' ).val( attachment.id );
this.$thisButton.text( this.$thisButton.data( 'alt-label' ) );
$targetDiv.find( '.upload-button' ).show();
$targetDiv.find( '.remove-button' ).show();
//This will activate the save button
$targetDiv.find( 'input, textarea, select' ).trigger( 'change' );
this.frame.close();
},
getMimeType: function() {
'use strict';
// We get the field id from which this was called
var currentFieldId = this.$thisButton.siblings( 'input.hidden-field' ).attr( 'data-field' ),
attrs = [ 'mime_type' ]; // A list of attributes to look for
// Make sure we got it
if ( 'string' === typeof currentFieldId && '' !== currentFieldId ) {
// Make fields is defined and only do the hack for cropped_image
if ( 'object' === typeof this.params.fields[ currentFieldId ] && 'upload' === this.params.fields[ currentFieldId ].type ) {
// If the attribute exists in the field
if ( 'undefined' !== typeof this.params.fields[ currentFieldId ].mime_type ) {
// Set the attribute in the main object
return this.params.fields[ currentFieldId ].mime_type;
}
}
}
return 'image';
},
removeImage: function( event ) {
'use strict';
var $targetDiv,
control = this,
$uploadButton;
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
$targetDiv = this.$thisButton.closest( '.element-field-image,.element-field-cropped_image,.element-field-upload' );
$uploadButton = $targetDiv.find( '.image-upload-button' );
var $a = $targetDiv.find( '.image-wrapper img' );
$a.remove();
$a.removeClass('added_image');
control.updateField( null, $targetDiv.data('field'), null );
$uploadButton.text( $uploadButton.data( 'label' ) );
this.$thisButton.hide();
$targetDiv.find( 'input, textarea, select' ).trigger( 'change' );
},
removeFile: function( event ) {
'use strict';
var $targetDiv,
$uploadButton;
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
$targetDiv = this.$thisButton.closest( '.element-field-upload' );
$uploadButton = $targetDiv.find( '.upload-button' );
$targetDiv.find( '.kirki-file-attachment' ).slideUp( 'fast', function() {
jQuery( this ).show().html( jQuery( this ).data( 'placeholder' ) );
});
$targetDiv.find( '.hidden-field' ).val( '' );
$uploadButton.text( $uploadButton.data( 'label' ) );
this.$thisButton.hide();
$targetDiv.find( 'input, textarea, select' ).trigger( 'change' );
},
initKirkiSortable: function() {
'use strict';
var control = this;
control.container.find( '.kirki-controls-loading-spinner' ).hide();
// Set the sortable container.
control.sortableContainer = control.container.find( 'ul.sortable' ).first();
// Init sortable.
control.sortableContainer.sortable({
// Update value when we stop sorting.
stop: function() {
control.updateSortableValue();
}
}).disableSelection().find( 'li' ).each( function() {
// Enable/disable options when we click on the eye of Thundera.
jQuery( this ).find( 'i.visibility' ).on( 'click', function() {
jQuery( this ).toggleClass( 'dashicons-visibility-faint' ).parents( 'li:eq(0)' ).toggleClass( 'invisible' );
});
}).on( 'click', function() {
// Update value on click.
control.updateSortableValue();
});
},
/**
* Updates the sorting list
*/
updateSortableValue: function() {
'use strict';
var control = this,
newValue = [],
fieldId = this.sortableContainer.closest('.element-field').data( 'field' );
this.sortableContainer.find( 'li' ).each( function() {
if ( ! jQuery( this ).is( '.invisible' ) ) {
newValue.push( jQuery( this ).data( 'value' ) );
}
});
control.setValue( newValue, true, false, fieldId, 'sortable' );
},
/**
* Get the current value of the setting
*
* @return Object
*/
getValue: function() {
'use strict';
return this.element_values;
},
/**
* Set a new value for the setting
*
* @param newValue Object
* @param refresh If we want to refresh the previewer or not
*/
setValue: function( newValue, refresh, filtering, fieldId, field_type, selector, css_property, subKey ) {
'use strict';
this.element_values[fieldId] = newValue;
this.setting.previewer.send('cl_element_updated', [this.element_id, fieldId, field_type, newValue, selector, css_property, this.cl_required[fieldId], subKey] );
},
/**
* Add a new row to repeater settings based on the structure.
*
* @param data (Optional) Object of field => value pairs (undefined if you want to get the default values)
*/
addElements: function( data, first ) {
'use strict';
var control = this,
//template = control.elementTemplate(), // The template for the new row (defined on Kirki_Customize_Repeater_Control::render_content() ).
settingValue = this.getValue(), // Get the current setting value.
newRowSetting = [], // Saves the new setting data.
templateData, // Data to pass to the template
newRow,
temporaryHtml = '',
u,
i;
var reMap = {
'color': 'kirki-input-color',
'switch': 'kirki-switch',
'select': 'kirki-input-select',
'slider': 'kirki-slider',
'inline_select': 'kirki-input-select',
'text' : 'cltext',
'image' : 'kirki-input-image',
'multicheck': 'kirki-multicheck',
'sortable': 'kirki-sortable',
'textarea': 'kirki-input-textarea'
}
// The control structure is going to define the new fields
// We need to clone control.params.fields. Assigning it
// ould result in a reference assignment.
templateData = jQuery.extend( true, {}, control.params.fields );
_.each( templateData, function( value, key ){
var type = value['type'],
newType = _.isUndefined( reMap[type] ) ? type : reMap[type];
value['value'] = !_.isUndefined( data[key] ) ? data[key] : value['default'];
control.element_values[key] = value['value'];
value['id'] = key;
if( type == 'inline_text' || type == 'select_icon' || ( !_.isUndefined( value['show'] ) && !value['show'] ) )
return true;
if( type == 'image' ){
if( !_.isUndefined( value['value']['url'] ) )
value['value']['url'] = decodeURIComponent( value['value']['url'] );
if( _.isObject(value['value']) && _.isEmpty( value['value'] ) )
value['value'] = '';
}
if(type == 'color'){
value['data-alpha'] = true;
}
if( type == 'slider' ){
value['inputAttrs'] = 'value="'+value['value']+'" min="'+value['choices']['min']+'" max="'+value['choices']['max']+'" step="'+value['choices']['step']+'"';
}
if( type == 'sortable' ){
if( _.isObject( value['value'] ) ){
var arrayValue = $.map(value['value'], function(value, index) {
return [value];
});
}
value['value'] = arrayValue;
}
var template_name = newType;
if( template_name.indexOf('kirki-input') === -1 )
template_name = 'customize-control-' + template_name + '-content';
console.log(template_name);
var template = wp.template( template_name );
if( value.type == 'css_tool' && ( _.isEmpty( value.value ) || _.isUndefined( value.value ) ) )
value.value = value.default;
console.log(value.value)
if( newType == 'kirki-input-color' )
newType = 'kirki-color';
if( newType == 'kirki-input-select' )
newType = 'kirki-select';
template = template( value );
if( type != 'show_tabs' && type != 'tab_start' && type != 'tab_end' && type != 'group_start' && type != 'group_end' ){
var tooltip_trigger = '',
tooltip_content = '',
tooltip_wrapper = '';
if( !_.isUndefined( value.tooltip ) ){
tooltip_trigger = '';
tooltip_content = '' + value.tooltip + '
';
tooltip_wrapper = '' + tooltip_trigger + tooltip_content + '
';
}
template = '' + tooltip_wrapper + template + '
';
}
temporaryHtml += template;
} );
// Remove Old Events
control.container.off( 'change paste keyup ', 'input:not([type="range"]), select, textarea');
control.container.off( 'input', 'input[type="range"]');
control.container.off( 'click keypress', '.element-field-image .image-upload-button,.element-field-cropped_image .upload-button,.element-field-upload .image-upload-button');
control.container.off( 'click keypress', '.element-field-image .image-remove-button,.element-field-cropped_image .iamge-remove-button');
control.container.off( 'click keypress', '.element-field-upload .image-remove-button');
control.elementsFieldsContainer.html( temporaryHtml );
// But if we have passed data, we'll use the data values instead
/*if ( data ) {
for ( i in data ) {
if ( data.hasOwnProperty( i ) && templateData.hasOwnProperty( i ) ) {
templateData[ i ]['default'] = data[ i ];
}
}
}
// Append the template content
template = template( templateData );
control.elementsFieldsContainer.html(template);
for ( u in templateData ) {
if ( templateData.hasOwnProperty( u ) ) {
settingValue[u] = templateData[ u ]['default'];
}
}
this.setValue( settingValue, false );
return newRow;*/
},
/**
* Update a single field inside a row.
* Triggered when a field has changed
*
* @param e Event Object
*/
updateField: function( e, fieldId, element, executeElementId ) {
'use strict';
var type,
subKey,
currentSettings,
control = this,
currentValue;
if ( ! this.params.fields[ fieldId ] ) {
return;
}
if( !_.isUndefined(executeElementId) && !_.isNull( executeElementId ) && executeElementId != control.element_id )
return;
type = this.params.fields[ fieldId].type;
currentSettings = this.getValue();
element = jQuery( element );
if ( undefined === typeof currentSettings[ fieldId ] ) {
return;
}
if ( 'checkbox' === type || 'switch' === type ) {
currentValue = element.is( ':checked' ) ? 1 : 0;
}else if('image' === type) {
var final_img = {};
var sel = (!_.isUndefined(this.frame) ? this.frame.state().get( 'selection' ).first() : '');
if( !_.isUndefined(sel) && !_.isEmpty(sel) ){
sel = sel.toJSON();
_.each(sel, function(value, key){
final_img[key] = encodeURIComponent(value);
});
}
currentValue = final_img;
}else if('css_tool' === type){
var name = element.data('name');
if(!_.isObject(currentValue) )
currentValue = {};
if ( false === kirki.util.validate.cssValue( element.val() ) && element.val() != '' ) {
element.addClass('invalid');
return;
}else{
element.removeClass('invalid');
currentValue = element.val();
if(element.val() == '' && !_.isUndefined(currentValue[name]))
delete currentValue[ name ];
subKey = name;
}
} else if('multicheck' == type) {
var value = {}, i = 0, control = this;
jQuery.each( control.params.fields[ fieldId].choices, function( key, subValue ) {
if ( control.container.find( 'input[value="' + key + '"]' ).is( ':checked' ) ) {
value[ i ] = key;
i++;
}
});
currentValue = value;
} else if('select' == type || type == 'inline_select'){
var value = element.val();
var multiple = parseInt( element.data( 'multiple' ) );
if ( multiple > 1 ) {
value = _.extend( {}, element.val() );
}
currentValue = value;
} else {
// Update the settings
currentValue = element.val();
}
if( _.isUndefined( currentValue ) )
currentValue = '';
this.setValue( currentValue, true, false, fieldId, type, '', '', subKey );
this.checkDependecies(fieldId, currentValue);
},
checkDependecies: function(fieldId, value){
var operators = {
'==': function(a, b){ return a==b},
'!=': function(a, b){ return a!=b}
}
var control = this;
if(!_.isUndefined(this.cl_required[fieldId]) && this.cl_required[fieldId].length ){
_.each(this.cl_required[fieldId], function(opt, index){
if(operators[opt['operator']](opt['value'], value ) ){
control.container.find('.id-'+opt['setting']).removeClass('show_on_required');
}else{
control.container.find('.id-'+opt['setting']).addClass('show_on_required');
}
});
}
},
/**
* Init the color picker on color fields
* Called after AddRow
*
*/
initColorPicker: function() {
'use strict';
var control = this,
colorPicker = control.container.find( '.kirki-color-control' );
jQuery.each(colorPicker, function(){
var colorPicker = jQuery(this);
var options = {};
var fieldId = colorPicker.closest('.element-field').data( 'field' );
// We check if the color palette parameter is defined.
if ( 'undefined' !== typeof fieldId && 'undefined' !== typeof control.params.fields[ fieldId ] && 'undefined' !== typeof control.params.fields[ fieldId ].palettes && 'object' === typeof control.params.fields[ fieldId ].palettes ) {
options.palettes = control.params.fields[ fieldId ].palettes;
}
options.width = 259;
options.palettes = codelessPalettes;
// When the color picker value is changed we update the value of the field
options.change = function( event, ui ) {
var currentPicker = jQuery( event.target ),
selector = '',
css_property = '';
if('undefined' !== typeof control.params.fields[ fieldId ].selector)
selector = control.params.fields[ fieldId ].selector;
if('undefined' !== typeof control.params.fields[ fieldId ].css_property)
css_property = control.params.fields[ fieldId ].css_property;
if( !colorPicker.closest('.element-field').hasClass('show_on_required') )
control.setValue( ui.color.toString(), true, false, fieldId, 'color', selector, css_property );
};
// Init the color picker
if ( 0 !== colorPicker.length ) {
colorPicker.wpColorPicker( options );
}
});
},
/**
* Init the dropdown-pages field with selectize
* Called after AddRow
*
* @param {object} theNewRow the row that was added to the repeater
* @param {object} data the data for the row if we're initializing a pre-existing row
*
*/
initSelect: function( data ) {
'use strict';
var control = this,
dropdown = control.container.find( 'select' ),
$select,
dataField,
multiple,
selectWooOptions = {};
if ( 0 === dropdown.length ) {
return;
}
dataField = dropdown.data( 'field' );
multiple = jQuery( dropdown ).data( 'multiple' );
if ( 'undefined' !== multiple && jQuery.isNumeric( multiple ) ) {
multiple = parseInt( multiple, 10 );
if ( 1 < multiple ) {
selectWooOptions.maximumSelectionLength = multiple;
}
}
$select = jQuery( dropdown ).selectWoo( selectWooOptions ).val( dropdown.val() );
this.selects.push( $select );
},
updateSilent: function(element){
jQuery.each(this.selects[0], function(key, value){
if(jQuery(value).closest('.element-field').data('field') == element.id){
jQuery( value ).selectWoo().val( element.value ).trigger( 'change' );
}
});
},
kirkiValidateCSSValue: function( value ) {
var validUnits = ['rem', 'em', 'ex', '%', 'px', 'cm', 'mm', 'in', 'pt', 'pc', 'ch', 'vh', 'vw', 'vmin', 'vmax'],
numericValue,
unit;
// 0 is always a valid value, and we can't check calc() values effectively.
if ( '0' === value || ( 0 <= value.indexOf( 'calc(' ) && 0 <= value.indexOf( ')' ) ) ) {
return true;
}
// Get the numeric value.
numericValue = parseFloat( value );
// Get the unit
unit = value.replace( numericValue, '' );
// Check the validity of the numeric value and units.
if ( isNaN( numericValue ) || -1 === jQuery.inArray( unit, validUnits ) ) {
return false;
}
return true;
}
});