Add theme browsing and theme switching to the Customizer
* Brings into core the Customizer Theme Switcher feature plugin * You can now browse, preview, and activate themes right from the Customizer fixes #31303. props celloexpressions, afercia, westonruter, folletto, designsimply Built from https://develop.svn.wordpress.org/trunk@31533 git-svn-id: http://core.svn.wordpress.org/trunk@31514 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
0d9275930b
commit
8b180b9a46
|
@ -827,6 +827,176 @@ p.customize-section-description {
|
|||
float: left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Themes
|
||||
*/
|
||||
@-webkit-keyframes customize-reload {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@-moz-keyframes customize-reload {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes customize-reload {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* #customize-container is reused from customize-loader.js, hence the naming. */
|
||||
.wp-customizer .customize-loading #customize-container {
|
||||
display: block;
|
||||
-webkit-animation: customize-reload .75s; /* Can't use %60transition` because `display` changes here. */
|
||||
-moz-animation: customize-reload .75s;
|
||||
animation: customize-reload .75s;
|
||||
}
|
||||
|
||||
.customize-themes-panel {
|
||||
display: none;
|
||||
padding: 0 8px;
|
||||
background: #f1f1f1;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.control-section.open .customize-themes-panel {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#customize-theme-controls .customize-themes-panel .accordion-section-content {
|
||||
background: transparent;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.customize-control.customize-control-theme {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .themes {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .theme {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .theme .theme-actions {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#customize-controls h3.theme-name {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .theme.active .theme-name {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.wp-customizer #themes-filter {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Panel-like behavior */
|
||||
#accordion-section-themes .accordion-section-title:after {
|
||||
content: "\f148";
|
||||
}
|
||||
|
||||
.rtl #accordion-section-themes .accordion-section-title:after {
|
||||
-webkit-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
#customize-theme-controls .control-section.current-panel > h3.accordion-section-title {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.customize-themes-panel.control-panel-content {
|
||||
position: absolute;
|
||||
right: -100%;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.in-themes-panel #customize-info,
|
||||
.in-themes-panel #customize-theme-controls > ul > .accordion-section {
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.themes-panel-back:before {
|
||||
top: 13px;
|
||||
right: 14px;
|
||||
}
|
||||
|
||||
.in-themes-panel .themes-panel-back {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.in-sub-panel .themes-panel-back {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.control-panel-back.themes-panel-back:before {
|
||||
content: "\f345";
|
||||
}
|
||||
|
||||
.rtl .control-panel-back.themes-panel-back:before {
|
||||
content: "\f341";
|
||||
}
|
||||
|
||||
/* Details View */
|
||||
.wp-customizer .theme-overlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wp-customizer.modal-open .theme-overlay {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 109;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-overlay .theme-backdrop {
|
||||
background: rgba( 238, 238, 238, 0.75 );
|
||||
position: fixed;
|
||||
z-index: 110;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-overlay .theme-wrap {
|
||||
right: 90px;
|
||||
left: 90px;
|
||||
top: 45px;
|
||||
bottom: 45px;
|
||||
z-index: 120;
|
||||
max-width: 1740px; /* To ensure that theme screenshots are not displayed larger than 880px wide. */
|
||||
}
|
||||
|
||||
.wp-customizer .theme-overlay .theme-actions {
|
||||
text-align: left; /* Because there's only one action, match the pattern of media modals and right-align the action. */
|
||||
}
|
||||
|
||||
.modal-open .in-themes-panel #customize-controls .wp-full-overlay-sidebar-content {
|
||||
overflow: visible; /* Prevent the top-level Customizer controls from becoming visible when elements on the right of the details modal are focused. */
|
||||
}
|
||||
|
||||
/* Small Screens */
|
||||
@media (max-width:850px), (max-height:472px) {
|
||||
.wp-customizer .theme-overlay .theme-wrap {
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Handle cheaters. */
|
||||
body.cheatin {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -827,6 +827,176 @@ p.customize-section-description {
|
|||
float: right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Themes
|
||||
*/
|
||||
@-webkit-keyframes customize-reload {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@-moz-keyframes customize-reload {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes customize-reload {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* #customize-container is reused from customize-loader.js, hence the naming. */
|
||||
.wp-customizer .customize-loading #customize-container {
|
||||
display: block;
|
||||
-webkit-animation: customize-reload .75s; /* Can't use `transition` because `display` changes here. */
|
||||
-moz-animation: customize-reload .75s;
|
||||
animation: customize-reload .75s;
|
||||
}
|
||||
|
||||
.customize-themes-panel {
|
||||
display: none;
|
||||
padding: 0 8px;
|
||||
background: #f1f1f1;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.control-section.open .customize-themes-panel {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#customize-theme-controls .customize-themes-panel .accordion-section-content {
|
||||
background: transparent;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.customize-control.customize-control-theme {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .themes {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .theme {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .theme .theme-actions {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#customize-controls h3.theme-name {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-browser .theme.active .theme-name {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.wp-customizer #themes-filter {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Panel-like behavior */
|
||||
#accordion-section-themes .accordion-section-title:after {
|
||||
content: "\f148";
|
||||
}
|
||||
|
||||
.rtl #accordion-section-themes .accordion-section-title:after {
|
||||
-webkit-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
#customize-theme-controls .control-section.current-panel > h3.accordion-section-title {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.customize-themes-panel.control-panel-content {
|
||||
position: absolute;
|
||||
left: -100%;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.in-themes-panel #customize-info,
|
||||
.in-themes-panel #customize-theme-controls > ul > .accordion-section {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.themes-panel-back:before {
|
||||
top: 13px;
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
.in-themes-panel .themes-panel-back {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.in-sub-panel .themes-panel-back {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.control-panel-back.themes-panel-back:before {
|
||||
content: "\f345";
|
||||
}
|
||||
|
||||
.rtl .control-panel-back.themes-panel-back:before {
|
||||
content: "\f341";
|
||||
}
|
||||
|
||||
/* Details View */
|
||||
.wp-customizer .theme-overlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wp-customizer.modal-open .theme-overlay {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 109;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-overlay .theme-backdrop {
|
||||
background: rgba( 238, 238, 238, 0.75 );
|
||||
position: fixed;
|
||||
z-index: 110;
|
||||
}
|
||||
|
||||
.wp-customizer .theme-overlay .theme-wrap {
|
||||
left: 90px;
|
||||
right: 90px;
|
||||
top: 45px;
|
||||
bottom: 45px;
|
||||
z-index: 120;
|
||||
max-width: 1740px; /* To ensure that theme screenshots are not displayed larger than 880px wide. */
|
||||
}
|
||||
|
||||
.wp-customizer .theme-overlay .theme-actions {
|
||||
text-align: right; /* Because there's only one action, match the pattern of media modals and right-align the action. */
|
||||
}
|
||||
|
||||
.modal-open .in-themes-panel #customize-controls .wp-full-overlay-sidebar-content {
|
||||
overflow: visible; /* Prevent the top-level Customizer controls from becoming visible when elements on the right of the details modal are focused. */
|
||||
}
|
||||
|
||||
/* Small Screens */
|
||||
@media (max-width:850px), (max-height:472px) {
|
||||
.wp-customizer .theme-overlay .theme-wrap {
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Handle cheaters. */
|
||||
body.cheatin {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -136,40 +136,17 @@ do_action( 'customize_controls_print_scripts' );
|
|||
<span class="control-panel-back" tabindex="-1"><span class="screen-reader-text"><?php _e( 'Back' ); ?></span></span>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$screenshot = $wp_customize->theme()->get_screenshot();
|
||||
$cannot_expand = ! ( $wp_customize->is_theme_active() || $screenshot || $wp_customize->theme()->get('Description') );
|
||||
?>
|
||||
|
||||
<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" tabindex="-1">
|
||||
<div id="customize-info" class="accordion-section <?php if ( $cannot_expand ) echo ' cannot-expand'; ?>">
|
||||
<div id="customize-info" class="accordion-section">
|
||||
<div class="accordion-section-title" aria-label="<?php esc_attr_e( 'Customizer Options' ); ?>" tabindex="0">
|
||||
<span class="preview-notice"><?php
|
||||
if ( ! $wp_customize->is_theme_active() ) {
|
||||
/* translators: %s is the theme name in the Customize/Live Preview pane */
|
||||
echo sprintf( __( 'You are previewing %s' ), '<strong class="theme-name">' . $wp_customize->theme()->display('Name') . '</strong>' );
|
||||
} else {
|
||||
/* translators: %s is the site/panel title in the Customize pane */
|
||||
echo sprintf( __( 'You are customizing %s' ), '<strong class="theme-name site-title">' . get_bloginfo( 'name' ) . '</strong>' );
|
||||
}
|
||||
echo sprintf( __( 'You are customizing %s' ), '<strong class="theme-name site-title">' . get_bloginfo( 'name' ) . '</strong>' );
|
||||
?></span>
|
||||
</div>
|
||||
<?php if ( ! $cannot_expand ) : ?>
|
||||
<div class="accordion-section-content">
|
||||
<?php if ( ! $wp_customize->is_theme_active() ) :
|
||||
if ( $screenshot ) : ?>
|
||||
<img class="theme-screenshot" src="<?php echo esc_url( $screenshot ); ?>" />
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $wp_customize->theme()->get('Description') ): ?>
|
||||
<div class="theme-description"><?php echo $wp_customize->theme()->display('Description'); ?></div>
|
||||
<?php endif;
|
||||
else:
|
||||
echo __( 'The Customizer allows you to preview changes to your site before publishing them. You can also navigate to different pages on your site to preview them.' );
|
||||
endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="accordion-section-content"><?php
|
||||
echo __( 'The Customizer allows you to preview changes to your site before publishing them. You can also navigate to different pages on your site to preview them.' );
|
||||
?></div>
|
||||
</div>
|
||||
|
||||
<div id="customize-theme-controls">
|
||||
|
@ -246,7 +223,7 @@ do_action( 'customize_controls_print_scripts' );
|
|||
'url' => array(
|
||||
'preview' => esc_url_raw( $url ? $url : home_url( '/' ) ),
|
||||
'parent' => esc_url_raw( admin_url() ),
|
||||
'activated' => esc_url_raw( admin_url( 'themes.php?activated=true&previewed' ) ),
|
||||
'activated' => esc_url_raw( home_url( '/' ) ),
|
||||
'ajax' => esc_url_raw( admin_url( 'admin-ajax.php', 'relative' ) ),
|
||||
'allowed' => array_map( 'esc_url_raw', $allowed_urls ),
|
||||
'isCrossDomain' => $cross_domain,
|
||||
|
|
|
@ -486,3 +486,58 @@ function wp_prepare_themes_for_js( $themes = null ) {
|
|||
$prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes );
|
||||
return array_values( $prepared_themes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print JS templates for the theme-browsing UI in the Customizer.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
function customize_themes_print_templates() {
|
||||
?>
|
||||
<script type="text/html" id="tmpl-customize-themes-details-view">
|
||||
<div class="theme-backdrop"></div>
|
||||
<div class="theme-wrap">
|
||||
<div class="theme-header">
|
||||
<button type="button" class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous theme' ); ?></span></button>
|
||||
<button type="button" class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next theme' ); ?></span></button>
|
||||
<button type="button" class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog' ); ?></span></button>
|
||||
</div>
|
||||
<div class="theme-about">
|
||||
<div class="theme-screenshots">
|
||||
<# if ( data.screenshot[0] ) { #>
|
||||
<div class="screenshot"><img src="{{ data.screenshot[0] }}" alt="" /></div>
|
||||
<# } else { #>
|
||||
<div class="screenshot blank"></div>
|
||||
<# } #>
|
||||
</div>
|
||||
|
||||
<div class="theme-info">
|
||||
<# if ( data.active ) { #>
|
||||
<span class="current-label"><?php _e( 'Current Theme' ); ?></span>
|
||||
<# } #>
|
||||
<h3 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></span></h3>
|
||||
<h4 class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' ); ?></h4>
|
||||
<p class="theme-description">{{{ data.description }}}</p>
|
||||
|
||||
<# if ( data.parent ) { #>
|
||||
<p class="parent-theme"><?php printf( __( 'This is a child theme of %s.' ), '<strong>{{{ data.parent }}}</strong>' ); ?></p>
|
||||
<# } #>
|
||||
|
||||
<# if ( data.tags ) { #>
|
||||
<p class="theme-tags"><span><?php _e( 'Tags:' ); ?></span> {{ data.tags }}</p>
|
||||
<# } #>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-actions">
|
||||
<# if ( ! data.active ) { #>
|
||||
<div class="inactive-theme">
|
||||
<a href="<?php echo add_query_arg( 'theme', '{{ data.id }}', remove_query_arg( 'theme' ) ); ?>" target="_top" class="button button-primary"><?php _e( 'Live Preview' ); ?></a>
|
||||
</div>
|
||||
<# } #>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
add_action( 'customize_controls_print_footer_scripts', 'customize_themes_print_templates' );
|
||||
|
|
|
@ -520,6 +520,351 @@
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.customize.ThemesSection
|
||||
*
|
||||
* Custom section for themes that functions similarly to a backwards panel,
|
||||
* and also handles the theme-details view rendering and navigation.
|
||||
*
|
||||
* @constructor
|
||||
* @augments wp.customize.Section
|
||||
* @augments wp.customize.Container
|
||||
*/
|
||||
api.ThemesSection = api.Section.extend({
|
||||
currentTheme: '',
|
||||
overlay: '',
|
||||
template: '',
|
||||
|
||||
/**
|
||||
* @since 4.2.0
|
||||
*/
|
||||
ready: function () {
|
||||
var section = this;
|
||||
section.overlay = section.container.find( '.theme-overlay' );
|
||||
section.template = wp.template( 'customize-themes-details-view' );
|
||||
|
||||
// Bind global keyboard events.
|
||||
$( 'body' ).on( 'keyup', function( event ) {
|
||||
if ( ! section.overlay.find( '.theme-wrap' ).is( ':visible' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pressing the right arrow key fires a theme:next event
|
||||
if ( 39 === event.keyCode ) {
|
||||
section.nextTheme();
|
||||
}
|
||||
|
||||
// Pressing the left arrow key fires a theme:previous event
|
||||
if ( 37 === event.keyCode ) {
|
||||
section.previousTheme();
|
||||
}
|
||||
|
||||
// Pressing the escape key fires a theme:collapse event
|
||||
if ( 27 === event.keyCode ) {
|
||||
section.closeDetails();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @since 4.2.0
|
||||
*/
|
||||
attachEvents: function () {
|
||||
var meta, section = this;
|
||||
|
||||
// Expand/Collapse section/panel.
|
||||
section.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault(); // Keep this AFTER the key filter above
|
||||
|
||||
if ( section.expanded() ) {
|
||||
section.collapse();
|
||||
} else {
|
||||
section.expand();
|
||||
}
|
||||
});
|
||||
|
||||
section.container.find( '.themes-panel-back' ).on( 'click keydown', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault(); // Keep this AFTER the key filter above
|
||||
|
||||
section.collapse();
|
||||
});
|
||||
|
||||
// Theme navigation in details view.
|
||||
section.container.on( 'click keydown', '.left', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault(); // Keep this AFTER the key filter above
|
||||
|
||||
section.previousTheme();
|
||||
});
|
||||
|
||||
section.container.on( 'click keydown', '.right', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault(); // Keep this AFTER the key filter above
|
||||
|
||||
section.nextTheme();
|
||||
});
|
||||
|
||||
section.container.on( 'click keydown', '.theme-backdrop, .close', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault(); // Keep this AFTER the key filter above
|
||||
|
||||
section.closeDetails();
|
||||
});
|
||||
|
||||
section.container.on( 'click keydown', '.theme-actions .button', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$( '.wp-full-overlay' ).addClass( 'customize-loading' );
|
||||
});
|
||||
|
||||
section.container.on( 'input', '#themes-filter', function( event ) {
|
||||
var term = event.currentTarget.value.toLowerCase().trim().replace( '-', ' ' ),
|
||||
controls = section.controls();
|
||||
controls.pop(); // Remove the last control (the add-new control).
|
||||
_.each( controls, function( control ) {
|
||||
control.filter( term );
|
||||
});
|
||||
// Update theme count. Note that the add-theme tile is a div.customize-control.
|
||||
count = section.container.find( 'li.customize-control:visible' ).length;
|
||||
section.container.find( '.theme-count' ).text( count );
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Update UI to reflect expanded state
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param {Boolean} expanded
|
||||
* @param {Object} args
|
||||
* @param {Boolean} args.unchanged
|
||||
* @param {Callback} args.completeCallback
|
||||
*/
|
||||
onChangeExpanded: function ( expanded, args ) {
|
||||
|
||||
// Immediately call the complete callback if there were no changes
|
||||
if ( args.unchanged ) {
|
||||
if ( args.completeCallback ) {
|
||||
args.completeCallback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: there is a second argument 'args' passed
|
||||
var position, scroll,
|
||||
panel = this,
|
||||
section = panel.container.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( '.themes-panel-back' ),
|
||||
panelTitle = section.find( '.accordion-section-title' ).first(),
|
||||
content = section.find( '.control-panel-content' );
|
||||
|
||||
if ( expanded ) {
|
||||
|
||||
// Collapse any sibling sections/panels
|
||||
api.section.each( function ( otherSection ) {
|
||||
if ( otherSection !== panel ) {
|
||||
otherSection.collapse( { duration: args.duration } );
|
||||
}
|
||||
});
|
||||
api.panel.each( function ( otherPanel ) {
|
||||
if ( panel !== otherPanel ) {
|
||||
otherPanel.collapse( { duration: 0 } );
|
||||
}
|
||||
});
|
||||
|
||||
content.show( 0, function() {
|
||||
position = content.offset().top;
|
||||
scroll = container.scrollTop();
|
||||
content.css( 'margin-top', ( 45 - position - scroll ) );
|
||||
section.addClass( 'current-panel' );
|
||||
overlay.addClass( 'in-themes-panel' );
|
||||
container.scrollTop( 0 );
|
||||
if ( args.completeCallback ) {
|
||||
args.completeCallback();
|
||||
}
|
||||
} );
|
||||
topPanel.attr( 'tabindex', '-1' );
|
||||
backBtn.attr( 'tabindex', '0' );
|
||||
backBtn.focus();
|
||||
} else {
|
||||
siblings.removeClass( 'open' );
|
||||
section.removeClass( 'current-panel' );
|
||||
overlay.removeClass( 'in-themes-panel' );
|
||||
content.delay( 180 ).hide( 0, function() {
|
||||
content.css( 'margin-top', 'inherit' ); // Reset
|
||||
if ( args.completeCallback ) {
|
||||
args.completeCallback();
|
||||
}
|
||||
} );
|
||||
topPanel.attr( 'tabindex', '0' );
|
||||
backBtn.attr( 'tabindex', '-1' );
|
||||
panelTitle.focus();
|
||||
container.scrollTop( 0 );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Advance the modal to the next theme.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
nextTheme: function () {
|
||||
var section = this;
|
||||
if ( section.getNextTheme() ) {
|
||||
section.showDetails( section.getNextTheme(), function() {
|
||||
section.overlay.find( '.right' ).focus();
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the next theme model.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
getNextTheme: function () {
|
||||
var control, next;
|
||||
control = api.control( 'theme_' + this.currentTheme );
|
||||
next = control.container.next( 'li.customize-control-theme' );
|
||||
if ( ! next.length ) {
|
||||
return false;
|
||||
}
|
||||
next = next[0].id.replace( 'customize-control-', '' );
|
||||
control = api.control( next );
|
||||
|
||||
return control.params.theme;
|
||||
},
|
||||
|
||||
/**
|
||||
* Advance the modal to the previous theme.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
previousTheme: function () {
|
||||
var section = this;
|
||||
if ( section.getPreviousTheme() ) {
|
||||
section.showDetails( section.getPreviousTheme(), function() {
|
||||
section.overlay.find( '.left' ).focus();
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the previous theme model.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
getPreviousTheme: function () {
|
||||
var control, previous;
|
||||
control = api.control( 'theme_' + this.currentTheme );
|
||||
previous = control.container.prev( 'li.customize-control-theme' );
|
||||
if ( ! previous.length ) {
|
||||
return false;
|
||||
}
|
||||
previous = previous[0].id.replace( 'customize-control-', '' );
|
||||
control = api.control( previous );
|
||||
|
||||
return control.params.theme;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable buttons when we're viewing the first or last theme.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
updateLimits: function () {
|
||||
if ( ! this.getNextTheme() ) {
|
||||
this.overlay.find( '.right' ).addClass( 'disabled' );
|
||||
}
|
||||
if ( ! this.getPreviousTheme() ) {
|
||||
this.overlay.find( '.left' ).addClass( 'disabled' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Render & show the theme details for a given theme model.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param {Object} theme
|
||||
*/
|
||||
showDetails: function ( theme, callback ) {
|
||||
var section = this;
|
||||
callback = callback || function(){};
|
||||
section.currentTheme = theme.id;
|
||||
section.overlay.html( section.template( theme ) )
|
||||
.fadeIn( 'fast' )
|
||||
.focus();
|
||||
$( 'body' ).addClass( 'modal-open' );
|
||||
section.containFocus( section.overlay );
|
||||
section.updateLimits();
|
||||
callback();
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the theme details modal.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
closeDetails: function ( theme ) {
|
||||
$( 'body' ).removeClass( 'modal-open' );
|
||||
this.overlay.fadeOut( 'fast' );
|
||||
api.control( 'theme_' + this.currentTheme ).focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Keep tab focus within the theme details modal.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
containFocus: function( el ) {
|
||||
var tabbables;
|
||||
|
||||
el.on( 'keydown', function( event ) {
|
||||
|
||||
// Return if it's not the tab key
|
||||
// When navigating with prev/next focus is already handled
|
||||
if ( 9 !== event.keyCode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// uses jQuery UI to get the tabbable elements
|
||||
tabbables = $( ':tabbable', el );
|
||||
|
||||
// Keep focus within the overlay
|
||||
if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
|
||||
tabbables.first().focus();
|
||||
return false;
|
||||
} else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
|
||||
tabbables.last().focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @since 4.1.0
|
||||
*
|
||||
|
@ -1409,6 +1754,63 @@
|
|||
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.customize.ThemeControl
|
||||
*
|
||||
* @constructor
|
||||
* @augments wp.customize.Control
|
||||
* @augments wp.customize.Class
|
||||
*/
|
||||
api.ThemeControl = api.Control.extend({
|
||||
|
||||
/**
|
||||
* @since 4.2.0
|
||||
*/
|
||||
ready: function() {
|
||||
var control = this;
|
||||
|
||||
// Bind details view trigger.
|
||||
control.container.on( 'click keydown', '.theme', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'button' === event.target.className ) {
|
||||
return;
|
||||
}
|
||||
|
||||
api.section( control.section() ).showDetails( control.params.theme );
|
||||
});
|
||||
|
||||
control.container.on( 'click keydown', '.theme-actions .button', function( event ) {
|
||||
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$( '.wp-full-overlay' ).addClass( 'customize-loading' );
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide the theme based on the presence of the term in the title, description, and author.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
filter: function( term ) {
|
||||
var control = this,
|
||||
haystack = control.params.theme.name + ' '
|
||||
+ control.params.theme.description + ' '
|
||||
+ control.params.theme.tags + ' '
|
||||
+ control.params.theme.author;
|
||||
haystack = haystack.toLowerCase().replace( '-', ' ' );
|
||||
if ( -1 !== haystack.search( term ) ) {
|
||||
control.activate();
|
||||
} else {
|
||||
control.deactivate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Change objects contained within the main customize object to Settings.
|
||||
api.defaultConstructor = api.Setting;
|
||||
|
||||
|
@ -1853,14 +2255,17 @@
|
|||
});
|
||||
|
||||
api.controlConstructor = {
|
||||
color: api.ColorControl,
|
||||
upload: api.UploadControl,
|
||||
image: api.ImageControl,
|
||||
header: api.HeaderControl,
|
||||
background: api.BackgroundControl
|
||||
color: api.ColorControl,
|
||||
upload: api.UploadControl,
|
||||
image: api.ImageControl,
|
||||
header: api.HeaderControl,
|
||||
background: api.BackgroundControl,
|
||||
theme: api.ThemeControl
|
||||
};
|
||||
api.panelConstructor = {};
|
||||
api.sectionConstructor = {};
|
||||
api.sectionConstructor = {
|
||||
themes: api.ThemesSection
|
||||
};
|
||||
|
||||
$( function() {
|
||||
api.settings = window._wpCustomizeSettings;
|
||||
|
@ -2273,6 +2678,9 @@
|
|||
// Prompt user with AYS dialog if leaving the Customizer with unsaved changes
|
||||
$( window ).on( 'beforeunload', function () {
|
||||
if ( ! api.state( 'saved' )() ) {
|
||||
var timeout = setTimeout( function() {
|
||||
overlay.removeClass( 'customize-loading' );
|
||||
}, 1 );
|
||||
return api.l10n.saveAlert;
|
||||
}
|
||||
} );
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -650,14 +650,33 @@ function wp_admin_bar_comments_menu( $wp_admin_bar ) {
|
|||
function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
|
||||
$wp_admin_bar->add_group( array( 'parent' => 'site-name', 'id' => 'appearance' ) );
|
||||
|
||||
if ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) )
|
||||
$wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'themes', 'title' => __('Themes'), 'href' => admin_url('themes.php') ) );
|
||||
|
||||
if ( ! current_user_can( 'edit_theme_options' ) )
|
||||
return;
|
||||
|
||||
$current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$customize_url = add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() );
|
||||
|
||||
if ( current_user_can( 'switch_themes' ) ) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'appearance',
|
||||
'id' => 'themes',
|
||||
'title' => __( 'Themes' ),
|
||||
'href' => admin_url( 'themes.php' ),
|
||||
'meta' => array(
|
||||
'class' => 'hide-if-customize',
|
||||
),
|
||||
) );
|
||||
|
||||
if ( current_user_can( 'customize' ) ) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'appearance',
|
||||
'id' => 'customize-themes',
|
||||
'title' => __( 'Themes' ),
|
||||
'href' => add_query_arg( urlencode( 'autofocus[section]' ), 'themes', $customize_url ), // urlencode() needed due to #16859
|
||||
'meta' => array(
|
||||
'class' => 'hide-if-no-customize',
|
||||
),
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( current_user_can( 'customize' ) ) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'appearance',
|
||||
|
@ -671,6 +690,10 @@ function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
|
|||
add_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( current_theme_supports( 'widgets' ) ) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'appearance',
|
||||
|
|
|
@ -1100,6 +1100,101 @@ class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize Theme Control Class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Customize
|
||||
* @since 4.2.0
|
||||
*/
|
||||
class WP_Customize_Theme_Control extends WP_Customize_Control {
|
||||
|
||||
public $type = 'theme';
|
||||
public $theme;
|
||||
|
||||
/**
|
||||
* Refresh the parameters passed to the JavaScript via JSON.
|
||||
*
|
||||
* @since 4.2.0
|
||||
* @uses WP_Customize_Control::to_json()
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['theme'] = $this->theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't render the control content from PHP, as it's rendered via JS on load.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function render_content() {}
|
||||
|
||||
/**
|
||||
* Render a JS template for theme display.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function content_template() {
|
||||
?>
|
||||
<div class="theme<# if ( data.theme.active ) { #> active<# } #>" tabindex="0" aria-describedby="{{ data.theme.id }}-action {{ data.theme.id }}-name">
|
||||
<# if ( data.theme.screenshot[0] ) { #>
|
||||
<div class="theme-screenshot">
|
||||
<img src="{{ data.theme.screenshot[0] }}" alt="" />
|
||||
</div>
|
||||
<# } else { #>
|
||||
<div class="theme-screenshot blank"></div>
|
||||
<# } #>
|
||||
<span class="more-details" id="{{ data.theme.id }}-action"><?php _e( 'Theme Details' ); ?></span>
|
||||
<div class="theme-author"><?php printf( __( 'By %s' ), '{{ data.theme.author }}' ); ?></div>
|
||||
|
||||
<# if ( data.theme.active ) { #>
|
||||
<h3 class="theme-name" id="{{ data.theme.id }}-name"><span><?php _ex( 'Previewing:', 'theme' ); ?></span> {{ data.theme.name }}</h3>
|
||||
<# } else { #>
|
||||
<h3 class="theme-name" id="{{ data.theme.id }}-name">{{ data.theme.name }}</h3>
|
||||
<# } #>
|
||||
|
||||
<# if ( ! data.theme.active ) { #>
|
||||
<div class="theme-actions">
|
||||
<a class="button" href="<?php echo add_query_arg( 'theme', '{{ data.theme.id }}', remove_query_arg( 'theme' ) ); ?>" target="_top"><?php _e( 'Live Preview' ); ?></a>
|
||||
</div>
|
||||
<# } #>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize New Theme Control Class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Customize
|
||||
* @since 4.2.0
|
||||
*/
|
||||
class WP_Customize_New_Theme_Control extends WP_Customize_Control {
|
||||
|
||||
/**
|
||||
* Render the new control.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function render() {
|
||||
if ( is_multisite() || ! current_user_can( 'install_themes') ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="theme add-new-theme">
|
||||
<a href="<?php echo admin_url( 'theme-install.php' ); ?>" target="_top">
|
||||
<div class="theme-screenshot">
|
||||
<span></span>
|
||||
</div>
|
||||
<h3 class="theme-name"><?php _e( 'Add New Theme' ); ?></h3>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget Area Customize Control Class
|
||||
*
|
||||
|
|
|
@ -1110,6 +1110,38 @@ final class WP_Customize_Manager {
|
|||
$this->register_control_type( 'WP_Customize_Upload_Control' );
|
||||
$this->register_control_type( 'WP_Customize_Image_Control' );
|
||||
$this->register_control_type( 'WP_Customize_Background_Image_Control' );
|
||||
$this->register_control_type( 'WP_Customize_Theme_Control' );
|
||||
|
||||
/* Themes */
|
||||
|
||||
$this->add_section( new WP_Customize_Themes_Section( $this, 'themes', array(
|
||||
'title' => sprintf( __( 'Theme: %s' ), $this->theme()->display('Name') ),
|
||||
'capability' => 'switch_themes',
|
||||
'priority' => 0,
|
||||
) ) );
|
||||
|
||||
// Themes Setting (unused - the theme is considerably more fundamental to the Customizer experience).
|
||||
$this->add_setting( new WP_Customize_Filter_Setting( $this, 'active_theme', array(
|
||||
'capability' => 'switch_themes',
|
||||
) ) );
|
||||
|
||||
require_once( ABSPATH . 'wp-admin/includes/theme.php' );
|
||||
|
||||
// Theme Controls.
|
||||
$themes = wp_prepare_themes_for_js();
|
||||
foreach ( $themes as $theme ) {
|
||||
$theme_id = 'theme_' . $theme['id'];
|
||||
$this->add_control( new WP_Customize_Theme_Control( $this, $theme_id, array(
|
||||
'theme' => $theme,
|
||||
'section' => 'themes',
|
||||
'settings' => 'active_theme',
|
||||
) ) );
|
||||
}
|
||||
|
||||
$this->add_control( new WP_Customize_New_Theme_Control( $this, 'add_theme', array(
|
||||
'section' => 'themes',
|
||||
'settings' => 'active_theme',
|
||||
) ) );
|
||||
|
||||
/* Site Title & Tagline */
|
||||
|
||||
|
|
|
@ -311,6 +311,57 @@ class WP_Customize_Section {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize Themes Section Class.
|
||||
*
|
||||
* A UI container for theme controls, which behaves like a backwards Panel.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Customize
|
||||
* @since 4.2.0
|
||||
*/
|
||||
class WP_Customize_Themes_Section extends WP_Customize_Section {
|
||||
|
||||
public $type = 'themes';
|
||||
|
||||
/**
|
||||
* Render the themes section, which behaves like a panel.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
protected function render() {
|
||||
$classes = 'accordion-section control-section control-section-' . $this->type;
|
||||
?>
|
||||
<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
|
||||
<h3 class="accordion-section-title" tabindex="0">
|
||||
<?php echo esc_html( $this->title ); ?>
|
||||
<span class="screen-reader-text"><?php _e( 'Press return or enter to expand' ); ?></span>
|
||||
</h3>
|
||||
<span class="control-panel-back themes-panel-back" tabindex="-1"><span class="screen-reader-text"><?php _e( 'Back' ); ?></span></span>
|
||||
<div class="customize-themes-panel control-panel-content themes-php">
|
||||
<h2><?php esc_html_e( 'Themes' ); ?>
|
||||
<span class="title-count theme-count"><?php echo count( $this->controls ) - 1; ?></span>
|
||||
<?php if ( ! is_multisite() && current_user_can( 'install_themes' ) ) : ?>
|
||||
<a href="<?php echo admin_url( 'theme-install.php' ); ?>" target="_top" class="add-new-h2"><?php echo esc_html_x( 'Add New', 'Add new theme' ); ?></a>
|
||||
<?php endif; ?>
|
||||
</h2>
|
||||
<div class="theme-overlay" tabindex="0" role="dialog" aria-label="<?php esc_attr_e( 'Theme details' ); ?>"></div>
|
||||
<div id="customize-container"></div>
|
||||
<?php if ( 6 < count( $this->controls ) ) : ?>
|
||||
<p><label for="themes-filter">
|
||||
<span class="screen-reader-text"><?php _e( 'Search installed themes...' ); ?></span>
|
||||
<input type="search" id="themes-filter" placeholder="<?php esc_attr_e( 'Search installed themes...' ); ?>" />
|
||||
</label></p>
|
||||
<?php endif; ?>
|
||||
<div class="theme-browser rendered">
|
||||
<ul class="themes accordion-section-content">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php }
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizer section representing widget area (sidebar).
|
||||
*
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '4.2-alpha-31532';
|
||||
$wp_version = '4.2-alpha-31533';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
*
|
||||
* @global int $wp_db_version
|
||||
*/
|
||||
$wp_db_version = 31351;
|
||||
$wp_db_version = 31532;
|
||||
|
||||
/**
|
||||
* Holds the TinyMCE version
|
||||
|
|
Loading…
Reference in New Issue