From 7edd9edde43b11a0b3867278a941a115c30126ff Mon Sep 17 00:00:00 2001 From: "Dominik Schilling (ocean90)" Date: Thu, 26 Jun 2014 20:16:21 +0000 Subject: [PATCH] Customizer: Introduce a "panel" API to organize multiple sections into a one section. Create a panel via `$GLOBALS['wp_customize']->add_panel( $panel_id, $args )` and use `$panel_id` for the `panel` argument in `$GLOBALS['wp_customize']->add_section( $section_id, $args )`. That's it. As an example all widget area sections are now summarized into one panel. Feedback appreciated. props celloexpressions. see #27406. git-svn-id: https://develop.svn.wordpress.org/trunk@28861 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/colors/_admin.scss | 5 + src/wp-admin/css/customize-controls.css | 146 +++++++++++++++++- src/wp-admin/customize.php | 6 +- src/wp-admin/js/accordion.js | 49 +++++- .../class-wp-customize-manager.php | 91 ++++++++++- .../class-wp-customize-section.php | 89 ++++++++++- .../class-wp-customize-widgets.php | 13 +- 7 files changed, 379 insertions(+), 20 deletions(-) diff --git a/src/wp-admin/css/colors/_admin.scss b/src/wp-admin/css/colors/_admin.scss index 2ce80049c3..eb869c6610 100644 --- a/src/wp-admin/css/colors/_admin.scss +++ b/src/wp-admin/css/colors/_admin.scss @@ -472,6 +472,11 @@ body.more-filters-opened .more-filters:focus:before { color: $menu-highlight-text; } +.control-panel-back:focus, +.control-panel-back:hover { + background-color: $menu-highlight-background; + color: $menu-highlight-text; +} /* jQuery UI Slider */ diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css index f966114735..a3ffbdf9c5 100644 --- a/src/wp-admin/css/customize-controls.css +++ b/src/wp-admin/css/customize-controls.css @@ -32,6 +32,11 @@ body { display: block; } +#customize-controls .wp-full-overlay-sidebar-content { + overflow-y: auto; + overflow-x: hidden; +} + #customize-info { border: none; border-top: 1px solid #ddd; @@ -83,11 +88,6 @@ body { line-height: 20px; } -#customize-theme-controls { - -webkit-box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1); -} - #customize-theme-controls .control-section { border: none; } @@ -103,7 +103,7 @@ body { background: white; } -#customize-theme-controls .control-section:hover .accordion-section-title, +#customize-theme-controls .control-section:hover > .accordion-section-title, #customize-theme-controls .control-section .accordion-section-title:hover, #customize-theme-controls .control-section.open .accordion-section-title, #customize-theme-controls .control-section .accordion-section-title:focus { @@ -118,7 +118,7 @@ body { background: #f5f5f5; } -#customize-theme-controls .control-section:hover .accordion-section-title::after, +#customize-theme-controls .control-section:hover > .accordion-section-title::after, #customize-theme-controls .control-section .accordion-section-title:hover::after, #customize-theme-controls .control-section.open .accordion-section-title::after, #customize-theme-controls .control-section .accordion-section-title:focus::after { @@ -143,6 +143,138 @@ body { margin: 0; } +.control-section.control-panel > .accordion-section-title:after { + content: "\f139"; +} + +.accordion-sub-container.control-panel-content { + display: none; + position: absolute; + left: 300px; + top: 0; + width: 300px; + border-top: 1px solid #ddd; + -webkit-transition: left ease-in-out .18s; + transition: left ease-in-out .18s; +} + +.accordion-sub-container.control-panel-content.animating { + display: block; +} + +.current-panel .accordion-sub-container.control-panel-content { + width: 100%; +} + +.control-panel-back { + display: block; + position: fixed; + top: 0; + z-index: 99; + left: -48px; + width: 45px; + height: 45px; + padding-right: 2px; + background: #eee; + border-right: 1px solid #ddd; + cursor: pointer; + -webkit-transition: left ease-in-out .18s, color ease-in .1s; + transition: left ease-in-out .18s, color ease-in .1s; +} + +.collapsed .control-panel-back { + display: none; +} + +.control-panel-back:focus, +.control-panel-back:hover { + background-color: #0074a2; + color: #fff; + outline: none; +} + +.control-panel-back:before { + font: normal 29px/1 dashicons; + content: "\f340"; + position: relative; + top: 9px; + left: 9px; +} + +.current-panel .control-panel-back { + left: 0; +} + +.current-panel > .accordion-section-title { + height: 22px; +} + +#customize-header-actions a.back { + position: relative; + left: 0; + -webkit-transition: left ease-in-out .18s; + transition: left ease-in-out .18s; +} + +.in-sub-panel #customize-header-actions a.back { + left: -120px; +} + +.wp-full-overlay-sidebar .wp-full-overlay-header { + -webkit-transition: padding ease-in-out .18s; + transition: padding ease-in-out .18s; +} + +.in-sub-panel .wp-full-overlay-sidebar .wp-full-overlay-header { + padding-left: 62px; +} + +#customize-info, +#customize-theme-controls > ul > .accordion-section { + position: relative; + left: 0; + -webkit-transition: left ease-in-out .18s; + transition: left ease-in-out .18s; +} + +.in-sub-panel #customize-info, +.in-sub-panel #customize-theme-controls > ul > .accordion-section { + left: -300px; + width: 300px; +} + +.in-sub-panel #customize-theme-controls .accordion-section.current-panel { + width: 100%; +} + +#customize-theme-controls .control-section.current-panel { + padding: 0; +} + +#customize-theme-controls .control-section > h3.accordion-section-title { + position: relative; + left: 0; +} + +#customize-theme-controls .control-section.current-panel > h3.accordion-section-title { + left: -300px; + -webkit-transition: left ease-in-out .18s; + transition: left ease-in-out .18s; +} + +.control-section.control-panel .accordion-section-title .panel-title { + font-size: 20px; + font-weight: 200; + line-height: 24px; + display: block; + border: none; +} + +.control-section.control-panel .preview-notice { + font-size: 13px; + line-height: 24px; +} + .customize-control { width: 100%; float: left; diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php index 1faf371cd9..29ae035599 100644 --- a/src/wp-admin/customize.php +++ b/src/wp-admin/customize.php @@ -142,8 +142,12 @@ do_action( 'customize_controls_print_scripts' );
diff --git a/src/wp-admin/js/accordion.js b/src/wp-admin/js/accordion.js index 7bc99ccca8..e2a6212b55 100644 --- a/src/wp-admin/js/accordion.js +++ b/src/wp-admin/js/accordion.js @@ -4,13 +4,26 @@ // Expand/Collapse on click $( '.accordion-container' ).on( 'click keydown', '.accordion-section-title', function( e ) { - if ( e.type === 'keydown' && 13 !== e.which ) // "return" key - return; + if ( e.type === 'keydown' && 13 !== e.which ) { // "return" key + return; + } + e.preventDefault(); // Keep this AFTER the key filter above accordionSwitch( $( this ) ); }); + // Back to top level + $( '.accordion-container' ).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( $( this ) ); + }); + // Re-initialize accordion when screen options are toggled $( '.hide-postbox-tog' ).click( function () { accordionInit(); @@ -33,8 +46,14 @@ siblings = section.closest( '.accordion-container' ).find( '.open' ), content = section.find( sectionContent ); - if ( section.hasClass( 'cannot-expand' ) ) + if ( section.hasClass( 'cannot-expand' ) ) { return; + } + + if ( section.hasClass( 'control-panel' ) ) { + panelSwitch( section ); + return; + } if ( section.hasClass( 'open' ) ) { section.toggleClass( 'open' ); @@ -49,6 +68,30 @@ accordionInit(); } + function panelSwitch( panel ) { + var position, + section = panel.closest( '.accordion-section' ), + container = section.closest( '.wp-full-overlay' ), + siblings = container.find( '.accordion-section.open' ), + content = section.find( '.control-panel-content' ); + + if ( section.hasClass( 'current-panel' ) ) { + section.toggleClass( 'current-panel' ); + container.toggleClass( 'in-sub-panel' ); + content.delay( 180 ).hide( 0, function() { + content.css( 'margin-top', 'inherit' ); // Reset + } ); + } else { + siblings.removeClass( 'open' ); + content.show( 0, function() { + position = content.offset().top; + content.css( 'margin-top', ( 45 - position ) ); + section.toggleClass( 'current-panel' ); + container.toggleClass( 'in-sub-panel' ); + } ); + } + } + // Initialize the accordion (currently just corner fixes) accordionInit(); diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index 42977cbf4e..7ec89ee904 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -45,6 +45,7 @@ final class WP_Customize_Manager { public $widgets; protected $settings = array(); + protected $panels = array(); protected $sections = array(); protected $controls = array(); @@ -314,6 +315,17 @@ final class WP_Customize_Manager { return $this->sections; } + /** + * Get the registered panels. + * + * @since 4.0.0 + * + * @return array + */ + public function panels() { + return $this->panels; + } + /** * Checks if the current theme is active. * @@ -647,6 +659,50 @@ final class WP_Customize_Manager { unset( $this->settings[ $id ] ); } + /** + * Add a customize panel. + * + * @since 4.0.0 + * + * @param WP_Customize_Panel|string $id Customize Panel object, or Panel ID. + * @param array $args Panel arguments. + */ + public function add_panel( $id, $args = array() ) { + if ( is_a( $id, 'WP_Customize_Panel' ) ) { + $panel = $id; + } + else { + $panel = new WP_Customize_Panel( $this, $id, $args ); + } + + $this->panels[ $panel->id ] = $panel; + } + + /** + * Retrieve a customize panel. + * + * @since 4.0.0 + * + * @param string $id Panel ID. + * @return WP_Customize_Panel + */ + public function get_panel( $id ) { + if ( isset( $this->panels[ $id ] ) ) { + return $this->panels[ $id ]; + } + } + + /** + * Remove a customize panel. + * + * @since 4.0.0 + * + * @param string $id Panel ID. + */ + public function remove_panel( $id ) { + unset( $this->panels[ $id ] ); + } + /** * Add a customize section. * @@ -749,7 +805,7 @@ final class WP_Customize_Manager { } /** - * Prepare settings and sections. + * Prepare panels, sections, and controls. * * For each, check if required related components exist, * whether the user has the necessary capabilities, @@ -763,8 +819,9 @@ final class WP_Customize_Manager { $controls = array(); foreach ( $this->controls as $id => $control ) { - if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() ) + if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() ) { continue; + } $this->sections[ $control->section ]->controls[] = $control; $controls[ $id ] = $control; @@ -778,13 +835,39 @@ final class WP_Customize_Manager { $sections = array(); foreach ( $this->sections as $section ) { - if ( ! $section->check_capabilities() || ! $section->controls ) + if ( ! $section->check_capabilities() || ! $section->controls ) { continue; + } usort( $section->controls, array( $this, '_cmp_priority' ) ); - $sections[] = $section; + + if ( ! $section->panel ) { + // Top-level section. + $sections[] = $section; + } else { + // This section belongs to a panel. + if ( isset( $this->panels [ $section->panel ] ) ) { + $this->panels[ $section->panel ]->sections[] = $section; + } + } } $this->sections = $sections; + + // Prepare panels. + // Reversing makes uasort sort by time added when conflicts occur. + $this->panels = array_reverse( $this->panels ); + uasort( $this->panels, array( $this, '_cmp_priority' ) ); + $panels = array(); + + foreach ( $this->panels as $panel ) { + if ( ! $panel->check_capabilities() || ! $panel->sections ) { + continue; + } + + usort( $panel->sections, array( $this, '_cmp_priority' ) ); + $panels[] = $panel; + } + $this->panels = $panels; } /** diff --git a/src/wp-includes/class-wp-customize-section.php b/src/wp-includes/class-wp-customize-section.php index 2cfae71a63..1082647ac9 100644 --- a/src/wp-includes/class-wp-customize-section.php +++ b/src/wp-includes/class-wp-customize-section.php @@ -37,6 +37,15 @@ class WP_Customize_Section { */ public $priority = 10; + /** + * Panel in which to show the section, making it a sub-section. + * + * @since 4.0.0 + * @access public + * @var string + */ + public $panel = ''; + /** * Capability required for the section. * @@ -162,8 +171,12 @@ class WP_Customize_Section { * @since 3.4.0 */ protected function render() { + $classes = 'control-section accordion-section'; + if ( $this->panel ) { + $classes .= ' control-subsection'; + } ?> -
  • +
  • title ); ?>