Improve/introduce Customizer JavaScript models for Controls, Sections, and Panels.
* Introduce models for panels and sections. * Introduce API to expand and focus a control, section or panel. * Allow deep-linking to panels, sections, and controls inside of the Customizer. * Clean up `accordion.js`, removing all Customizer-specific logic. * Add initial unit tests for `wp.customize.Class` in `customize-base.js`. https://make.wordpress.org/core/2014/10/27/toward-a-complete-javascript-api-for-the-customizer/ provides an overview of how to use the JavaScript API. props westonruter, celloexpressions, ryankienstra. see #28032, #28579, #28580, #28650, #28709, #29758. fixes #29529. Built from https://develop.svn.wordpress.org/trunk@30102 git-svn-id: http://core.svn.wordpress.org/trunk@30102 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
63cf4db8ae
commit
3c962ee5d8
|
@ -53,8 +53,6 @@ do_action( 'customize_controls_init' );
|
||||||
wp_enqueue_script( 'customize-controls' );
|
wp_enqueue_script( 'customize-controls' );
|
||||||
wp_enqueue_style( 'customize-controls' );
|
wp_enqueue_style( 'customize-controls' );
|
||||||
|
|
||||||
wp_enqueue_script( 'accordion' );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue Customizer control scripts.
|
* Enqueue Customizer control scripts.
|
||||||
*
|
*
|
||||||
|
@ -130,7 +128,7 @@ do_action( 'customize_controls_print_scripts' );
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="widgets-right"><!-- For Widget Customizer, many widgets try to look for instances under div#widgets-right, so we have to add that ID to a container div in the Customizer for compat -->
|
<div id="widgets-right"><!-- For Widget Customizer, many widgets try to look for instances under div#widgets-right, so we have to add that ID to a container div in the Customizer for compat -->
|
||||||
<div class="wp-full-overlay-sidebar-content accordion-container" tabindex="-1">
|
<div class="wp-full-overlay-sidebar-content" tabindex="-1">
|
||||||
<div id="customize-info" class="accordion-section <?php if ( $cannot_expand ) echo ' cannot-expand'; ?>">
|
<div id="customize-info" class="accordion-section <?php if ( $cannot_expand ) echo ' cannot-expand'; ?>">
|
||||||
<div class="accordion-section-title" aria-label="<?php esc_attr_e( 'Customizer Options' ); ?>" tabindex="0">
|
<div class="accordion-section-title" aria-label="<?php esc_attr_e( 'Customizer Options' ); ?>" tabindex="0">
|
||||||
<span class="preview-notice"><?php
|
<span class="preview-notice"><?php
|
||||||
|
@ -160,13 +158,9 @@ do_action( 'customize_controls_print_scripts' );
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="customize-theme-controls"><ul>
|
<div id="customize-theme-controls">
|
||||||
<?php
|
<ul><?php // Panels and sections are managed here via JavaScript ?></ul>
|
||||||
foreach ( $wp_customize->containers() as $container ) {
|
</div>
|
||||||
$container->maybe_render();
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</ul></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -252,10 +246,13 @@ do_action( 'customize_controls_print_scripts' );
|
||||||
),
|
),
|
||||||
'settings' => array(),
|
'settings' => array(),
|
||||||
'controls' => array(),
|
'controls' => array(),
|
||||||
|
'panels' => array(),
|
||||||
|
'sections' => array(),
|
||||||
'nonce' => array(
|
'nonce' => array(
|
||||||
'save' => wp_create_nonce( 'save-customize_' . $wp_customize->get_stylesheet() ),
|
'save' => wp_create_nonce( 'save-customize_' . $wp_customize->get_stylesheet() ),
|
||||||
'preview' => wp_create_nonce( 'preview-customize_' . $wp_customize->get_stylesheet() )
|
'preview' => wp_create_nonce( 'preview-customize_' . $wp_customize->get_stylesheet() )
|
||||||
),
|
),
|
||||||
|
'autofocus' => array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prepare Customize Setting objects to pass to Javascript.
|
// Prepare Customize Setting objects to pass to Javascript.
|
||||||
|
@ -266,10 +263,32 @@ do_action( 'customize_controls_print_scripts' );
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare Customize Control objects to pass to Javascript.
|
// Prepare Customize Control objects to pass to JavaScript.
|
||||||
foreach ( $wp_customize->controls() as $id => $control ) {
|
foreach ( $wp_customize->controls() as $id => $control ) {
|
||||||
$control->to_json();
|
$settings['controls'][ $id ] = $control->json();
|
||||||
$settings['controls'][ $id ] = $control->json;
|
}
|
||||||
|
|
||||||
|
// Prepare Customize Section objects to pass to JavaScript.
|
||||||
|
foreach ( $wp_customize->sections() as $id => $section ) {
|
||||||
|
$settings['sections'][ $id ] = $section->json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare Customize Panel objects to pass to JavaScript.
|
||||||
|
foreach ( $wp_customize->panels() as $id => $panel ) {
|
||||||
|
$settings['panels'][ $id ] = $panel->json();
|
||||||
|
foreach ( $panel->sections as $section_id => $section ) {
|
||||||
|
$settings['sections'][ $section_id ] = $section->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass to frontend the Customizer construct being deeplinked
|
||||||
|
if ( isset( $_GET['autofocus'] ) && is_array( $_GET['autofocus'] ) ) {
|
||||||
|
$autofocus = wp_unslash( $_GET['autofocus'] );
|
||||||
|
foreach ( $autofocus as $type => $id ) {
|
||||||
|
if ( isset( $settings[ $type . 's' ][ $id ] ) ) {
|
||||||
|
$settings['autofocus'][ $type ] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
*
|
*
|
||||||
* Note that any appropriate tags may be used, as long as the above classes are present.
|
* Note that any appropriate tags may be used, as long as the above classes are present.
|
||||||
*
|
*
|
||||||
* In addition to the standard accordion behavior, this file includes JS for the
|
|
||||||
* Customizer's "Panel" functionality.
|
|
||||||
*
|
|
||||||
* @since 3.6.0.
|
* @since 3.6.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -46,19 +43,7 @@
|
||||||
accordionSwitch( $( this ) );
|
accordionSwitch( $( this ) );
|
||||||
});
|
});
|
||||||
|
|
||||||
// Go back to the top-level Customizer accordion.
|
|
||||||
$( '#customize-header-actions' ).on( 'click keydown', '.control-panel-back', function( e ) {
|
|
||||||
if ( e.type === 'keydown' && 13 !== e.which ) { // "return" key
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault(); // Keep this AFTER the key filter above
|
|
||||||
|
|
||||||
panelSwitch( $( '.current-panel' ) );
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
var sectionContent = $( '.accordion-section-content' );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the current accordion section and open a new one.
|
* Close the current accordion section and open a new one.
|
||||||
|
@ -69,75 +54,22 @@
|
||||||
function accordionSwitch ( el ) {
|
function accordionSwitch ( el ) {
|
||||||
var section = el.closest( '.accordion-section' ),
|
var section = el.closest( '.accordion-section' ),
|
||||||
siblings = section.closest( '.accordion-container' ).find( '.open' ),
|
siblings = section.closest( '.accordion-container' ).find( '.open' ),
|
||||||
content = section.find( sectionContent );
|
content = section.find( '.accordion-section-content' );
|
||||||
|
|
||||||
// This section has no content and cannot be expanded.
|
// This section has no content and cannot be expanded.
|
||||||
if ( section.hasClass( 'cannot-expand' ) ) {
|
if ( section.hasClass( 'cannot-expand' ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slide into a sub-panel instead of accordioning (Customizer-specific).
|
|
||||||
if ( section.hasClass( 'control-panel' ) ) {
|
|
||||||
panelSwitch( section );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( section.hasClass( 'open' ) ) {
|
if ( section.hasClass( 'open' ) ) {
|
||||||
section.toggleClass( 'open' );
|
section.toggleClass( 'open' );
|
||||||
content.toggle( true ).slideToggle( 150 );
|
content.toggle( true ).slideToggle( 150 );
|
||||||
} else {
|
} else {
|
||||||
siblings.removeClass( 'open' );
|
siblings.removeClass( 'open' );
|
||||||
siblings.find( sectionContent ).show().slideUp( 150 );
|
siblings.find( '.accordion-section-content' ).show().slideUp( 150 );
|
||||||
content.toggle( false ).slideToggle( 150 );
|
content.toggle( false ).slideToggle( 150 );
|
||||||
section.toggleClass( 'open' );
|
section.toggleClass( 'open' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Slide into an accordion sub-panel.
|
|
||||||
*
|
|
||||||
* For the Customizer-specific panel functionality
|
|
||||||
*
|
|
||||||
* @param {Object} panel Title element or back button of the accordion panel to toggle.
|
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
|
||||||
function panelSwitch( panel ) {
|
|
||||||
var position, scroll,
|
|
||||||
section = panel.closest( '.accordion-section' ),
|
|
||||||
overlay = section.closest( '.wp-full-overlay' ),
|
|
||||||
container = section.closest( '.accordion-container' ),
|
|
||||||
siblings = container.find( '.open' ),
|
|
||||||
topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ).add( '#customize-info > .accordion-section-title' ),
|
|
||||||
backBtn = overlay.find( '.control-panel-back' ),
|
|
||||||
panelTitle = section.find( '.accordion-section-title' ).first(),
|
|
||||||
content = section.find( '.control-panel-content' );
|
|
||||||
|
|
||||||
if ( section.hasClass( 'current-panel' ) ) {
|
|
||||||
section.toggleClass( 'current-panel' );
|
|
||||||
overlay.toggleClass( 'in-sub-panel' );
|
|
||||||
content.delay( 180 ).hide( 0, function() {
|
|
||||||
content.css( 'margin-top', 'inherit' ); // Reset
|
|
||||||
} );
|
|
||||||
topPanel.attr( 'tabindex', '0' );
|
|
||||||
backBtn.attr( 'tabindex', '-1' );
|
|
||||||
panelTitle.focus();
|
|
||||||
container.scrollTop( 0 );
|
|
||||||
} else {
|
|
||||||
// Close all open sections in any accordion level.
|
|
||||||
siblings.removeClass( 'open' );
|
|
||||||
siblings.find( sectionContent ).show().slideUp( 0 );
|
|
||||||
content.show( 0, function() {
|
|
||||||
position = content.offset().top;
|
|
||||||
scroll = container.scrollTop();
|
|
||||||
content.css( 'margin-top', ( 45 - position - scroll ) );
|
|
||||||
section.toggleClass( 'current-panel' );
|
|
||||||
overlay.toggleClass( 'in-sub-panel' );
|
|
||||||
container.scrollTop( 0 );
|
|
||||||
} );
|
|
||||||
topPanel.attr( 'tabindex', '-1' );
|
|
||||||
backBtn.attr( 'tabindex', '0' );
|
|
||||||
backBtn.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
!function(a){function b(a){var b=a.closest(".accordion-section"),e=b.closest(".accordion-container").find(".open"),f=b.find(d);if(!b.hasClass("cannot-expand"))return b.hasClass("control-panel")?void c(b):void(b.hasClass("open")?(b.toggleClass("open"),f.toggle(!0).slideToggle(150)):(e.removeClass("open"),e.find(d).show().slideUp(150),f.toggle(!1).slideToggle(150),b.toggleClass("open")))}function c(a){var b,c,e=a.closest(".accordion-section"),f=e.closest(".wp-full-overlay"),g=e.closest(".accordion-container"),h=g.find(".open"),i=f.find("#customize-theme-controls > ul > .accordion-section > .accordion-section-title").add("#customize-info > .accordion-section-title"),j=f.find(".control-panel-back"),k=e.find(".accordion-section-title").first(),l=e.find(".control-panel-content");e.hasClass("current-panel")?(e.toggleClass("current-panel"),f.toggleClass("in-sub-panel"),l.delay(180).hide(0,function(){l.css("margin-top","inherit")}),i.attr("tabindex","0"),j.attr("tabindex","-1"),k.focus(),g.scrollTop(0)):(h.removeClass("open"),h.find(d).show().slideUp(0),l.show(0,function(){b=l.offset().top,c=g.scrollTop(),l.css("margin-top",45-b-c),e.toggleClass("current-panel"),f.toggleClass("in-sub-panel"),g.scrollTop(0)}),i.attr("tabindex","-1"),j.attr("tabindex","0"),j.focus())}a(document).ready(function(){a(".accordion-container").on("click keydown",".accordion-section-title",function(c){("keydown"!==c.type||13===c.which)&&(c.preventDefault(),b(a(this)))}),a("#customize-header-actions").on("click keydown",".control-panel-back",function(b){("keydown"!==b.type||13===b.which)&&(b.preventDefault(),c(a(".current-panel")))})});var d=a(".accordion-section-content")}(jQuery);
|
!function(a){function b(a){var b=a.closest(".accordion-section"),c=b.closest(".accordion-container").find(".open"),d=b.find(".accordion-section-content");b.hasClass("cannot-expand")||(b.hasClass("open")?(b.toggleClass("open"),d.toggle(!0).slideToggle(150)):(c.removeClass("open"),c.find(".accordion-section-content").show().slideUp(150),d.toggle(!1).slideToggle(150),b.toggleClass("open")))}a(document).ready(function(){a(".accordion-container").on("click keydown",".accordion-section-title",function(c){("keydown"!==c.type||13===c.which)&&(c.preventDefault(),b(a(this)))})})}(jQuery);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -404,6 +404,23 @@
|
||||||
* @augments wp.customize.Control
|
* @augments wp.customize.Control
|
||||||
*/
|
*/
|
||||||
api.Widgets.WidgetControl = api.Control.extend({
|
api.Widgets.WidgetControl = api.Control.extend({
|
||||||
|
defaultExpandedArguments: {
|
||||||
|
duration: 'fast'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function ( id, options ) {
|
||||||
|
var control = this;
|
||||||
|
api.Control.prototype.initialize.call( control, id, options );
|
||||||
|
control.expanded = new api.Value();
|
||||||
|
control.expandedArgumentsQueue = [];
|
||||||
|
control.expanded.bind( function ( expanded ) {
|
||||||
|
var args = control.expandedArgumentsQueue.shift();
|
||||||
|
args = $.extend( {}, control.defaultExpandedArguments, args );
|
||||||
|
control.onChangeExpanded( expanded, args );
|
||||||
|
});
|
||||||
|
control.expanded.set( false );
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the control
|
* Set up the control
|
||||||
*/
|
*/
|
||||||
|
@ -529,13 +546,13 @@
|
||||||
if ( sidebarWidgetsControl.isReordering ) {
|
if ( sidebarWidgetsControl.isReordering ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.toggleForm();
|
self.expanded( ! self.expanded() );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
$closeBtn = this.container.find( '.widget-control-close' );
|
$closeBtn = this.container.find( '.widget-control-close' );
|
||||||
$closeBtn.on( 'click', function( e ) {
|
$closeBtn.on( 'click', function( e ) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
self.collapseForm();
|
self.collapse();
|
||||||
self.container.find( '.widget-top .widget-action:first' ).focus(); // keyboard accessibility
|
self.container.find( '.widget-top .widget-action:first' ).focus(); // keyboard accessibility
|
||||||
} );
|
} );
|
||||||
},
|
},
|
||||||
|
@ -777,9 +794,14 @@
|
||||||
* Overrides api.Control.toggle()
|
* Overrides api.Control.toggle()
|
||||||
*
|
*
|
||||||
* @param {Boolean} active
|
* @param {Boolean} active
|
||||||
|
* @param {Object} args
|
||||||
*/
|
*/
|
||||||
toggle: function ( active ) {
|
onChangeActive: function ( active, args ) {
|
||||||
|
// Note: there is a second 'args' parameter being passed, merged on top of this.defaultActiveArguments
|
||||||
this.container.toggleClass( 'widget-rendered', active );
|
this.container.toggleClass( 'widget-rendered', active );
|
||||||
|
if ( args.completeCallback ) {
|
||||||
|
args.completeCallback();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1101,51 +1123,90 @@
|
||||||
* Expand the accordion section containing a control
|
* Expand the accordion section containing a control
|
||||||
*/
|
*/
|
||||||
expandControlSection: function() {
|
expandControlSection: function() {
|
||||||
var $section = this.container.closest( '.accordion-section' );
|
api.Control.prototype.expand.call( this );
|
||||||
|
|
||||||
if ( ! $section.hasClass( 'open' ) ) {
|
|
||||||
$section.find( '.accordion-section-title:first' ).trigger( 'click' );
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Boolean} expanded
|
||||||
|
* @param {Object} [params]
|
||||||
|
* @returns {Boolean} false if state already applied
|
||||||
|
*/
|
||||||
|
_toggleExpanded: api.Section.prototype._toggleExpanded,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} [params]
|
||||||
|
* @returns {Boolean} false if already expanded
|
||||||
|
*/
|
||||||
|
expand: api.Section.prototype.expand,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand the widget form control
|
* Expand the widget form control
|
||||||
|
*
|
||||||
|
* @deprecated alias of expand()
|
||||||
*/
|
*/
|
||||||
expandForm: function() {
|
expandForm: function() {
|
||||||
this.toggleForm( true );
|
this.expand();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} [params]
|
||||||
|
* @returns {Boolean} false if already collapsed
|
||||||
|
*/
|
||||||
|
collapse: api.Section.prototype.collapse,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collapse the widget form control
|
* Collapse the widget form control
|
||||||
|
*
|
||||||
|
* @deprecated alias of expand()
|
||||||
*/
|
*/
|
||||||
collapseForm: function() {
|
collapseForm: function() {
|
||||||
this.toggleForm( false );
|
this.collapse();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand or collapse the widget control
|
* Expand or collapse the widget control
|
||||||
*
|
*
|
||||||
|
* @deprecated this is poor naming, and it is better to directly set control.expanded( showOrHide )
|
||||||
|
*
|
||||||
* @param {boolean|undefined} [showOrHide] If not supplied, will be inverse of current visibility
|
* @param {boolean|undefined} [showOrHide] If not supplied, will be inverse of current visibility
|
||||||
*/
|
*/
|
||||||
toggleForm: function( showOrHide ) {
|
toggleForm: function( showOrHide ) {
|
||||||
var self = this, $widget, $inside, complete;
|
|
||||||
|
|
||||||
$widget = this.container.find( 'div.widget:first' );
|
|
||||||
$inside = $widget.find( '.widget-inside:first' );
|
|
||||||
if ( typeof showOrHide === 'undefined' ) {
|
if ( typeof showOrHide === 'undefined' ) {
|
||||||
showOrHide = ! $inside.is( ':visible' );
|
showOrHide = ! this.expanded();
|
||||||
}
|
}
|
||||||
|
this.expanded( showOrHide );
|
||||||
|
},
|
||||||
|
|
||||||
// Already expanded or collapsed, so noop
|
/**
|
||||||
if ( $inside.is( ':visible' ) === showOrHide ) {
|
* Respond to change in the expanded state.
|
||||||
|
*
|
||||||
|
* @param {Boolean} expanded
|
||||||
|
* @param {Object} args merged on top of this.defaultActiveArguments
|
||||||
|
*/
|
||||||
|
onChangeExpanded: function ( expanded, args ) {
|
||||||
|
var self = this, $widget, $inside, complete, prevComplete;
|
||||||
|
|
||||||
|
// If the expanded state is unchanged only manipulate container expanded states
|
||||||
|
if ( args.unchanged ) {
|
||||||
|
if ( expanded ) {
|
||||||
|
api.Control.prototype.expand.call( self, {
|
||||||
|
completeCallback: args.completeCallback
|
||||||
|
});
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( showOrHide ) {
|
$widget = this.container.find( 'div.widget:first' );
|
||||||
|
$inside = $widget.find( '.widget-inside:first' );
|
||||||
|
|
||||||
|
if ( expanded ) {
|
||||||
|
|
||||||
|
self.expandControlSection();
|
||||||
|
|
||||||
// Close all other widget controls before expanding this one
|
// Close all other widget controls before expanding this one
|
||||||
api.control.each( function( otherControl ) {
|
api.control.each( function( otherControl ) {
|
||||||
if ( self.params.type === otherControl.params.type && self !== otherControl ) {
|
if ( self.params.type === otherControl.params.type && self !== otherControl ) {
|
||||||
otherControl.collapseForm();
|
otherControl.collapse();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -1154,29 +1215,44 @@
|
||||||
self.container.addClass( 'expanded' );
|
self.container.addClass( 'expanded' );
|
||||||
self.container.trigger( 'expanded' );
|
self.container.trigger( 'expanded' );
|
||||||
};
|
};
|
||||||
|
if ( args.completeCallback ) {
|
||||||
|
prevComplete = complete;
|
||||||
|
complete = function () {
|
||||||
|
prevComplete();
|
||||||
|
args.completeCallback();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if ( self.params.is_wide ) {
|
if ( self.params.is_wide ) {
|
||||||
$inside.fadeIn( 'fast', complete );
|
$inside.fadeIn( args.duration, complete );
|
||||||
} else {
|
} else {
|
||||||
$inside.slideDown( 'fast', complete );
|
$inside.slideDown( args.duration, complete );
|
||||||
}
|
}
|
||||||
|
|
||||||
self.container.trigger( 'expand' );
|
self.container.trigger( 'expand' );
|
||||||
self.container.addClass( 'expanding' );
|
self.container.addClass( 'expanding' );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
complete = function() {
|
complete = function() {
|
||||||
self.container.removeClass( 'collapsing' );
|
self.container.removeClass( 'collapsing' );
|
||||||
self.container.removeClass( 'expanded' );
|
self.container.removeClass( 'expanded' );
|
||||||
self.container.trigger( 'collapsed' );
|
self.container.trigger( 'collapsed' );
|
||||||
};
|
};
|
||||||
|
if ( args.completeCallback ) {
|
||||||
|
prevComplete = complete;
|
||||||
|
complete = function () {
|
||||||
|
prevComplete();
|
||||||
|
args.completeCallback();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
self.container.trigger( 'collapse' );
|
self.container.trigger( 'collapse' );
|
||||||
self.container.addClass( 'collapsing' );
|
self.container.addClass( 'collapsing' );
|
||||||
|
|
||||||
if ( self.params.is_wide ) {
|
if ( self.params.is_wide ) {
|
||||||
$inside.fadeOut( 'fast', complete );
|
$inside.fadeOut( args.duration, complete );
|
||||||
} else {
|
} else {
|
||||||
$inside.slideUp( 'fast', function() {
|
$inside.slideUp( args.duration, function() {
|
||||||
$widget.css( { width:'', margin:'' } );
|
$widget.css( { width:'', margin:'' } );
|
||||||
complete();
|
complete();
|
||||||
} );
|
} );
|
||||||
|
@ -1184,16 +1260,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand the containing sidebar section, expand the form, and focus on
|
|
||||||
* the first input in the control
|
|
||||||
*/
|
|
||||||
focus: function() {
|
|
||||||
this.expandControlSection();
|
|
||||||
this.expandForm();
|
|
||||||
this.container.find( '.widget-content :focusable:first' ).focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the position (index) of the widget in the containing sidebar
|
* Get the position (index) of the widget in the containing sidebar
|
||||||
*
|
*
|
||||||
|
@ -1304,6 +1370,7 @@
|
||||||
* @augments wp.customize.Control
|
* @augments wp.customize.Control
|
||||||
*/
|
*/
|
||||||
api.Widgets.SidebarControl = api.Control.extend({
|
api.Widgets.SidebarControl = api.Control.extend({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the control
|
* Set up the control
|
||||||
*/
|
*/
|
||||||
|
@ -1325,7 +1392,7 @@
|
||||||
registeredSidebar = api.Widgets.registeredSidebars.get( this.params.sidebar_id );
|
registeredSidebar = api.Widgets.registeredSidebars.get( this.params.sidebar_id );
|
||||||
|
|
||||||
this.setting.bind( function( newWidgetIds, oldWidgetIds ) {
|
this.setting.bind( function( newWidgetIds, oldWidgetIds ) {
|
||||||
var widgetFormControls, $sidebarWidgetsAddControl, finalControlContainers, removedWidgetIds;
|
var widgetFormControls, removedWidgetIds, priority;
|
||||||
|
|
||||||
removedWidgetIds = _( oldWidgetIds ).difference( newWidgetIds );
|
removedWidgetIds = _( oldWidgetIds ).difference( newWidgetIds );
|
||||||
|
|
||||||
|
@ -1350,21 +1417,16 @@
|
||||||
widgetFormControls.sort( function( a, b ) {
|
widgetFormControls.sort( function( a, b ) {
|
||||||
var aIndex = _.indexOf( newWidgetIds, a.params.widget_id ),
|
var aIndex = _.indexOf( newWidgetIds, a.params.widget_id ),
|
||||||
bIndex = _.indexOf( newWidgetIds, b.params.widget_id );
|
bIndex = _.indexOf( newWidgetIds, b.params.widget_id );
|
||||||
|
return aIndex - bIndex;
|
||||||
if ( aIndex === bIndex ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aIndex < bIndex ? -1 : 1;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Append the controls to put them in the right order
|
priority = 0;
|
||||||
finalControlContainers = _( widgetFormControls ).map( function( widgetFormControls ) {
|
_( widgetFormControls ).each( function ( control ) {
|
||||||
return widgetFormControls.container[0];
|
control.priority( priority );
|
||||||
|
control.section( self.section() );
|
||||||
|
priority += 1;
|
||||||
});
|
});
|
||||||
|
self.priority( priority ); // Make sure sidebar control remains at end
|
||||||
$sidebarWidgetsAddControl = self.$sectionContent.find( '.customize-control-sidebar_widgets' );
|
|
||||||
$sidebarWidgetsAddControl.before( finalControlContainers );
|
|
||||||
|
|
||||||
// Re-sort widget form controls (including widgets form other sidebars newly moved here)
|
// Re-sort widget form controls (including widgets form other sidebars newly moved here)
|
||||||
self._applyCardinalOrderClassNames();
|
self._applyCardinalOrderClassNames();
|
||||||
|
@ -1434,36 +1496,9 @@
|
||||||
// Update the model with whether or not the sidebar is rendered
|
// Update the model with whether or not the sidebar is rendered
|
||||||
self.active.bind( function ( active ) {
|
self.active.bind( function ( active ) {
|
||||||
registeredSidebar.set( 'is_rendered', active );
|
registeredSidebar.set( 'is_rendered', active );
|
||||||
|
api.section( self.section.get() ).active( active );
|
||||||
} );
|
} );
|
||||||
},
|
api.section( self.section.get() ).active( self.active() );
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the sidebar section when it becomes visible.
|
|
||||||
*
|
|
||||||
* Overrides api.Control.toggle()
|
|
||||||
*
|
|
||||||
* @param {Boolean} active
|
|
||||||
*/
|
|
||||||
toggle: function ( active ) {
|
|
||||||
var $section, sectionSelector;
|
|
||||||
|
|
||||||
sectionSelector = '#accordion-section-sidebar-widgets-' + this.params.sidebar_id;
|
|
||||||
$section = $( sectionSelector );
|
|
||||||
|
|
||||||
if ( active ) {
|
|
||||||
$section.stop().slideDown( function() {
|
|
||||||
$( this ).css( 'height', 'auto' ); // so that the .accordion-section-content won't overflow
|
|
||||||
} );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Make sure that hidden sections get closed first
|
|
||||||
if ( $section.hasClass( 'open' ) ) {
|
|
||||||
// it would be nice if accordionSwitch() in accordion.js was public
|
|
||||||
$section.find( '.accordion-section-title' ).trigger( 'click' );
|
|
||||||
}
|
|
||||||
|
|
||||||
$section.stop().slideUp();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1500,12 +1535,18 @@
|
||||||
this.$controlSection.find( '.accordion-section-title' ).droppable({
|
this.$controlSection.find( '.accordion-section-title' ).droppable({
|
||||||
accept: '.customize-control-widget_form',
|
accept: '.customize-control-widget_form',
|
||||||
over: function() {
|
over: function() {
|
||||||
if ( ! self.$controlSection.hasClass( 'open' ) ) {
|
var section = api.section( self.section.get() );
|
||||||
self.$controlSection.addClass( 'open' );
|
section.expand({
|
||||||
self.$sectionContent.toggle( false ).slideToggle( 150, function() {
|
allowMultiple: true, // Prevent the section being dragged from to be collapsed
|
||||||
self.$sectionContent.sortable( 'refreshPositions' );
|
completeCallback: function () {
|
||||||
|
// @todo It is not clear when refreshPositions should be called on which sections, or if it is even needed
|
||||||
|
api.section.each( function ( otherSection ) {
|
||||||
|
if ( otherSection.container.find( '.customize-control-sidebar_widgets' ).length ) {
|
||||||
|
otherSection.container.find( '.accordion-section-content:first' ).sortable( 'refreshPositions' );
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1548,16 +1589,30 @@
|
||||||
* Add classes to the widget_form controls to assist with styling
|
* Add classes to the widget_form controls to assist with styling
|
||||||
*/
|
*/
|
||||||
_applyCardinalOrderClassNames: function() {
|
_applyCardinalOrderClassNames: function() {
|
||||||
this.$sectionContent.find( '.customize-control-widget_form' )
|
var widgetControls = [];
|
||||||
|
_.each( this.setting(), function ( widgetId ) {
|
||||||
|
var widgetControl = api.Widgets.getWidgetFormControlForWidget( widgetId );
|
||||||
|
if ( widgetControl ) {
|
||||||
|
widgetControls.push( widgetControl );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( ! widgetControls.length ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$( widgetControls ).each( function () {
|
||||||
|
$( this.container )
|
||||||
.removeClass( 'first-widget' )
|
.removeClass( 'first-widget' )
|
||||||
.removeClass( 'last-widget' )
|
.removeClass( 'last-widget' )
|
||||||
.find( '.move-widget-down, .move-widget-up' ).prop( 'tabIndex', 0 );
|
.find( '.move-widget-down, .move-widget-up' ).prop( 'tabIndex', 0 );
|
||||||
|
});
|
||||||
|
|
||||||
this.$sectionContent.find( '.customize-control-widget_form:first' )
|
_.first( widgetControls ).container
|
||||||
.addClass( 'first-widget' )
|
.addClass( 'first-widget' )
|
||||||
.find( '.move-widget-up' ).prop( 'tabIndex', -1 );
|
.find( '.move-widget-up' ).prop( 'tabIndex', -1 );
|
||||||
|
|
||||||
this.$sectionContent.find( '.customize-control-widget_form:last' )
|
_.last( widgetControls ).container
|
||||||
.addClass( 'last-widget' )
|
.addClass( 'last-widget' )
|
||||||
.find( '.move-widget-down' ).prop( 'tabIndex', -1 );
|
.find( '.move-widget-down' ).prop( 'tabIndex', -1 );
|
||||||
},
|
},
|
||||||
|
@ -1571,6 +1626,8 @@
|
||||||
* Enable/disable the reordering UI
|
* Enable/disable the reordering UI
|
||||||
*
|
*
|
||||||
* @param {Boolean} showOrHide to enable/disable reordering
|
* @param {Boolean} showOrHide to enable/disable reordering
|
||||||
|
*
|
||||||
|
* @todo We should have a reordering state instead and rename this to onChangeReordering
|
||||||
*/
|
*/
|
||||||
toggleReordering: function( showOrHide ) {
|
toggleReordering: function( showOrHide ) {
|
||||||
showOrHide = Boolean( showOrHide );
|
showOrHide = Boolean( showOrHide );
|
||||||
|
@ -1584,7 +1641,7 @@
|
||||||
|
|
||||||
if ( showOrHide ) {
|
if ( showOrHide ) {
|
||||||
_( this.getWidgetFormControls() ).each( function( formControl ) {
|
_( this.getWidgetFormControls() ).each( function( formControl ) {
|
||||||
formControl.collapseForm();
|
formControl.collapse();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
this.$sectionContent.find( '.first-widget .move-widget' ).focus();
|
this.$sectionContent.find( '.first-widget .move-widget' ).focus();
|
||||||
|
@ -1619,7 +1676,7 @@
|
||||||
* @returns {object|false} widget_form control instance, or false on error
|
* @returns {object|false} widget_form control instance, or false on error
|
||||||
*/
|
*/
|
||||||
addWidget: function( widgetId ) {
|
addWidget: function( widgetId ) {
|
||||||
var self = this, controlHtml, $widget, controlType = 'widget_form', $control, controlConstructor,
|
var self = this, controlHtml, $widget, controlType = 'widget_form', controlContainer, controlConstructor,
|
||||||
parsedWidgetId = parseWidgetId( widgetId ),
|
parsedWidgetId = parseWidgetId( widgetId ),
|
||||||
widgetNumber = parsedWidgetId.number,
|
widgetNumber = parsedWidgetId.number,
|
||||||
widgetIdBase = parsedWidgetId.id_base,
|
widgetIdBase = parsedWidgetId.id_base,
|
||||||
|
@ -1651,30 +1708,28 @@
|
||||||
|
|
||||||
$widget = $( controlHtml );
|
$widget = $( controlHtml );
|
||||||
|
|
||||||
$control = $( '<li/>' )
|
controlContainer = $( '<li/>' )
|
||||||
.addClass( 'customize-control' )
|
.addClass( 'customize-control' )
|
||||||
.addClass( 'customize-control-' + controlType )
|
.addClass( 'customize-control-' + controlType )
|
||||||
.append( $widget );
|
.append( $widget );
|
||||||
|
|
||||||
// Remove icon which is visible inside the panel
|
// Remove icon which is visible inside the panel
|
||||||
$control.find( '> .widget-icon' ).remove();
|
controlContainer.find( '> .widget-icon' ).remove();
|
||||||
|
|
||||||
if ( widget.get( 'is_multi' ) ) {
|
if ( widget.get( 'is_multi' ) ) {
|
||||||
$control.find( 'input[name="widget_number"]' ).val( widgetNumber );
|
controlContainer.find( 'input[name="widget_number"]' ).val( widgetNumber );
|
||||||
$control.find( 'input[name="multi_number"]' ).val( widgetNumber );
|
controlContainer.find( 'input[name="multi_number"]' ).val( widgetNumber );
|
||||||
}
|
}
|
||||||
|
|
||||||
widgetId = $control.find( '[name="widget-id"]' ).val();
|
widgetId = controlContainer.find( '[name="widget-id"]' ).val();
|
||||||
|
|
||||||
$control.hide(); // to be slid-down below
|
controlContainer.hide(); // to be slid-down below
|
||||||
|
|
||||||
settingId = 'widget_' + widget.get( 'id_base' );
|
settingId = 'widget_' + widget.get( 'id_base' );
|
||||||
if ( widget.get( 'is_multi' ) ) {
|
if ( widget.get( 'is_multi' ) ) {
|
||||||
settingId += '[' + widgetNumber + ']';
|
settingId += '[' + widgetNumber + ']';
|
||||||
}
|
}
|
||||||
$control.attr( 'id', 'customize-control-' + settingId.replace( /\]/g, '' ).replace( /\[/g, '-' ) );
|
controlContainer.attr( 'id', 'customize-control-' + settingId.replace( /\]/g, '' ).replace( /\[/g, '-' ) );
|
||||||
|
|
||||||
this.container.after( $control );
|
|
||||||
|
|
||||||
// Only create setting if it doesn't already exist (if we're adding a pre-existing inactive widget)
|
// Only create setting if it doesn't already exist (if we're adding a pre-existing inactive widget)
|
||||||
isExistingWidget = api.has( settingId );
|
isExistingWidget = api.has( settingId );
|
||||||
|
@ -1692,6 +1747,7 @@
|
||||||
settings: {
|
settings: {
|
||||||
'default': settingId
|
'default': settingId
|
||||||
},
|
},
|
||||||
|
content: controlContainer,
|
||||||
sidebar_id: self.params.sidebar_id,
|
sidebar_id: self.params.sidebar_id,
|
||||||
widget_id: widgetId,
|
widget_id: widgetId,
|
||||||
widget_id_base: widget.get( 'id_base' ),
|
widget_id_base: widget.get( 'id_base' ),
|
||||||
|
@ -1731,9 +1787,9 @@
|
||||||
this.setting( sidebarWidgets );
|
this.setting( sidebarWidgets );
|
||||||
}
|
}
|
||||||
|
|
||||||
$control.slideDown( function() {
|
controlContainer.slideDown( function() {
|
||||||
if ( isExistingWidget ) {
|
if ( isExistingWidget ) {
|
||||||
widgetFormControl.expandForm();
|
widgetFormControl.expand();
|
||||||
widgetFormControl.updateWidget( {
|
widgetFormControl.updateWidget( {
|
||||||
instance: widgetFormControl.setting(),
|
instance: widgetFormControl.setting(),
|
||||||
complete: function( error ) {
|
complete: function( error ) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -74,6 +74,7 @@ class WP_Customize_Control {
|
||||||
public $input_attrs = array();
|
public $input_attrs = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated It is better to just call the json() method
|
||||||
* @access public
|
* @access public
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
@ -218,9 +219,24 @@ class WP_Customize_Control {
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->json['type'] = $this->type;
|
$this->json['type'] = $this->type;
|
||||||
|
$this->json['priority'] = $this->priority;
|
||||||
|
$this->json['active'] = $this->active();
|
||||||
|
$this->json['section'] = $this->section;
|
||||||
|
$this->json['content'] = $this->get_content();
|
||||||
$this->json['label'] = $this->label;
|
$this->json['label'] = $this->label;
|
||||||
$this->json['description'] = $this->description;
|
$this->json['description'] = $this->description;
|
||||||
$this->json['active'] = $this->active();
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data to export to the client via JSON.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function json() {
|
||||||
|
$this->to_json();
|
||||||
|
return $this->json;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,6 +259,21 @@ class WP_Customize_Control {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the control's content for insertion into the Customizer pane.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public final function get_content() {
|
||||||
|
ob_start();
|
||||||
|
$this->maybe_render();
|
||||||
|
$template = trim( ob_get_contents() );
|
||||||
|
ob_end_clean();
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check capabilities and render the control.
|
* Check capabilities and render the control.
|
||||||
*
|
*
|
||||||
|
@ -1073,6 +1104,7 @@ class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
|
||||||
/**
|
/**
|
||||||
* Widget Area Customize Control Class
|
* Widget Area Customize Control Class
|
||||||
*
|
*
|
||||||
|
* @since 3.9.0
|
||||||
*/
|
*/
|
||||||
class WP_Widget_Area_Customize_Control extends WP_Customize_Control {
|
class WP_Widget_Area_Customize_Control extends WP_Customize_Control {
|
||||||
public $type = 'sidebar_widgets';
|
public $type = 'sidebar_widgets';
|
||||||
|
@ -1114,6 +1146,8 @@ class WP_Widget_Area_Customize_Control extends WP_Customize_Control {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Widget Form Customize Control Class
|
* Widget Form Customize Control Class
|
||||||
|
*
|
||||||
|
* @since 3.9.0
|
||||||
*/
|
*/
|
||||||
class WP_Widget_Form_Customize_Control extends WP_Customize_Control {
|
class WP_Widget_Form_Customize_Control extends WP_Customize_Control {
|
||||||
public $type = 'widget_form';
|
public $type = 'widget_form';
|
||||||
|
|
|
@ -498,6 +498,8 @@ final class WP_Customize_Manager {
|
||||||
$settings = array(
|
$settings = array(
|
||||||
'values' => array(),
|
'values' => array(),
|
||||||
'channel' => wp_unslash( $_POST['customize_messenger_channel'] ),
|
'channel' => wp_unslash( $_POST['customize_messenger_channel'] ),
|
||||||
|
'activePanels' => array(),
|
||||||
|
'activeSections' => array(),
|
||||||
'activeControls' => array(),
|
'activeControls' => array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -511,6 +513,12 @@ final class WP_Customize_Manager {
|
||||||
foreach ( $this->settings as $id => $setting ) {
|
foreach ( $this->settings as $id => $setting ) {
|
||||||
$settings['values'][ $id ] = $setting->js_value();
|
$settings['values'][ $id ] = $setting->js_value();
|
||||||
}
|
}
|
||||||
|
foreach ( $this->panels as $id => $panel ) {
|
||||||
|
$settings['activePanels'][ $id ] = $panel->active();
|
||||||
|
}
|
||||||
|
foreach ( $this->sections as $id => $section ) {
|
||||||
|
$settings['activeSections'][ $id ] = $section->active();
|
||||||
|
}
|
||||||
foreach ( $this->controls as $id => $control ) {
|
foreach ( $this->controls as $id => $control ) {
|
||||||
$settings['activeControls'][ $id ] = $control->active();
|
$settings['activeControls'][ $id ] = $control->active();
|
||||||
}
|
}
|
||||||
|
@ -911,11 +919,11 @@ final class WP_Customize_Manager {
|
||||||
|
|
||||||
if ( ! $section->panel ) {
|
if ( ! $section->panel ) {
|
||||||
// Top-level section.
|
// Top-level section.
|
||||||
$sections[] = $section;
|
$sections[ $section->id ] = $section;
|
||||||
} else {
|
} else {
|
||||||
// This section belongs to a panel.
|
// This section belongs to a panel.
|
||||||
if ( isset( $this->panels [ $section->panel ] ) ) {
|
if ( isset( $this->panels [ $section->panel ] ) ) {
|
||||||
$this->panels[ $section->panel ]->sections[] = $section;
|
$this->panels[ $section->panel ]->sections[ $section->id ] = $section;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -932,8 +940,8 @@ final class WP_Customize_Manager {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
usort( $panel->sections, array( $this, '_cmp_priority' ) );
|
uasort( $panel->sections, array( $this, '_cmp_priority' ) );
|
||||||
$panels[] = $panel;
|
$panels[ $panel->id ] = $panel;
|
||||||
}
|
}
|
||||||
$this->panels = $panels;
|
$this->panels = $panels;
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,28 @@ class WP_Customize_Panel {
|
||||||
*/
|
*/
|
||||||
public $sections;
|
public $sections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @see WP_Customize_Section::active()
|
||||||
|
*
|
||||||
|
* @var callable Callback is called with one argument, the instance of
|
||||||
|
* WP_Customize_Section, and returns bool to indicate whether
|
||||||
|
* the section is active (such as it relates to the URL
|
||||||
|
* currently being previewed).
|
||||||
|
*/
|
||||||
|
public $active_callback = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -103,12 +125,69 @@ class WP_Customize_Panel {
|
||||||
|
|
||||||
$this->manager = $manager;
|
$this->manager = $manager;
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
|
if ( empty( $this->active_callback ) ) {
|
||||||
|
$this->active_callback = array( $this, 'active_callback' );
|
||||||
|
}
|
||||||
|
|
||||||
$this->sections = array(); // Users cannot customize the $sections array.
|
$this->sections = array(); // Users cannot customize the $sections array.
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether panel is active to current Customizer preview.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @return bool Whether the panel is active to the current preview.
|
||||||
|
*/
|
||||||
|
public final function active() {
|
||||||
|
$panel = $this;
|
||||||
|
$active = call_user_func( $this->active_callback, $this );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter response of WP_Customize_Panel::active().
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @param bool $active Whether the Customizer panel is active.
|
||||||
|
* @param WP_Customize_Panel $panel WP_Customize_Panel instance.
|
||||||
|
*/
|
||||||
|
$active = apply_filters( 'customize_panel_active', $active, $panel );
|
||||||
|
|
||||||
|
return $active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default callback used when invoking WP_Customize_Panel::active().
|
||||||
|
*
|
||||||
|
* Subclasses can override this with their specific logic, or they may
|
||||||
|
* provide an 'active_callback' argument to the constructor.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @return bool Always true.
|
||||||
|
*/
|
||||||
|
public function active_callback() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather the parameters passed to client JavaScript via JSON.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @return array The array to be exported to the client as JSON
|
||||||
|
*/
|
||||||
|
public function json() {
|
||||||
|
$array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'type' ) );
|
||||||
|
$array['content'] = $this->get_content();
|
||||||
|
$array['active'] = $this->active();
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks required user capabilities and whether the theme has the
|
* Checks required user capabilities and whether the theme has the
|
||||||
* feature support required by the panel.
|
* feature support required by the panel.
|
||||||
|
@ -129,6 +208,21 @@ class WP_Customize_Panel {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the panel's content template for insertion into the Customizer pane.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public final function get_content() {
|
||||||
|
ob_start();
|
||||||
|
$this->maybe_render();
|
||||||
|
$template = trim( ob_get_contents() );
|
||||||
|
ob_end_clean();
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check capabilities and render the panel.
|
* Check capabilities and render the panel.
|
||||||
*
|
*
|
||||||
|
@ -189,7 +283,7 @@ class WP_Customize_Panel {
|
||||||
*/
|
*/
|
||||||
protected function render_content() {
|
protected function render_content() {
|
||||||
?>
|
?>
|
||||||
<li class="accordion-section control-section<?php if ( empty( $this->description ) ) echo ' cannot-expand'; ?>">
|
<li class="panel-meta accordion-section control-section<?php if ( empty( $this->description ) ) { echo ' cannot-expand'; } ?>">
|
||||||
<div class="accordion-section-title" tabindex="0">
|
<div class="accordion-section-title" tabindex="0">
|
||||||
<span class="preview-notice"><?php
|
<span class="preview-notice"><?php
|
||||||
/* translators: %s is the site/panel title in the Customizer */
|
/* translators: %s is the site/panel title in the Customizer */
|
||||||
|
@ -203,8 +297,5 @@ class WP_Customize_Panel {
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</li>
|
</li>
|
||||||
<?php
|
<?php
|
||||||
foreach ( $this->sections as $section ) {
|
|
||||||
$section->maybe_render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,28 @@ class WP_Customize_Section {
|
||||||
*/
|
*/
|
||||||
public $controls;
|
public $controls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @see WP_Customize_Section::active()
|
||||||
|
*
|
||||||
|
* @var callable Callback is called with one argument, the instance of
|
||||||
|
* WP_Customize_Section, and returns bool to indicate whether
|
||||||
|
* the section is active (such as it relates to the URL
|
||||||
|
* currently being previewed).
|
||||||
|
*/
|
||||||
|
public $active_callback = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -105,18 +127,76 @@ class WP_Customize_Section {
|
||||||
public function __construct( $manager, $id, $args = array() ) {
|
public function __construct( $manager, $id, $args = array() ) {
|
||||||
$keys = array_keys( get_object_vars( $this ) );
|
$keys = array_keys( get_object_vars( $this ) );
|
||||||
foreach ( $keys as $key ) {
|
foreach ( $keys as $key ) {
|
||||||
if ( isset( $args[ $key ] ) )
|
if ( isset( $args[ $key ] ) ) {
|
||||||
$this->$key = $args[ $key ];
|
$this->$key = $args[ $key ];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->manager = $manager;
|
$this->manager = $manager;
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
|
if ( empty( $this->active_callback ) ) {
|
||||||
|
$this->active_callback = array( $this, 'active_callback' );
|
||||||
|
}
|
||||||
|
|
||||||
$this->controls = array(); // Users cannot customize the $controls array.
|
$this->controls = array(); // Users cannot customize the $controls array.
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether section is active to current Customizer preview.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @return bool Whether the section is active to the current preview.
|
||||||
|
*/
|
||||||
|
public final function active() {
|
||||||
|
$section = $this;
|
||||||
|
$active = call_user_func( $this->active_callback, $this );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter response of WP_Customize_Section::active().
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @param bool $active Whether the Customizer section is active.
|
||||||
|
* @param WP_Customize_Section $section WP_Customize_Section instance.
|
||||||
|
*/
|
||||||
|
$active = apply_filters( 'customize_section_active', $active, $section );
|
||||||
|
|
||||||
|
return $active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default callback used when invoking WP_Customize_Section::active().
|
||||||
|
*
|
||||||
|
* Subclasses can override this with their specific logic, or they may
|
||||||
|
* provide an 'active_callback' argument to the constructor.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @return bool Always true.
|
||||||
|
*/
|
||||||
|
public function active_callback() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather the parameters passed to client JavaScript via JSON.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @return array The array to be exported to the client as JSON
|
||||||
|
*/
|
||||||
|
public function json() {
|
||||||
|
$array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'panel', 'type' ) );
|
||||||
|
$array['content'] = $this->get_content();
|
||||||
|
$array['active'] = $this->active();
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks required user capabilities and whether the theme has the
|
* Checks required user capabilities and whether the theme has the
|
||||||
* feature support required by the section.
|
* feature support required by the section.
|
||||||
|
@ -126,23 +206,41 @@ class WP_Customize_Section {
|
||||||
* @return bool False if theme doesn't support the section or user doesn't have the capability.
|
* @return bool False if theme doesn't support the section or user doesn't have the capability.
|
||||||
*/
|
*/
|
||||||
public final function check_capabilities() {
|
public final function check_capabilities() {
|
||||||
if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
|
if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
|
if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the section's content template for insertion into the Customizer pane.
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public final function get_content() {
|
||||||
|
ob_start();
|
||||||
|
$this->maybe_render();
|
||||||
|
$template = trim( ob_get_contents() );
|
||||||
|
ob_end_clean();
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check capabilities and render the section.
|
* Check capabilities and render the section.
|
||||||
*
|
*
|
||||||
* @since 3.4.0
|
* @since 3.4.0
|
||||||
*/
|
*/
|
||||||
public final function maybe_render() {
|
public final function maybe_render() {
|
||||||
if ( ! $this->check_capabilities() )
|
if ( ! $this->check_capabilities() ) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires before rendering a Customizer section.
|
* Fires before rendering a Customizer section.
|
||||||
|
@ -172,9 +270,6 @@ class WP_Customize_Section {
|
||||||
*/
|
*/
|
||||||
protected function render() {
|
protected function render() {
|
||||||
$classes = 'control-section accordion-section';
|
$classes = 'control-section accordion-section';
|
||||||
if ( $this->panel ) {
|
|
||||||
$classes .= ' control-subsection';
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
|
<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
|
||||||
<h3 class="accordion-section-title" tabindex="0">
|
<h3 class="accordion-section-title" tabindex="0">
|
||||||
|
@ -183,12 +278,10 @@ class WP_Customize_Section {
|
||||||
</h3>
|
</h3>
|
||||||
<ul class="accordion-section-content">
|
<ul class="accordion-section-content">
|
||||||
<?php if ( ! empty( $this->description ) ) : ?>
|
<?php if ( ! empty( $this->description ) ) : ?>
|
||||||
<li><p class="description customize-section-description"><?php echo $this->description; ?></p></li>
|
<li class="customize-section-description-container">
|
||||||
|
<p class="description customize-section-description"><?php echo $this->description; ?></p>
|
||||||
|
</li>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php
|
|
||||||
foreach ( $this->controls as $control )
|
|
||||||
$control->maybe_render();
|
|
||||||
?>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -184,8 +184,9 @@ window.wp = window.wp || {};
|
||||||
to = this.validate( to );
|
to = this.validate( to );
|
||||||
|
|
||||||
// Bail if the sanitized value is null or unchanged.
|
// Bail if the sanitized value is null or unchanged.
|
||||||
if ( null === to || _.isEqual( from, to ) )
|
if ( null === to || _.isEqual( from, to ) ) {
|
||||||
return this;
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
this._value = to;
|
this._value = to;
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
|
|
|
@ -107,6 +107,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
preview.send( 'ready', {
|
preview.send( 'ready', {
|
||||||
|
activePanels: api.settings.activePanels,
|
||||||
|
activeSections: api.settings.activeSections,
|
||||||
activeControls: api.settings.activeControls
|
activeControls: api.settings.activeControls
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
!function(a,b){var c,d=wp.customize;c=function(a,b,c){var d;return function(){var e=arguments;c=c||this,clearTimeout(d),d=setTimeout(function(){d=null,a.apply(c,e)},b)}},d.Preview=d.Messenger.extend({initialize:function(a,e){var f=this;d.Messenger.prototype.initialize.call(this,a,e),this.body=b(document.body),this.body.on("click.preview","a",function(a){a.preventDefault(),f.send("scroll",0),f.send("url",b(this).prop("href"))}),this.body.on("submit.preview","form",function(a){a.preventDefault()}),this.window=b(window),this.window.on("scroll.preview",c(function(){f.send("scroll",f.window.scrollTop())},200)),this.bind("scroll",function(a){f.window.scrollTop(a)})}}),b(function(){if(d.settings=window._wpCustomizeSettings,d.settings){var a,c;a=new d.Preview({url:window.location.href,channel:d.settings.channel}),a.bind("settings",function(a){b.each(a,function(a,b){d.has(a)?d(a).set(b):d.create(a,b)})}),a.trigger("settings",d.settings.values),a.bind("setting",function(a){var b;a=a.slice(),(b=d(a.shift()))&&b.set.apply(b,a)}),a.bind("sync",function(c){b.each(c,function(b,c){a.trigger(b,c)}),a.send("synced")}),a.bind("active",function(){d.settings.nonce&&a.send("nonce",d.settings.nonce)}),a.send("ready",{activeControls:d.settings.activeControls}),c=b.map(["color","image","position_x","repeat","attachment"],function(a){return"background_"+a}),d.when.apply(d,c).done(function(a,c,d,e,f){var g,h=b(document.body),i=b("head"),j=b("#custom-background-css");g=function(){var g="";h.toggleClass("custom-background",!(!a()&&!c())),a()&&(g+="background-color: "+a()+";"),c()&&(g+='background-image: url("'+c()+'");',g+="background-position: top "+d()+";",g+="background-repeat: "+e()+";",g+="background-attachment: "+f()+";"),j.remove(),j=b('<style type="text/css" id="custom-background-css">body.custom-background { '+g+" }</style>").appendTo(i)},b.each(arguments,function(){this.bind(g)})})}})}(wp,jQuery);
|
!function(a,b){var c,d=wp.customize;c=function(a,b,c){var d;return function(){var e=arguments;c=c||this,clearTimeout(d),d=setTimeout(function(){d=null,a.apply(c,e)},b)}},d.Preview=d.Messenger.extend({initialize:function(a,e){var f=this;d.Messenger.prototype.initialize.call(this,a,e),this.body=b(document.body),this.body.on("click.preview","a",function(a){a.preventDefault(),f.send("scroll",0),f.send("url",b(this).prop("href"))}),this.body.on("submit.preview","form",function(a){a.preventDefault()}),this.window=b(window),this.window.on("scroll.preview",c(function(){f.send("scroll",f.window.scrollTop())},200)),this.bind("scroll",function(a){f.window.scrollTop(a)})}}),b(function(){if(d.settings=window._wpCustomizeSettings,d.settings){var a,c;a=new d.Preview({url:window.location.href,channel:d.settings.channel}),a.bind("settings",function(a){b.each(a,function(a,b){d.has(a)?d(a).set(b):d.create(a,b)})}),a.trigger("settings",d.settings.values),a.bind("setting",function(a){var b;a=a.slice(),(b=d(a.shift()))&&b.set.apply(b,a)}),a.bind("sync",function(c){b.each(c,function(b,c){a.trigger(b,c)}),a.send("synced")}),a.bind("active",function(){d.settings.nonce&&a.send("nonce",d.settings.nonce)}),a.send("ready",{activePanels:d.settings.activePanels,activeSections:d.settings.activeSections,activeControls:d.settings.activeControls}),c=b.map(["color","image","position_x","repeat","attachment"],function(a){return"background_"+a}),d.when.apply(d,c).done(function(a,c,d,e,f){var g,h=b(document.body),i=b("head"),j=b("#custom-background-css");g=function(){var g="";h.toggleClass("custom-background",!(!a()&&!c())),a()&&(g+="background-color: "+a()+";"),c()&&(g+='background-image: url("'+c()+'");',g+="background-position: top "+d()+";",g+="background-repeat: "+e()+";",g+="background-attachment: "+f()+";"),j.remove(),j=b('<style type="text/css" id="custom-background-css">body.custom-background { '+g+" }</style>").appendTo(i)},b.each(arguments,function(){this.bind(g)})})}})}(wp,jQuery);
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '4.1-alpha-30101';
|
$wp_version = '4.1-alpha-30102';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue