Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
<?php
|
||||
/**
|
||||
* Rara Business Customizer Repeater Control.
|
||||
*
|
||||
* @package Rara_Business
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if( ! class_exists( 'Rara_Business_Control_Repeater' ) ) {
|
||||
/**
|
||||
* Repeater control
|
||||
*/
|
||||
class Rara_Business_Control_Repeater extends WP_Customize_Control {
|
||||
|
||||
/**
|
||||
* The control type.
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'rara-business-repeater';
|
||||
|
||||
/**
|
||||
* Data type
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $option_type = 'theme_mod';
|
||||
|
||||
/**
|
||||
* The fields that each container row will contain.
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
public $fields = array();
|
||||
|
||||
/**
|
||||
* Will store a filtered version of value for advenced fields (like images).
|
||||
*
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
protected $filtered_value = array();
|
||||
|
||||
/**
|
||||
* The row label
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
public $row_label = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Supplied `$args` override class property defaults.
|
||||
* If `$args['settings']` is not defined, use the $id as the setting ID.
|
||||
*
|
||||
* @param WP_Customize_Manager $manager Customizer bootstrap instance.
|
||||
* @param string $id Control ID.
|
||||
* @param array $args {@see WP_Customize_Control::__construct}.
|
||||
*/
|
||||
public function __construct( $manager, $id, $args = array() ) {
|
||||
|
||||
parent::__construct( $manager, $id, $args );
|
||||
|
||||
// Set up defaults for row labels.
|
||||
$this->row_label = array(
|
||||
'type' => 'text',
|
||||
'value' => esc_attr__( 'row', 'rara-business' ),
|
||||
'field' => false,
|
||||
);
|
||||
|
||||
// Validate row-labels.
|
||||
$this->row_label( $args );
|
||||
|
||||
if ( empty( $this->button_label ) ) {
|
||||
$this->button_label = sprintf( esc_attr__( 'Add new %s', 'rara-business' ), $this->row_label['value'] );
|
||||
}
|
||||
|
||||
if ( empty( $args['fields'] ) || ! is_array( $args['fields'] ) ) {
|
||||
$args['fields'] = array();
|
||||
}
|
||||
|
||||
// An array to store keys of fields that need to be filtered.
|
||||
$media_fields_to_filter = array();
|
||||
|
||||
foreach ( $args['fields'] as $key => $value ) {
|
||||
$args['fields'][ $key ]['default'] = ( isset( $value['default'] ) ) ? $value['default'] : '';
|
||||
$args['fields'][ $key ]['id'] = $key;
|
||||
|
||||
// We check if the filed is an uploaded media ( image , file, video, etc.. ).
|
||||
if ( isset( $value['type'] ) ) {
|
||||
switch ( $value['type'] ) {
|
||||
case 'image':
|
||||
case 'cropped_image':
|
||||
case 'upload':
|
||||
// We add it to the list of fields that need some extra filtering/processing.
|
||||
$media_fields_to_filter[ $key ] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->fields = $args['fields'];
|
||||
|
||||
// Now we are going to filter the fields.
|
||||
// First we create a copy of the value that would be used otherwise.
|
||||
$this->filtered_value = $this->value();
|
||||
|
||||
if ( is_array( $this->filtered_value ) && ! empty( $this->filtered_value ) ) {
|
||||
|
||||
// We iterate over the list of fields.
|
||||
foreach ( $this->filtered_value as &$filtered_value_field ) {
|
||||
|
||||
if ( is_array( $filtered_value_field ) && ! empty( $filtered_value_field ) ) {
|
||||
|
||||
// We iterate over the list of properties for this field.
|
||||
foreach ( $filtered_value_field as $key => &$value ) {
|
||||
|
||||
// We check if this field was marked as requiring extra filtering (in this case image, cropped_images, upload).
|
||||
if ( array_key_exists( $key, $media_fields_to_filter ) ) {
|
||||
|
||||
// What follows was made this way to preserve backward compatibility.
|
||||
// The repeater control use to store the URL for images instead of the attachment ID.
|
||||
// We check if the value look like an ID (otherwise it's probably a URL so don't filter it).
|
||||
if ( is_numeric( $value ) ) {
|
||||
|
||||
// "sanitize" the value.
|
||||
$attachment_id = (int) $value;
|
||||
|
||||
// Try to get the attachment_url.
|
||||
$url = wp_get_attachment_url( $attachment_id );
|
||||
|
||||
$filename = basename( get_attached_file( $attachment_id ) );
|
||||
|
||||
// If we got a URL.
|
||||
if ( $url ) {
|
||||
|
||||
// 'id' is needed for form hidden value, URL is needed to display the image.
|
||||
$value = array(
|
||||
'id' => $attachment_id,
|
||||
'url' => $url,
|
||||
'filename' => $filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the parameters passed to the JavaScript via JSON.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
|
||||
$this->json['default'] = ( isset( $this->default ) ) ? $this->default : $this->setting->default;
|
||||
$this->json['value'] = $this->value();
|
||||
$this->json['choices'] = $this->choices;
|
||||
$this->json['link'] = $this->get_link();
|
||||
$this->json['id'] = $this->id;
|
||||
|
||||
if ( 'user_meta' === $this->option_type ) {
|
||||
$this->json['value'] = get_user_meta( get_current_user_id(), $this->id, true );
|
||||
}
|
||||
|
||||
$this->json['inputAttrs'] = '';
|
||||
foreach ( $this->input_attrs as $attr => $value ) {
|
||||
$this->json['inputAttrs'] .= $attr . '="' . esc_attr( $value ) . '" ';
|
||||
}
|
||||
|
||||
$fields = $this->fields;
|
||||
|
||||
$this->json['fields'] = $fields;
|
||||
$this->json['row_label'] = $this->row_label;
|
||||
|
||||
// If filtered_value has been set and is not empty we use it instead of the actual value.
|
||||
if ( is_array( $this->filtered_value ) && ! empty( $this->filtered_value ) ) {
|
||||
$this->json['value'] = $this->filtered_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue control related scripts/styles.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function enqueue() {
|
||||
// If we have a color picker field we need to enqueue the WordPress Color Picker style and script.
|
||||
if ( is_array( $this->fields ) && ! empty( $this->fields ) ) {
|
||||
foreach ( $this->fields as $field ) {
|
||||
if ( isset( $field['type'] ) ){
|
||||
if( 'color' === $field['type'] ){
|
||||
wp_enqueue_script( 'wp-color-picker' );
|
||||
wp_enqueue_style( 'wp-color-picker' );
|
||||
}elseif( 'font' === $field['type'] ){
|
||||
wp_enqueue_script( 'all', get_template_directory_uri() . '/js/all.min.js', array( 'jquery' ), '6.1.1', true );
|
||||
wp_enqueue_script( 'v4-shims', get_template_directory_uri() . '/js/v4-shims.min.js', array( 'jquery', 'all' ), '6.1.1', true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wp_enqueue_script( 'rara-business-repeater', get_template_directory_uri() . '/inc/custom-controls/repeater/repeater.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-sortable' ), false, true );
|
||||
wp_enqueue_style( 'rara-business-repeater', get_template_directory_uri() . '/inc/custom-controls/repeater/repeater.css', null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the control's content.
|
||||
* Allows the content to be overriden without having to rewrite the wrapper in $this->render().
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function render_content() {
|
||||
?>
|
||||
<label>
|
||||
<?php if ( ! empty( $this->label ) ) : ?>
|
||||
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $this->description ) ) : ?>
|
||||
<span class="description customize-control-description"><?php echo wp_kses_post( $this->description ); ?></span>
|
||||
<?php endif; ?>
|
||||
<input type="hidden" {{{ data.inputAttrs }}} value="" <?php echo wp_kses_post( $this->get_link() ); ?> />
|
||||
</label>
|
||||
|
||||
<ul class="repeater-fields"></ul>
|
||||
|
||||
<?php if ( isset( $this->choices['limit'] ) ) : ?>
|
||||
<p class="limit"><?php printf( esc_html__( 'Limit: %s rows', 'rara-business' ), esc_html( $this->choices['limit'] ) ); ?></p>
|
||||
<?php endif; ?>
|
||||
<button class="button-secondary repeater-add"><?php echo esc_html( $this->button_label ); ?></button>
|
||||
|
||||
<?php
|
||||
|
||||
$this->repeater_js_template();
|
||||
}
|
||||
|
||||
/**
|
||||
* An Underscore (JS) template for this control's content (but not its container).
|
||||
* Class variables for this control class are available in the `data` JS object.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function repeater_js_template() {
|
||||
?>
|
||||
<script type="text/html" class="customize-control-repeater-content">
|
||||
<# var field; var index = data.index; #>
|
||||
|
||||
<li class="repeater-row minimized" data-row="{{{ index }}}">
|
||||
|
||||
<div class="repeater-row-header">
|
||||
<span class="repeater-row-label"></span>
|
||||
<i class="dashicons dashicons-arrow-down repeater-minimize"></i>
|
||||
</div>
|
||||
<div class="repeater-row-content">
|
||||
<# _.each( data, function( field, i ) { #>
|
||||
|
||||
<div class="repeater-field repeater-field-{{{ field.type }}}">
|
||||
|
||||
<# if ( 'text' === field.type || 'font' === field.type || 'url' === field.type || 'link' === field.type || 'email' === field.type || 'tel' === field.type || 'date' === field.type ) { #>
|
||||
|
||||
<# if ( 'link' === field.type ) { #>
|
||||
<# field.type = 'url' #>
|
||||
<# } #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
<input type="{{field.type}}" name="" value="{{{ field.default }}}" data-field="{{{ field.id }}}">
|
||||
</label>
|
||||
|
||||
<# } else if ( 'hidden' === field.type ) { #>
|
||||
|
||||
<input type="hidden" data-field="{{{ field.id }}}" <# if ( field.default ) { #> value="{{{ field.default }}}" <# } #> />
|
||||
|
||||
<# } else if ( 'checkbox' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" value="true" data-field="{{{ field.id }}}" <# if ( field.default ) { #> checked="checked" <# } #> /> {{ field.label }}
|
||||
<# if ( field.description ) { #>
|
||||
{{ field.description }}
|
||||
<# } #>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'select' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
<select data-field="{{{ field.id }}}">
|
||||
<# _.each( field.choices, function( choice, i ) { #>
|
||||
<option value="{{{ i }}}" <# if ( field.default == i ) { #> selected="selected" <# } #>>{{ choice }}</option>
|
||||
<# }); #>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'radio' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
|
||||
<# _.each( field.choices, function( choice, i ) { #>
|
||||
<label>
|
||||
<input type="radio" name="{{{ field.id }}}{{ index }}" data-field="{{{ field.id }}}" value="{{{ i }}}" <# if ( field.default == i ) { #> checked="checked" <# } #>> {{ choice }} <br/>
|
||||
</label>
|
||||
<# }); #>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'radio-image' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
|
||||
<# _.each( field.choices, function( choice, i ) { #>
|
||||
<input type="radio" id="{{{ field.id }}}_{{ index }}_{{{ i }}}" name="{{{ field.id }}}{{ index }}" data-field="{{{ field.id }}}" value="{{{ i }}}" <# if ( field.default == i ) { #> checked="checked" <# } #>>
|
||||
<label for="{{{ field.id }}}_{{ index }}_{{{ i }}}">
|
||||
<img src="{{ choice }}">
|
||||
</label>
|
||||
</input>
|
||||
<# }); #>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'color' === field.type ) { #>
|
||||
|
||||
<# var defaultValue = '';
|
||||
if ( field.default ) {
|
||||
if ( '#' !== field.default.substring( 0, 1 ) ) {
|
||||
defaultValue = '#' + field.default;
|
||||
} else {
|
||||
defaultValue = field.default;
|
||||
}
|
||||
defaultValue = ' data-default-color=' + defaultValue; // Quotes added automatically.
|
||||
} #>
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{{ field.label }}}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{{ field.description }}}</span>
|
||||
<# } #>
|
||||
<input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php echo esc_attr__( 'Hex Value', 'rara-business' ); ?>" value="{{{ field.default }}}" data-field="{{{ field.id }}}" {{ defaultValue }} />
|
||||
|
||||
</label>
|
||||
|
||||
<# } else if ( 'textarea' === field.type ) { #>
|
||||
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
<textarea rows="5" data-field="{{{ field.id }}}">{{ field.default }}</textarea>
|
||||
|
||||
<# } else if ( field.type === 'image' || field.type === 'cropped_image' ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
</label>
|
||||
|
||||
<figure class="rara-business-image-attachment" data-placeholder="<?php esc_attr_e( 'No Image Selected', 'rara-business' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<# var defaultImageURL = ( field.default.url ) ? field.default.url : field.default; #>
|
||||
<img src="{{{ defaultImageURL }}}">
|
||||
<# } else { #>
|
||||
<?php esc_attr_e( 'No Image Selected', 'rara-business' ); ?>
|
||||
<# } #>
|
||||
</figure>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="button remove-button<# if ( ! field.default ) { #> hidden<# } #>"><?php esc_html_e( 'Remove', 'rara-business' ); ?></button>
|
||||
<button type="button" class="button upload-button" data-label=" <?php esc_attr_e( 'Add Image', 'rara-business' ); ?>" data-alt-label="<?php esc_attr_e( 'Change Image', 'rara-business' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<?php esc_attr_e( 'Change Image', 'rara-business' ); ?>
|
||||
<# } else { #>
|
||||
<?php esc_attr_e( 'Add Image', 'rara-business' ); ?>
|
||||
<# } #>
|
||||
</button>
|
||||
<# if ( field.default.id ) { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default.id }}}" data-field="{{{ field.id }}}" >
|
||||
<# } else { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default }}}" data-field="{{{ field.id }}}" >
|
||||
<# } #>
|
||||
</div>
|
||||
|
||||
<# } else if ( field.type === 'upload' ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
</label>
|
||||
|
||||
<figure class="rara-business-file-attachment" data-placeholder="<?php esc_attr_e( 'No File Selected', 'rara-business' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<# var defaultFilename = ( field.default.filename ) ? field.default.filename : field.default; #>
|
||||
<span class="file"><span class="dashicons dashicons-media-default"></span> {{ defaultFilename }}</span>
|
||||
<# } else { #>
|
||||
<?php esc_attr_e( 'No File Selected', 'rara-business' ); ?>
|
||||
<# } #>
|
||||
</figure>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="button remove-button<# if ( ! field.default ) { #> hidden<# } #>"></button>
|
||||
<button type="button" class="button upload-button" data-label="<?php esc_attr_e( 'Add File', 'rara-business' ); ?>" data-alt-label="<?php esc_attr_e( 'Change File', 'rara-business' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<?php esc_attr_e( 'Change File', 'rara-business' ); ?>
|
||||
<# } else { #>
|
||||
<?php esc_attr_e( 'Add File', 'rara-business' ); ?>
|
||||
<# } #>
|
||||
</button>
|
||||
<# if ( field.default.id ) { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default.id }}}" data-field="{{{ field.id }}}" >
|
||||
<# } else { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default }}}" data-field="{{{ field.id }}}" >
|
||||
<# } #>
|
||||
</div>
|
||||
|
||||
<# } else if ( 'custom' === field.type ) { #>
|
||||
|
||||
<# if ( field.label ) { #>
|
||||
<span class="customize-control-title">{{ field.label }}</span>
|
||||
<# } #>
|
||||
<# if ( field.description ) { #>
|
||||
<span class="description customize-control-description">{{ field.description }}</span>
|
||||
<# } #>
|
||||
<div data-field="{{{ field.id }}}">{{{ field.default }}}</div>
|
||||
|
||||
<# } #>
|
||||
|
||||
</div>
|
||||
<# }); #>
|
||||
<button type="button" class="button-link repeater-row-remove"><?php esc_html_e( 'Remove', 'rara-business' ); ?></button>
|
||||
</div>
|
||||
</li>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate row-labels.
|
||||
*
|
||||
* @access protected
|
||||
* @since 2.4.0
|
||||
* @param array $args {@see WP_Customize_Control::__construct}.
|
||||
*/
|
||||
protected function row_label( $args ) {
|
||||
|
||||
// Validating args for row labels.
|
||||
if ( isset( $args['row_label'] ) && is_array( $args['row_label'] ) && ! empty( $args['row_label'] ) ) {
|
||||
|
||||
// Validating row label type.
|
||||
if ( isset( $args['row_label']['type'] ) && ( 'text' === $args['row_label']['type'] || 'field' === $args['row_label']['type'] ) ) {
|
||||
$this->row_label['type'] = $args['row_label']['type'];
|
||||
}
|
||||
|
||||
// Validating row label type.
|
||||
if ( isset( $args['row_label']['value'] ) && ! empty( $args['row_label']['value'] ) ) {
|
||||
$this->row_label['value'] = esc_attr( $args['row_label']['value'] );
|
||||
}
|
||||
|
||||
// Validating row label field.
|
||||
if ( isset( $args['row_label']['field'] ) && ! empty( $args['row_label']['field'] ) && isset( $args['fields'][ esc_attr( $args['row_label']['field'] ) ] ) ) {
|
||||
$this->row_label['field'] = esc_attr( $args['row_label']['field'] );
|
||||
} else {
|
||||
// If from field is not set correctly, making sure standard is set as the type.
|
||||
$this->row_label['type'] = 'text';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* Rara Business Repeater Customizer Setting.
|
||||
*
|
||||
* @package Rara_Business
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'Rara_Business_Repeater_Setting' ) ) {
|
||||
|
||||
/**
|
||||
* Repeater Settings.
|
||||
*/
|
||||
class Rara_Business_Repeater_Setting extends WP_Customize_Setting {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Any supplied $args override class property defaults.
|
||||
*
|
||||
* @access public
|
||||
* @param WP_Customize_Manager $manager The WordPress WP_Customize_Manager object.
|
||||
* @param string $id A specific ID of the setting. Can be a theme mod or option name.
|
||||
* @param array $args Setting arguments.
|
||||
*/
|
||||
public function __construct( $manager, $id, $args = array() ) {
|
||||
parent::__construct( $manager, $id, $args );
|
||||
|
||||
// Will onvert the setting from JSON to array. Must be triggered very soon.
|
||||
add_filter( "customize_sanitize_{$this->id}", array( $this, 'sanitize_repeater_setting' ), 10, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the value of the setting.
|
||||
*
|
||||
* @access public
|
||||
* @return mixed The value.
|
||||
*/
|
||||
public function value() {
|
||||
$value = parent::value();
|
||||
if ( ! is_array( $value ) ) {
|
||||
$value = array();
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the JSON encoded setting coming from Customizer to an Array.
|
||||
*
|
||||
* @access public
|
||||
* @param string $value URL Encoded JSON Value.
|
||||
* @return array
|
||||
*/
|
||||
public static function sanitize_repeater_setting( $value ){
|
||||
if ( ! is_array( $value ) ) {
|
||||
$value = json_decode( urldecode( $value ) );
|
||||
}
|
||||
$sanitized = ( empty( $value ) || ! is_array( $value ) ) ? array() : $value;
|
||||
|
||||
// Make sure that every row is an array, not an object.
|
||||
foreach ( $sanitized as $key => $_value ) {
|
||||
if ( empty( $_value ) ) {
|
||||
unset( $sanitized[ $key ] );
|
||||
} else {
|
||||
$sanitized[ $key ] = (array) $_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Reindex array.
|
||||
$sanitized = array_values( $sanitized );
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row {
|
||||
border: 1px solid #999;
|
||||
margin-top: 0.5rem;
|
||||
background: #eee;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row.minimized {
|
||||
border: 1px solid #dfdfdf;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row.minimized:hover {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row.minimized .repeater-row-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row label {
|
||||
margin-bottom: 12px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row .repeater-field.repeater-field- {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row .repeater-field.repeater-field-radio-image input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row .repeater-field.repeater-field-radio-image input img {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row .repeater-field.repeater-field-radio-image input:checked + label img {
|
||||
-webkit-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.25);
|
||||
border: 1px solid #3498DB;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-fields .repeater-row .repeater-field:last-child {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater button.repeater-add {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field {
|
||||
margin-bottom: 12px;
|
||||
width: 100%;
|
||||
clear: both;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px dotted #CCC;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field .customize-control-title {
|
||||
font-size: 13px;
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field .customize-control-description {
|
||||
font-size: 13px;
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field.repeater-field-hidden {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field-select select {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field-checkbox label {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field-checkbox input {
|
||||
line-height: 28px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-field-textarea textarea {
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-header {
|
||||
background: white;
|
||||
border: 1px solid #dfdfdf;
|
||||
position: relative;
|
||||
padding: 10px 15px;
|
||||
height: auto;
|
||||
min-height: 20px;
|
||||
line-height: 30px;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-header:hover {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-header .dashicons {
|
||||
font-size: 18px;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 2px;
|
||||
color: #a0a5aa;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-label {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
display: block;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-remove {
|
||||
color: #a00;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-row-remove:hover {
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .repeater-minimize {
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.customize-control-rara-business-repeater .remove-button,
|
||||
.customize-control-rara-business-repeater .upload-button {
|
||||
width: 48%;
|
||||
}
|
||||
|
||||
.rara-business-image-attachment {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.rara-business-image-attachment img {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.rara-business-file-attachment {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.rara-business-file-attachment .file {
|
||||
display: block;
|
||||
padding: 10px 5px;
|
||||
border: 1px dotted #c3c3c3;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.limit {
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.limit.highlight {
|
||||
background: #D32F2F;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/** Font awesome list */
|
||||
.font-group{
|
||||
text-align: center;
|
||||
height: 350px;
|
||||
overflow-y: scroll;
|
||||
position: relative;
|
||||
border: 1px solid #EEE;
|
||||
margin: 0;
|
||||
}
|
||||
.font-group li{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
margin: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
input[type="font"]{
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
@@ -0,0 +1,860 @@
|
||||
/*jshint -W065 */
|
||||
var rarabusinessRepeaterRow = function( rowIndex, container, label ){
|
||||
'use strict';
|
||||
|
||||
var self = this;
|
||||
|
||||
this.rowIndex = rowIndex;
|
||||
this.container = container;
|
||||
this.label = label;
|
||||
this.header = this.container.find( '.repeater-row-header' ),
|
||||
|
||||
this.header.on( 'click', function() {
|
||||
self.toggleMinimize();
|
||||
});
|
||||
|
||||
this.container.on( 'click', '.repeater-row-remove', function() {
|
||||
self.remove();
|
||||
});
|
||||
|
||||
this.header.on( 'mousedown', function() {
|
||||
self.container.trigger( 'row:start-dragging' );
|
||||
});
|
||||
|
||||
this.container.on( 'keyup change', 'input, select, textarea', function( e ) {
|
||||
self.container.trigger( 'row:update', [ self.rowIndex, jQuery( e.target ).data( 'field' ), e.target ] );
|
||||
});
|
||||
|
||||
this.setRowIndex = function( rowIndex ) {
|
||||
this.rowIndex = rowIndex;
|
||||
this.container.attr( 'data-row', rowIndex );
|
||||
this.container.data( 'row', rowIndex );
|
||||
this.updateLabel();
|
||||
};
|
||||
|
||||
this.toggleMinimize = function() {
|
||||
// Store the previous state.
|
||||
this.container.toggleClass( 'minimized' );
|
||||
this.header.find( '.dashicons' ).toggleClass( 'dashicons-arrow-up' ).toggleClass( 'dashicons-arrow-down' );
|
||||
};
|
||||
|
||||
this.remove = function() {
|
||||
this.container.slideUp( 300, function() {
|
||||
jQuery( this ).detach();
|
||||
});
|
||||
this.container.trigger( 'row:remove', [ this.rowIndex ] );
|
||||
};
|
||||
|
||||
this.updateLabel = function() {
|
||||
var rowLabelField,
|
||||
rowLabel;
|
||||
|
||||
if ( 'field' === this.label.type ) {
|
||||
rowLabelField = this.container.find( '.repeater-field [data-field="' + this.label.field + '"]' );
|
||||
if ( 'function' === typeof rowLabelField.val ) {
|
||||
rowLabel = rowLabelField.val();
|
||||
if ( '' !== rowLabel ) {
|
||||
this.header.find( '.repeater-row-label' ).text( rowLabel );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.header.find( '.repeater-row-label' ).text( this.label.value + ' ' + ( this.rowIndex + 1 ) );
|
||||
};
|
||||
|
||||
this.updateLabel();
|
||||
};
|
||||
|
||||
wp.customize.controlConstructor['rara-business-repeater'] = wp.customize.Control.extend({
|
||||
ready: function(){
|
||||
'use strict';
|
||||
|
||||
var control = this,
|
||||
limit,
|
||||
theNewRow;
|
||||
|
||||
// The current value set in Control Class (set in Rara_Business_Control_Repeater::to_json() function)
|
||||
var settingValue = this.params.value;
|
||||
|
||||
// The hidden field that keeps the data saved (though we never update it)
|
||||
this.settingField = this.container.find( '[data-customize-setting-link]' ).first();
|
||||
|
||||
// Set the field value for the first time, we'll fill it up later
|
||||
this.setValue( [], false );
|
||||
|
||||
// The DIV that holds all the rows
|
||||
this.repeaterFieldsContainer = this.container.find( '.repeater-fields' ).first();
|
||||
|
||||
// Set number of rows to 0
|
||||
this.currentIndex = 0;
|
||||
|
||||
// Save the rows objects
|
||||
this.rows = [];
|
||||
|
||||
// Default limit choice
|
||||
limit = false;
|
||||
if ( 'undefined' !== typeof this.params.choices.limit ) {
|
||||
limit = ( 0 >= this.params.choices.limit ) ? false : parseInt( this.params.choices.limit );
|
||||
}
|
||||
|
||||
this.container.on( 'click', 'button.repeater-add', function( e ) {
|
||||
e.preventDefault();
|
||||
if ( ! limit || control.currentIndex < limit ) {
|
||||
theNewRow = control.addRow();
|
||||
theNewRow.toggleMinimize();
|
||||
control.initColorPicker();
|
||||
//control.initDropdownPages( theNewRow );
|
||||
} else {
|
||||
jQuery( control.selector + ' .limit' ).addClass( 'highlight' );
|
||||
}
|
||||
});
|
||||
|
||||
this.container.on( 'click', '.repeater-row-remove', function( e ) {
|
||||
control.currentIndex--;
|
||||
if ( ! limit || control.currentIndex < limit ) {
|
||||
jQuery( control.selector + ' .limit' ).removeClass( 'highlight' );
|
||||
}
|
||||
});
|
||||
|
||||
this.container.on( 'click keypress', '.repeater-field-image .upload-button,.repeater-field-cropped_image .upload-button,.repeater-field-upload .upload-button', function( e ) {
|
||||
e.preventDefault();
|
||||
control.$thisButton = jQuery( this );
|
||||
control.openFrame( e );
|
||||
});
|
||||
|
||||
this.container.on( 'click keypress', '.repeater-field-image .remove-button,.repeater-field-cropped_image .remove-button', function( e ) {
|
||||
e.preventDefault();
|
||||
control.$thisButton = jQuery( this );
|
||||
control.removeImage( e );
|
||||
});
|
||||
|
||||
this.container.on( 'click keypress', '.repeater-field-upload .remove-button', function( e ) {
|
||||
e.preventDefault();
|
||||
control.$thisButton = jQuery( this );
|
||||
control.removeFile( e );
|
||||
});
|
||||
|
||||
/**
|
||||
* Function that loads the Mustache template
|
||||
*/
|
||||
this.repeaterTemplate = _.memoize( function() {
|
||||
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( control.container.find( '.customize-control-repeater-content' ).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
|
||||
if( settingValue.length ){
|
||||
_.each( settingValue, function( subValue ) {
|
||||
theNewRow = control.addRow( subValue );
|
||||
control.initColorPicker();
|
||||
//control.initDropdownPages( theNewRow, subValue );
|
||||
});
|
||||
}
|
||||
|
||||
// Once we have displayed the rows, we cleanup the values
|
||||
this.setValue( settingValue, true, true );
|
||||
|
||||
this.repeaterFieldsContainer.sortable({
|
||||
handle: '.repeater-row-header',
|
||||
update: function( e, ui ) {
|
||||
control.sort();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the media modal.
|
||||
*/
|
||||
openFrame: function( event ){
|
||||
'use strict';
|
||||
|
||||
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.$thisButton.closest( '.repeater-field' ).hasClass( 'repeater-field-cropped_image' ) ) {
|
||||
this.initCropperFrame();
|
||||
} else {
|
||||
this.initFrame();
|
||||
}
|
||||
|
||||
this.frame.open();
|
||||
},
|
||||
|
||||
initFrame: function(){
|
||||
'use strict';
|
||||
|
||||
var libMediaType = this.getMimeType();
|
||||
|
||||
this.frame = wp.media({
|
||||
states: [
|
||||
new wp.media.controller.Library({
|
||||
library: wp.media.query({ type: libMediaType }),
|
||||
multiple: false,
|
||||
date: false
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
// When a file is selected, run a callback.
|
||||
this.frame.on( 'select', 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 attachment = this.frame.state().get( 'selection' ).first().toJSON();
|
||||
|
||||
if ( this.$thisButton.closest( '.repeater-field' ).hasClass( 'repeater-field-upload' ) ) {
|
||||
this.setFileInRepeaterField( attachment );
|
||||
} else {
|
||||
this.setImageInRepeaterField( 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 $targetDiv = this.$thisButton.closest( '.repeater-field-image,.repeater-field-cropped_image' );
|
||||
|
||||
$targetDiv.find( '.rara-business-image-attachment' ).html( '<img src="' + attachment.url + '">' ).hide().slideDown( 'slow' );
|
||||
|
||||
$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( '.repeater-field-upload' );
|
||||
|
||||
$targetDiv.find( '.rara-business-file-attachment' ).html( '<span class="file"><span class="dashicons dashicons-media-default"></span> ' + attachment.filename + '</span>' ).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,
|
||||
$uploadButton;
|
||||
|
||||
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$targetDiv = this.$thisButton.closest( '.repeater-field-image,.repeater-field-cropped_image,.repeater-field-upload' );
|
||||
$uploadButton = $targetDiv.find( '.upload-button' );
|
||||
|
||||
$targetDiv.find( '.rara-business-image-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' );
|
||||
},
|
||||
|
||||
removeFile: function( event ){
|
||||
'use strict';
|
||||
|
||||
var $targetDiv,
|
||||
$uploadButton;
|
||||
|
||||
if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$targetDiv = this.$thisButton.closest( '.repeater-field-upload' );
|
||||
$uploadButton = $targetDiv.find( '.upload-button' );
|
||||
|
||||
$targetDiv.find( '.rara-business-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' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the current value of the setting
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
getValue: function(){
|
||||
'use strict';
|
||||
|
||||
// The setting is saved in JSON
|
||||
return JSON.parse( decodeURI( this.setting.get() ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 ){
|
||||
'use strict';
|
||||
|
||||
// We need to filter the values after the first load to remove data requrired for diplay but that we don't want to save in DB
|
||||
var filteredValue = newValue,
|
||||
filter = [];
|
||||
|
||||
if ( filtering ) {
|
||||
jQuery.each( this.params.fields, function( index, value ) {
|
||||
if ( 'image' === value.type || 'cropped_image' === value.type || 'upload' === value.type ) {
|
||||
filter.push( index );
|
||||
}
|
||||
});
|
||||
jQuery.each( newValue, function( index, value ) {
|
||||
jQuery.each( filter, function( ind, field ) {
|
||||
if ( 'undefined' !== typeof value[field] && 'undefined' !== typeof value[field].id ) {
|
||||
filteredValue[index][field] = value[field].id;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.setting.set( encodeURI( JSON.stringify( filteredValue ) ) );
|
||||
|
||||
if ( refresh ) {
|
||||
// Trigger the change event on the hidden field so
|
||||
// previewer refresh the website on Customizer
|
||||
this.settingField.trigger( 'change' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
addRow: function( data ){
|
||||
'use strict';
|
||||
|
||||
var control = this,
|
||||
template = control.repeaterTemplate(), // The template for the new row (defined on Rara_Business_Control_Repeater::render_content() ).
|
||||
settingValue = this.getValue(), // Get the current setting value.
|
||||
newRowSetting = {}, // Saves the new setting data.
|
||||
templateData, // Data to pass to the template
|
||||
newRow,
|
||||
i;
|
||||
|
||||
if ( template ) {
|
||||
|
||||
// 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 );
|
||||
|
||||
// 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 ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templateData.index = this.currentIndex;
|
||||
|
||||
// Append the template content
|
||||
template = template( templateData );
|
||||
|
||||
// Create a new row object and append the element
|
||||
newRow = new rarabusinessRepeaterRow(
|
||||
control.currentIndex,
|
||||
jQuery( template ).appendTo( control.repeaterFieldsContainer ),
|
||||
control.params.row_label
|
||||
);
|
||||
|
||||
newRow.container.on( 'row:remove', function( e, rowIndex ) {
|
||||
control.deleteRow( rowIndex );
|
||||
});
|
||||
|
||||
newRow.container.on( 'row:update', function( e, rowIndex, fieldName, element ) {
|
||||
control.updateField.call( control, e, rowIndex, fieldName, element );
|
||||
newRow.updateLabel();
|
||||
});
|
||||
|
||||
// Add the row to rows collection
|
||||
this.rows[ this.currentIndex ] = newRow;
|
||||
|
||||
for ( i in templateData ) {
|
||||
if ( templateData.hasOwnProperty( i ) ) {
|
||||
newRowSetting[ i ] = templateData[ i ]['default'];
|
||||
}
|
||||
}
|
||||
|
||||
settingValue[ this.currentIndex ] = newRowSetting;
|
||||
this.setValue( settingValue, true );
|
||||
|
||||
this.currentIndex++;
|
||||
|
||||
return newRow;
|
||||
}
|
||||
},
|
||||
|
||||
sort: function(){
|
||||
'use strict';
|
||||
|
||||
var control = this,
|
||||
$rows = this.repeaterFieldsContainer.find( '.repeater-row' ),
|
||||
newOrder = [],
|
||||
settings = control.getValue(),
|
||||
newRows = [],
|
||||
newSettings = [];
|
||||
|
||||
$rows.each( function( i, element ) {
|
||||
newOrder.push( jQuery( element ).data( 'row' ) );
|
||||
});
|
||||
|
||||
jQuery.each( newOrder, function( newPosition, oldPosition ) {
|
||||
newRows[ newPosition ] = control.rows[ oldPosition ];
|
||||
newRows[ newPosition ].setRowIndex( newPosition );
|
||||
|
||||
newSettings[ newPosition ] = settings[ oldPosition ];
|
||||
});
|
||||
|
||||
control.rows = newRows;
|
||||
control.setValue( newSettings );
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete a row in the repeater setting
|
||||
*
|
||||
* @param index Position of the row in the complete Setting Array
|
||||
*/
|
||||
deleteRow: function( index ){
|
||||
'use strict';
|
||||
|
||||
var currentSettings = this.getValue(),
|
||||
row,
|
||||
i,
|
||||
prop;
|
||||
|
||||
if ( currentSettings[ index ] ) {
|
||||
|
||||
// Find the row
|
||||
row = this.rows[ index ];
|
||||
if ( row ) {
|
||||
|
||||
// The row exists, let's delete it
|
||||
|
||||
// Remove the row settings
|
||||
delete currentSettings[ index ];
|
||||
|
||||
// Remove the row from the rows collection
|
||||
delete this.rows[ index ];
|
||||
|
||||
// Update the new setting values
|
||||
this.setValue( currentSettings, true );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remap the row numbers
|
||||
i = 1;
|
||||
for ( prop in this.rows ) {
|
||||
if ( this.rows.hasOwnProperty( prop ) && this.rows[ prop ] ) {
|
||||
this.rows[ prop ].updateLabel();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a single field inside a row.
|
||||
* Triggered when a field has changed
|
||||
*
|
||||
* @param e Event Object
|
||||
*/
|
||||
updateField: function( e, rowIndex, fieldId, element ){
|
||||
'use strict';
|
||||
|
||||
var type,
|
||||
row,
|
||||
currentSettings;
|
||||
|
||||
if ( ! this.rows[ rowIndex ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! this.params.fields[ fieldId ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
type = this.params.fields[ fieldId].type;
|
||||
row = this.rows[ rowIndex ];
|
||||
currentSettings = this.getValue();
|
||||
|
||||
element = jQuery( element );
|
||||
|
||||
if ( 'undefined' === typeof currentSettings[ row.rowIndex ][ fieldId ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'checkbox' === type ) {
|
||||
|
||||
currentSettings[ row.rowIndex ][ fieldId ] = element.is( ':checked' );
|
||||
|
||||
} else {
|
||||
|
||||
// Update the settings
|
||||
currentSettings[ row.rowIndex ][ fieldId ] = element.val();
|
||||
|
||||
}
|
||||
this.setValue( currentSettings, true );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init the color picker on color fields
|
||||
* Called after AddRow
|
||||
*
|
||||
*/
|
||||
initColorPicker: function(){
|
||||
'use strict';
|
||||
|
||||
var control = this,
|
||||
colorPicker = control.container.find( '.color-picker-hex' ),
|
||||
options = {},
|
||||
fieldId = colorPicker.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;
|
||||
}
|
||||
|
||||
// When the color picker value is changed we update the value of the field
|
||||
options.change = function( event, ui ) {
|
||||
|
||||
var currentPicker = jQuery( event.target ),
|
||||
row = currentPicker.closest( '.repeater-row' ),
|
||||
rowIndex = row.data( 'row' ),
|
||||
currentSettings = control.getValue();
|
||||
|
||||
currentSettings[ rowIndex ][ currentPicker.data( 'field' ) ] = ui.color.toString();
|
||||
control.setValue( currentSettings, true );
|
||||
|
||||
};
|
||||
|
||||
// Init the color picker
|
||||
if ( 0 !== colorPicker.length ) {
|
||||
colorPicker.wpColorPicker( options );
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
jQuery( document ).ready(function($){
|
||||
'use strict';
|
||||
$(document).on('click','.repeater-add',function() {
|
||||
$('.repeater-field').find('input[type="font"]').attr('placeholder','search icons');
|
||||
});
|
||||
|
||||
$(document).on( 'click', 'input[type="font"]', function(){
|
||||
var $this = $(this);
|
||||
if( ( ! $this.hasClass('ajax-running') ) && $this.siblings( '.font-awesome-list' ).length < 1 ){
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url : ajaxurl,
|
||||
data: {
|
||||
action : 'rara_business_get_fontawesome_ajax',
|
||||
rara_business_customize_nonce: rara_business_customize.nonce
|
||||
},
|
||||
beforeSend: function(){
|
||||
$this.addClass('ajax-running');
|
||||
},
|
||||
success: function (response) {
|
||||
var html = '<div class="font-awesome-list">'+response+'</div>';
|
||||
$this.after(html);
|
||||
$this.removeClass('ajax-running');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on( 'click', '.font-group li', function(event){
|
||||
var val = $(this).data( 'font' );
|
||||
$(this).parent().parent().siblings( 'input[type="font"]' ).val( val );
|
||||
$(this).parent().parent().siblings( 'input[type="font"]' ).trigger( 'change' );
|
||||
$(this).parent().parent().fadeOut( 'slow', function(){
|
||||
$(this).remove();
|
||||
});
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
$(document).on( 'keyup', 'input[type="font"]', function(){
|
||||
var value = $(this).val();
|
||||
var matcher = new RegExp( value, 'gi' );
|
||||
$(this).next( '.font-awesome-list' ).children('.font-group').children( 'li' ).show().not(function(){
|
||||
return matcher.test( $(this).find( 'svg' ).attr( 'class' ) );
|
||||
}).hide();
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user