Closed rinkuyadav999 closed 5 years ago
class Color_Picker_Widget_25809 extends WP_Widget {
/**
* Widget constructor.
*
* @since 1.0
*
* @access public
*/
public function __construct() {
parent::__construct(
'color-picker',
_x( 'Color Picker', 'widget title', 'color-picker-widget' ),
array(
'classname' => 'color-picker-widget',
'description' => _x( 'Widget with a color picker', 'widget description', 'color-picker-widget' )
)
);
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'admin_footer-widgets.php', array( $this, 'print_scripts' ), 9999 );
}
/**
* Enqueue scripts.
*
* @since 1.0
*
* @param string $hook_suffix
*/
public function enqueue_scripts( $hook_suffix ) {
if ( 'widgets.php' !== $hook_suffix ) {
return;
}
wp_enqueue_style( 'wp-color-picker' );
wp_enqueue_script( 'wp-color-picker' );
wp_enqueue_script( 'underscore' );
}
/**
* Print scripts.
*
* @since 1.0
*/
public function print_scripts() {
?>
<script>
( function( $ ){
function initColorPicker( widget ) {
widget.find( '.color-picker' ).wpColorPicker( {
change: _.throttle( function() { // For Customizer
$(this).trigger( 'change' );
}, 3000 )
});
}
function onFormUpdate( event, widget ) {
initColorPicker( widget );
}
$( document ).on( 'widget-added widget-updated', onFormUpdate );
$( document ).ready( function() {
$( '#widgets-right .widget:has(.color-picker)' ).each( function () {
initColorPicker( $( this ) );
} );
} );
}( jQuery ) );
/**!
* wp-color-picker-alpha
*
* Overwrite Automattic Iris for enabled Alpha Channel in wpColorPicker
* Only run in input and is defined data alpha in true
*
* Version: 2.1.3
* https://github.com/kallookoo/wp-color-picker-alpha
* Licensed under the GPLv2 license.
*/
( function( $ ) {
// Prevent double-init.
if ( $.wp.wpColorPicker.prototype._hasAlpha ) {
return;
}
// Variable for some backgrounds ( grid )
var image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAAHnlligAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHJJREFUeNpi+P///4EDBxiAGMgCCCAGFB5AADGCRBgYDh48CCRZIJS9vT2QBAggFBkmBiSAogxFBiCAoHogAKIKAlBUYTELAiAmEtABEECk20G6BOmuIl0CIMBQ/IEMkO0myiSSraaaBhZcbkUOs0HuBwDplz5uFJ3Z4gAAAABJRU5ErkJggg==',
// html stuff for wpColorPicker copy of the original color-picker.js
_after = '<div class="wp-picker-holder" />',
_wrap = '<div class="wp-picker-container" />',
_button = '<input type="button" class="button button-small" />',
// Prevent CSS issues in < WordPress 4.9
_deprecated = ( wpColorPickerL10n.current !== undefined );
// Declare some global variables when is deprecated or not
if ( _deprecated ) {
var _before = '<a tabindex="0" class="wp-color-result" />';
} else {
var _before = '<button type="button" class="button wp-color-result" aria-expanded="false"><span class="wp-color-result-text"></span></button>',
_wrappingLabel = '<label></label>',
_wrappingLabelText = '<span class="screen-reader-text"></span>';
}
/**
* Overwrite Color
* for enable support rbga
*/
Color.fn.toString = function() {
if ( this._alpha < 1 )
return this.toCSS( 'rgba', this._alpha ).replace( /\s+/g, '' );
var hex = parseInt( this._color, 10 ).toString( 16 );
if ( this.error )
return '';
if ( hex.length < 6 )
hex = ( '00000' + hex ).substr( -6 );
return '#' + hex;
};
/**
* Overwrite wpColorPicker
*/
$.widget( 'wp.wpColorPicker', $.wp.wpColorPicker, {
_hasAlpha: true,
/**
* @summary Creates the color picker.
*
* Creates the color picker, sets default values, css classes and wraps it all in HTML.
*
* @since 3.5.0
*
* @access private
*
* @returns {void}
*/
_create: function() {
// Return early if Iris support is missing.
if ( ! $.support.iris ) {
return;
}
var self = this,
el = self.element;
// Override default options with options bound to the element.
$.extend( self.options, el.data() );
// Create a color picker which only allows adjustments to the hue.
if ( self.options.type === 'hue' ) {
return self._createHueOnly();
}
// Bind the close event.
self.close = $.proxy( self.close, self );
self.initialValue = el.val();
// Add a CSS class to the input field.
el.addClass( 'wp-color-picker' );
if ( _deprecated ) {
el.hide().wrap( _wrap );
self.wrap = el.parent();
self.toggler = $( _before )
.insertBefore( el )
.css( { backgroundColor : self.initialValue } )
.attr( 'title', wpColorPickerL10n.pick )
.attr( 'data-current', wpColorPickerL10n.current );
self.pickerContainer = $( _after ).insertAfter( el );
self.button = $( _button ).addClass('hidden');
} else {
/*
* Check if there's already a wrapping label, e.g. in the Customizer.
* If there's no label, add a default one to match the Customizer template.
*/
if ( ! el.parent( 'label' ).length ) {
// Wrap the input field in the default label.
el.wrap( _wrappingLabel );
// Insert the default label text.
self.wrappingLabelText = $( _wrappingLabelText )
.insertBefore( el )
.text( wpColorPickerL10n.defaultLabel );
}
/*
* At this point, either it's the standalone version or the Customizer
* one, we have a wrapping label to use as hook in the DOM, let's store it.
*/
self.wrappingLabel = el.parent();
// Wrap the label in the main wrapper.
self.wrappingLabel.wrap( _wrap );
// Store a reference to the main wrapper.
self.wrap = self.wrappingLabel.parent();
// Set up the toggle button and insert it before the wrapping label.
self.toggler = $( _before )
.insertBefore( self.wrappingLabel )
.css( { backgroundColor: self.initialValue } );
// Set the toggle button span element text.
self.toggler.find( '.wp-color-result-text' ).text( wpColorPickerL10n.pick );
// Set up the Iris container and insert it after the wrapping label.
self.pickerContainer = $( _after ).insertAfter( self.wrappingLabel );
// Store a reference to the Clear/Default button.
self.button = $( _button );
}
// Set up the Clear/Default button.
if ( self.options.defaultColor ) {
self.button.addClass( 'wp-picker-default' ).val( wpColorPickerL10n.defaultString );
if ( ! _deprecated ) {
self.button.attr( 'aria-label', wpColorPickerL10n.defaultAriaLabel );
}
} else {
self.button.addClass( 'wp-picker-clear' ).val( wpColorPickerL10n.clear );
if ( ! _deprecated ) {
self.button.attr( 'aria-label', wpColorPickerL10n.clearAriaLabel );
}
}
if ( _deprecated ) {
el.wrap( '<span class="wp-picker-input-wrap" />' ).after( self.button );
} else {
// Wrap the wrapping label in its wrapper and append the Clear/Default button.
self.wrappingLabel
.wrap( '<span class="wp-picker-input-wrap hidden" />' )
.after( self.button );
/*
* The input wrapper now contains the label+input+Clear/Default button.
* Store a reference to the input wrapper: we'll use this to toggle
* the controls visibility.
*/
self.inputWrapper = el.closest( '.wp-picker-input-wrap' );
}
el.iris( {
target: self.pickerContainer,
hide: self.options.hide,
width: self.options.width,
mode: self.options.mode,
palettes: self.options.palettes,
/**
* @summary Handles the onChange event if one has been defined in the options.
*
* Handles the onChange event if one has been defined in the options and additionally
* sets the background color for the toggler element.
*
* @since 3.5.0
*
* @param {Event} event The event that's being called.
* @param {HTMLElement} ui The HTMLElement containing the color picker.
*
* @returns {void}
*/
change: function( event, ui ) {
if ( self.options.alpha ) {
self.toggler.css( { 'background-image' : 'url(' + image + ')' } );
if ( _deprecated ) {
self.toggler.html( '<span class="color-alpha" />' );
} else {
self.toggler.css( {
'position' : 'relative'
} );
if ( self.toggler.find('span.color-alpha').length == 0 ) {
self.toggler.append('<span class="color-alpha" />');
}
}
self.toggler.find( 'span.color-alpha' ).css( {
'width' : '30px',
'height' : '24px',
'position' : 'absolute',
'top' : 0,
'left' : 0,
'border-top-left-radius' : '2px',
'border-bottom-left-radius' : '2px',
'background' : ui.color.toString()
} );
} else {
self.toggler.css( { backgroundColor : ui.color.toString() } );
}
if ( $.isFunction( self.options.change ) ) {
self.options.change.call( this, event, ui );
}
}
} );
el.val( self.initialValue );
self._addListeners();
// Force the color picker to always be closed on initial load.
if ( ! self.options.hide ) {
self.toggler.click();
}
},
/**
* @summary Binds event listeners to the color picker.
*
* @since 3.5.0
*
* @access private
*
* @returns {void}
*/
_addListeners: function() {
var self = this;
/**
* @summary Prevent any clicks inside this widget from leaking to the top and closing it.
*
* @since 3.5.0
*
* @param {Event} event The event that's being called.
*
* @returs {void}
*/
self.wrap.on( 'click.wpcolorpicker', function( event ) {
event.stopPropagation();
});
/**
* @summary Open or close the color picker depending on the class.
*
* @since 3.5
*/
self.toggler.click( function(){
if ( self.toggler.hasClass( 'wp-picker-open' ) ) {
self.close();
} else {
self.open();
}
});
/**
* @summary Checks if value is empty when changing the color in the color picker.
*
* Checks if value is empty when changing the color in the color picker.
* If so, the background color is cleared.
*
* @since 3.5.0
*
* @param {Event} event The event that's being called.
*
* @returns {void}
*/
self.element.on( 'change', function( event ) {
// Empty or Error = clear
if ( $( this ).val() === '' || self.element.hasClass( 'iris-error' ) ) {
if ( self.options.alpha ) {
if ( _deprecated ) {
self.toggler.removeAttr( 'style' );
}
self.toggler.find( 'span.color-alpha' ).css( 'backgroundColor', '' );
} else {
self.toggler.css( 'backgroundColor', '' );
}
// fire clear callback if we have one
if ( $.isFunction( self.options.clear ) )
self.options.clear.call( this, event );
}
} );
/**
* @summary Enables the user to clear or revert the color in the color picker.
*
* Enables the user to either clear the color in the color picker or revert back to the default color.
*
* @since 3.5.0
*
* @param {Event} event The event that's being called.
*
* @returns {void}
*/
self.button.on( 'click', function( event ) {
if ( $( this ).hasClass( 'wp-picker-clear' ) ) {
self.element.val( '' );
if ( self.options.alpha ) {
if ( _deprecated ) {
self.toggler.removeAttr( 'style' );
}
self.toggler.find( 'span.color-alpha' ).css( 'backgroundColor', '' );
} else {
self.toggler.css( 'backgroundColor', '' );
}
if ( $.isFunction( self.options.clear ) )
self.options.clear.call( this, event );
self.element.trigger( 'change' );
} else if ( $( this ).hasClass( 'wp-picker-default' ) ) {
self.element.val( self.options.defaultColor ).change();
}
});
},
});
/**
* Overwrite iris
*/
$.widget( 'a8c.iris', $.a8c.iris, {
_create: function() {
this._super();
// Global option for check is mode rbga is enabled
this.options.alpha = this.element.data( 'alpha' ) || false;
// Is not input disabled
if ( ! this.element.is( ':input' ) )
this.options.alpha = false;
if ( typeof this.options.alpha !== 'undefined' && this.options.alpha ) {
var self = this,
el = self.element,
_html = '<div class="iris-strip iris-slider iris-alpha-slider"><div class="iris-slider-offset iris-slider-offset-alpha"></div></div>',
aContainer = $( _html ).appendTo( self.picker.find( '.iris-picker-inner' ) ),
aSlider = aContainer.find( '.iris-slider-offset-alpha' ),
controls = {
aContainer : aContainer,
aSlider : aSlider
};
if ( typeof el.data( 'custom-width' ) !== 'undefined' ) {
self.options.customWidth = parseInt( el.data( 'custom-width' ) ) || 0;
} else {
self.options.customWidth = 100;
}
// Set default width for input reset
self.options.defaultWidth = el.width();
// Update width for input
if ( self._color._alpha < 1 || self._color.toString().indexOf('rgb') != -1 )
el.width( parseInt( self.options.defaultWidth + self.options.customWidth ) );
// Push new controls
$.each( controls, function( k, v ) {
self.controls[k] = v;
} );
// Change size strip and add margin for sliders
self.controls.square.css( { 'margin-right': '0' } );
var emptyWidth = ( self.picker.width() - self.controls.square.width() - 20 ),
stripsMargin = ( emptyWidth / 6 ),
stripsWidth = ( ( emptyWidth / 2 ) - stripsMargin );
$.each( [ 'aContainer', 'strip' ], function( k, v ) {
self.controls[v].width( stripsWidth ).css( { 'margin-left' : stripsMargin + 'px' } );
} );
// Add new slider
self._initControls();
// For updated widget
self._change();
}
},
_initControls: function() {
this._super();
if ( this.options.alpha ) {
var self = this,
controls = self.controls;
controls.aSlider.slider({
orientation : 'vertical',
min : 0,
max : 100,
step : 1,
value : parseInt( self._color._alpha * 100 ),
slide : function( event, ui ) {
// Update alpha value
self._color._alpha = parseFloat( ui.value / 100 );
self._change.apply( self, arguments );
}
});
}
},
_change: function() {
this._super();
var self = this,
el = self.element;
if ( this.options.alpha ) {
var controls = self.controls,
alpha = parseInt( self._color._alpha * 100 ),
color = self._color.toRgb(),
gradient = [
'rgb(' + color.r + ',' + color.g + ',' + color.b + ') 0%',
'rgba(' + color.r + ',' + color.g + ',' + color.b + ', 0) 100%'
],
defaultWidth = self.options.defaultWidth,
customWidth = self.options.customWidth,
target = self.picker.closest( '.wp-picker-container' ).find( '.wp-color-result' );
// Generate background slider alpha, only for CSS3 old browser fuck!! :)
controls.aContainer.css( { 'background' : 'linear-gradient(to bottom, ' + gradient.join( ', ' ) + '), url(' + image + ')' } );
if ( target.hasClass( 'wp-picker-open' ) ) {
// Update alpha value
controls.aSlider.slider( 'value', alpha );
/**
* Disabled change opacity in default slider Saturation ( only is alpha enabled )
* and change input width for view all value
*/
if ( self._color._alpha < 1 ) {
controls.strip.attr( 'style', controls.strip.attr( 'style' ).replace( /rgba\(([0-9]+,)(\s+)?([0-9]+,)(\s+)?([0-9]+)(,(\s+)?[0-9\.]+)\)/g, 'rgb($1$3$5)' ) );
el.width( parseInt( defaultWidth + customWidth ) );
} else {
el.width( defaultWidth );
}
}
}
var reset = el.data( 'reset-alpha' ) || false;
if ( reset ) {
self.picker.find( '.iris-palette-container' ).on( 'click.palette', '.iris-palette', function() {
self._color._alpha = 1;
self.active = 'external';
self._change();
} );
}
el.trigger( 'change' );
},
_addInputListeners: function( input ) {
var self = this,
debounceTimeout = 100,
callback = function( event ) {
var color = new Color( input.val() ),
val = input.val();
input.removeClass( 'iris-error' );
// we gave a bad color
if ( color.error ) {
// don't error on an empty input
if ( val !== '' )
input.addClass( 'iris-error' );
} else {
if ( color.toString() !== self._color.toString() ) {
// let's not do this on keyup for hex shortcodes
if ( ! ( event.type === 'keyup' && val.match( /^[0-9a-fA-F]{3}$/ ) ) )
self._setOption( 'color', color.toString() );
}
}
};
input.on( 'change', callback ).on( 'keyup', self._debounce( callback, debounceTimeout ) );
// If we initialized hidden, show on first focus. The rest is up to you.
if ( self.options.hide ) {
input.on( 'focus', function() {
self.show();
} );
}
}
} );
}( jQuery ) );
</script>
<?php
}
/**
* Widget output.
*
* @since 1.0
*
* @access public
* @param array $args
* @param array $instance
*/
public function widget( $args, $instance ) {
extract( $args );
// Title
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : _x( 'Color Picker', 'widget title', 'color-picker-widget' );
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
// Colors
$color1 = ( ! empty( $instance['color1'] ) ) ? $instance['color1'] : '#fff';
$color2 = ( ! empty( $instance['color2'] ) ) ? $instance['color2'] : '#f00';
echo $before_widget;
if ( $title )
echo $before_title . $title . $after_title;
?>
<div style="height: 100px; width: 100%; background-color:<?php echo $color1; ?>"></div>
<div style="height: 100px; width: 100%; background-color:<?php echo $color2; ?>"></div>
<?php
echo $after_widget;
}
/**
* Saves widget settings.
*
* @since 1.0
*
* @access public
* @param array $new_instance
* @param array $old_instance
* @return array
*/
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance[ 'title' ] = strip_tags( $new_instance['title'] );
$instance[ 'color1' ] = strip_tags( $new_instance['color1'] );
$instance[ 'color2' ] = strip_tags( $new_instance['color2'] );
return $instance;
}
/**
* Prints the settings form.
*
* @since 1.0
*
* @access public
* @param array $instance
*/
public function form( $instance ) {
// Defaults
$instance = wp_parse_args(
$instance,
array(
'title' => _x( 'Color Picker', 'widget title', 'color-picker-widget' ),
'color1' => '',
'color2' => ''
)
);
$title = esc_attr( $instance[ 'title' ] );
$color1 = esc_attr( $instance[ 'color1' ] );
$color2 = esc_attr( $instance[ 'color2' ] );
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
</p>
<p>
<label for="<?php echo $this->get_field_id( 'color1' ); ?>"><?php _e( 'Color 1:' ); ?></label><br>
<input type="text" name="<?php echo $this->get_field_name( 'color1' ); ?>" class="color-picker" id="<?php echo $this->get_field_id( 'color1' ); ?>" value="<?php echo $color1; ?>" data-default-color="#fff" data-alpha="true" />
</p>
<p>
<label for="<?php echo $this->get_field_id( 'color2' ); ?>"><?php _e( 'Color 2:' ); ?></label><br>
<input type="text" name="<?php echo $this->get_field_name( 'color2' ); ?>" class="color-picker" id="<?php echo $this->get_field_id( 'color2' ); ?>" value="<?php echo $color2; ?>" data-default-color="#f00" data-alpha="true" />
</p>
<?php
}
}
add_action( 'widgets_init', function() {
register_widget( 'Color_Picker_Widget_25809' );
} );
Hi. Any news about this issue? Problem is that on _init, at the end self._change() called. Inside self._change() trigger('change') is called that calls default widget change function and that's why save isn't changed to saved, because widget thinks that some property has value changed.
Seeing the code I think it's not a bug, basically for how the code is written.
HI kallookoo,
thanks on quick answer. Here is the video showing the issue https://www.screencast.com/t/77bakoIH As you can see, problem is that button for save is never in disabled state with saved label. Also, remove label is not shown. Maybe the biggest problem is that when you use colorpicker with alpha on widget page, when you want to navigate off, confirmation dialog is displayed on top of the window and users get confused, everything is saved, but confirmation dialog is displayed. Could you please consider some improvement regarding this?
Thanks in advance, Uros
When use wpColorPicker and this wp-color-picker-alpha for color setting inside widget, it saves data but do not change 'Save' button to 'Saved'. Seems there is js issue in wp-color-picker-alpha.
When remove wp-color-picker-alpha from setting, it display color picker and 'Save' button changes to 'Saved'.