WordPress.org

Make WordPress Core

Ticket #34391: 34391_4.diff

File 34391_4.diff, 53.8 KB (added by delawski, 3 years ago)
  • src/wp-admin/css/common.css

    diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css
    index c699ad8..3d9014a 100644
    a b img { 
    33303330        display: none;
    33313331}
    33323332
    3333 .control-section .accordion-section-title {
     3333.control-section .accordion-section-title,
     3334.customize-pane-child .accordion-section-title {
    33343335        border-left: none;
    33353336        border-right: none;
    33363337        padding: 10px 10px 11px 14px;
    img { 
    33383339        background: #fff;
    33393340}
    33403341
    3341 .control-section .accordion-section-title:after {
     3342.control-section .accordion-section-title:after,
     3343.customize-pane-child .accordion-section-title:after {
    33423344        top: 11px;
    33433345}
    33443346
  • src/wp-admin/css/customize-controls.css

    diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
    index 5118b60..926bc3a 100644
    a b body { 
    7777        line-height: 24px;
    7878}
    7979
    80 #customize-controls .control-section .customize-section-title h3,
    81 #customize-controls .control-section h3.customize-section-title,
     80#customize-controls .customize-pane-child .customize-section-title h3,
     81#customize-controls .customize-pane-child h3.customize-section-title,
    8282#customize-controls .customize-info .panel-title {
    8383        font-size: 20px;
    8484        font-weight: 200;
    body { 
    229229        box-sizing: border-box;
    230230}
    231231
     232.wp-full-overlay #customize-controls .wp-full-overlay-sidebar-content {
     233        -webkit-transform: translate3d(0, 0, 0);
     234        transform: translate3d(0, 0, 0); /* Promote to separate layer to avoid full-screen repaints */
     235}
     236
     237#customize-info,
     238#customize-theme-controls .customize-pane-parent,
     239#customize-theme-controls .customize-pane-child {
     240        overflow: visible;
     241        width: 100%;
     242        margin: 0;
     243        padding: 0;
     244        -webkit-box-sizing: border-box;
     245        -moz-box-sizing: border-box;
     246        box-sizing: border-box;
     247        -webkit-transition: 0.36s -webkit-transform cubic-bezier(0.645, 0.045, 0.355, 1);
     248        transition: 0.36s -webkit-transform cubic-bezier(0.645, 0.045, 0.355, 1);
     249        transition: 0.36s transform cubic-bezier(0.645, 0.045, 0.355, 1);
     250        transition: 0.36s transform cubic-bezier(0.645, 0.045, 0.355, 1), 0.36s -webkit-transform cubic-bezier(0.645, 0.045, 0.355, 1); /* easeInOutCubic */
     251}
     252
     253#customize-info,
     254#customize-theme-controls .customize-pane-parent {
     255        position: relative;
     256        visibility: visible;
     257        height: auto;
     258        max-height: none;
     259        overflow: auto;
     260        -webkit-transform: none;
     261        -ms-transform: none;
     262        transform: none;
     263}
     264
     265#customize-theme-controls .customize-pane-child {
     266        position: absolute;
     267        top: 0;
     268        left: 0;
     269        visibility: hidden;
     270        height: 0;
     271        max-height: none;
     272        overflow: hidden;
     273        -webkit-transform: translateX(100%);
     274        -ms-transform: translateX(100%);
     275        transform: translateX(100%);
     276}
     277
     278#customize-theme-controls .customize-pane-child.open,
     279#customize-theme-controls .customize-pane-child.current-panel,
     280#customize-theme-controls .customize-themes-panel.customize-pane-child.current-panel {
     281        -webkit-transform: none;
     282        -ms-transform: none;
     283        transform: none;
     284}
     285
     286#customize-theme-controls .customize-themes-panel.customize-pane-child,
     287.section-open #customize-theme-controls .customize-pane-parent,
     288.in-sub-panel #customize-theme-controls .customize-pane-parent,
     289.section-open #customize-info,
     290.in-sub-panel #customize-info,
     291.in-sub-panel.section-open #customize-theme-controls .customize-pane-child.current-panel,
     292.in-themes-panel #customize-theme-controls .customize-pane-parent,
     293.in-themes-panel #customize-info {
     294        visibility: hidden;
     295        height: 0;
     296        overflow: hidden;
     297        -webkit-transform: translateX(-100%);
     298        -ms-transform: translateX(-100%);
     299        transform: translateX(-100%);
     300}
     301
     302.section-open #customize-theme-controls .customize-pane-parent.busy,
     303.in-sub-panel #customize-theme-controls .customize-pane-parent.busy,
     304.in-themes-panel #customize-theme-controls .customize-pane-parent.busy,
     305.section-open #customize-info.busy,
     306.in-sub-panel #customize-info.busy,
     307.in-themes-panel #customize-info.busy,
     308.busy.section-open.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel,
     309#customize-theme-controls .customize-pane-child.open,
     310#customize-theme-controls .customize-pane-child.current-panel,
     311#customize-theme-controls .customize-pane-child.busy {
     312        visibility: visible;
     313        height: auto;
     314        overflow: auto;
     315}
     316
     317.in-themes-panel #customize-theme-controls .customize-pane-parent,
     318.in-themes-panel #customize-info {
     319        -webkit-transform: translateX(100%);
     320        -ms-transform: translateX(100%);
     321        transform: translateX(100%);
     322}
     323
     324#customize-theme-controls .customize-pane-child.accordion-section-content,
     325#customize-theme-controls .customize-pane-child.accordion-sub-container {
     326        display: block;
     327        overflow-x: hidden;
     328}
     329
     330#customize-theme-controls .customize-pane-child.accordion-section-content {
     331        padding: 12px;
     332}
     333
    232334.customize-section-description-container {
    233335        margin-bottom: 15px;
    234336}
    h3.customize-section-title { 
    268370        color: #555;
    269371}
    270372
    271 #customize-theme-controls {
    272         position: relative;
    273         left: 0;
    274         -webkit-transition: .18s left ease-in-out;
    275         transition: .18s left ease-in-out;
    276 }
    277 
    278 .ios #customize-theme-controls {
    279         -webkit-transition: left 0s;
    280         transition: left 0s;
    281 }
    282 
    283 .section-open #customize-info,
    284 .section-open #customize-theme-controls {
    285         left: -100%;
    286 }
    287 
    288373.accordion-sub-container.control-panel-content {
    289374        display: none;
    290375        position: absolute;
    291         left: 100%;
    292376        top: 0;
    293377        width: 100%;
    294         -webkit-transition: left ease-in-out .18s;
    295         transition: left ease-in-out .18s;
    296 }
    297 
    298 .ios .accordion-sub-container.control-panel-content {
    299         -webkit-transition: left 0s;
    300         transition: left 0s;
    301378}
    302379
    303 .accordion-sub-container.control-panel-content.animating {
     380.accordion-sub-container.control-panel-content.busy {
    304381        display: block;
    305382}
    306383
    h3.customize-section-title { 
    343420        -webkit-box-shadow: none;
    344421        box-shadow: none;
    345422        cursor: pointer;
    346         -webkit-transition: left .18s ease-in-out, color .1s ease-in-out, background .1s ease-in-out;
    347         transition: left .18s ease-in-out, color .1s ease-in-out, background .1s ease-in-out;
     423        -webkit-transition: color .1s ease-in-out, background .1s ease-in-out;
     424        transition: color .1s ease-in-out, background .1s ease-in-out;
    348425}
    349426
    350427.customize-section-back {
    351428        height: 74px;
    352429}
    353430
    354 .ios .customize-panel-back,
    355 .ios .customize-section-back {
    356         -webkit-transition: left 0s;
    357         transition: left 0s;
    358 }
    359 
    360431.ios .customize-panel-back {
    361432        display: none;
    362433}
    h3.customize-section-title { 
    423494        padding-left: 62px;
    424495}
    425496
    426 #customize-info,
    427 #customize-theme-controls > ul > .accordion-section {
    428         position: relative;
    429         left: 0;
    430         -webkit-transition: left ease-in-out .18s;
    431         transition: left ease-in-out .18s;
    432 }
    433 
    434 .ios #customize-info,
    435 .ios #customize-theme-controls > ul > .accordion-section {
    436         -webkit-transition: left 0s;
    437         transition: left 0s;
    438 }
    439 
    440 .in-sub-panel #customize-info,
    441 .in-sub-panel #customize-theme-controls > ul > .accordion-section {
    442         left: -100%;
    443         width: 100%;
    444 }
    445 
    446 .in-sub-panel #customize-theme-controls .accordion-section.current-panel {
    447         width: 100%;
    448 }
    449 
    450 #customize-theme-controls .control-section.current-panel {
    451         padding: 0;
    452 }
    453 
    454 #customize-theme-controls .control-section > h3.accordion-section-title {
    455         position: relative;
    456         left: 0;
    457 }
    458 
    459 #customize-theme-controls .control-section.current-panel > h3.accordion-section-title {
    460         left: -354px;
    461         -webkit-transition: left ease-in-out .18s;
    462         transition: left ease-in-out .18s;
    463 }
    464 
    465 .ios #customize-theme-controls .control-section.current-panel > h3.accordion-section-title {
    466         -webkit-transition: left 0s;
    467         transition: left 0s;
    468 }
    469 
    470 .wp-full-overlay.section-open #customize-controls .wp-full-overlay-sidebar-content {
    471         visibility: hidden;
    472         overflow-y: hidden;
    473 }
    474 
    475 .wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open {
    476         visibility: visible;
    477 }
    478 
    479 .wp-full-overlay.section-open .wp-full-overlay-sidebar-content .accordion-section.open .accordion-section-content {
    480         overflow-y: auto;
    481 }
    482 
    483497p.customize-section-description {
    484498        font-style: normal;
    485499        margin-top: 22px;
    p.customize-section-description { 
    10081022        margin: 15px 0;
    10091023}
    10101024
    1011 .customize-themes-panel .accordion-section-title {
     1025#customize-controls .customize-themes-panel .accordion-section-title {
    10121026        margin: 15px -8px;
    10131027}
    10141028
    1015 .control-section-themes .accordion-section-title {
     1029#customize-controls .control-section-themes .accordion-section-title,
     1030#customize-controls .customize-themes-panel .accordion-section-title {
    10161031        padding-right: 100px; /* Space for the button */
    10171032}
    10181033
    1019 .control-section-themes .accordion-section-title span.customize-action,
     1034#customize-controls .control-section-themes .accordion-section-title span.customize-action,
    10201035#customize-controls .customize-section-title span.customize-action {
    10211036        font-size: 13px;
    10221037        display: block;
    10231038        font-weight: 400;
    10241039}
    10251040
    1026 .control-section-themes .accordion-section-title .change-theme,
    1027 .control-section-themes .accordion-section-title .customize-theme {
     1041#customize-controls .control-section-themes .accordion-section-title .change-theme,
     1042#customize-controls .customize-themes-panel .accordion-section-title .customize-theme {
    10281043        position: absolute;
    10291044        right: 10px;
    10301045        top: 50%;
    p.customize-section-description { 
    10321047        font-weight: 400;
    10331048}
    10341049
    1035 .control-section-themes .accordion-section-title:before {
     1050#customize-controls .control-section-themes .accordion-section-title:before {
    10361051        display: none;
    10371052}
    10381053
    1039 .customize-themes-panel {
    1040         display: none;
     1054#customize-controls .customize-themes-panel {
    10411055        padding: 0 8px;
    10421056        background: #f1f1f1;
    10431057        -webkit-box-sizing: border-box;
    p.customize-section-description { 
    10451059        box-sizing: border-box;
    10461060}
    10471061
    1048 .customize-themes-panel .accordion-section-title:first-child {
     1062#customize-controls .customize-themes-panel .accordion-section-title:first-child {
    10491063        margin-top: 0;
    10501064}
    10511065
    p.customize-section-description { 
    10541068        font-weight: 600;
    10551069}
    10561070
    1057 .customize-themes-panel > h2 {
     1071#customize-controls .customize-themes-panel > h2 {
    10581072        padding: 15px 8px 0 8px;
    10591073}
    10601074
    1061 .control-section.open .customize-themes-panel {
    1062         display: block;
    1063 }
    1064 
    10651075#customize-theme-controls .customize-themes-panel .accordion-section-content {
    10661076        background: transparent;
    10671077        display: block;
    p.customize-section-description { 
    11071117        width: 100%;
    11081118}
    11091119
    1110 #accordion-section-themes .accordion-section-title:after {
     1120.control-section-themes .accordion-section-title:after,
     1121.customize-themes-panel .accordion-section-title:after {
    11111122        display: none;
    11121123}
    11131124
    1114 #customize-theme-controls .control-section-themes.current-panel > h3.accordion-section-title {
    1115         left: 0;
    1116 }
    1117 
    11181125.customize-themes-panel.control-panel-content {
    1119         position: absolute;
    1120         left: -100%;
    1121         top: 0;
    1122         width: 100%;
    11231126        border-top: 1px solid #ddd;
    11241127}
    11251128
    1126 .in-themes-panel #customize-info,
    1127 .in-themes-panel #customize-theme-controls > ul > .accordion-section {
    1128         left: 100%;
    1129 }
    1130 
    11311129/* Details View */
    11321130.wp-customizer .theme-overlay {
    11331131        display: none;
    p.customize-section-description { 
    11611159        text-align: right; /* Because there's only one action, match the pattern of media modals and right-align the action. */
    11621160}
    11631161
    1164 .modal-open .in-themes-panel #customize-controls .wp-full-overlay-sidebar-content {
    1165         overflow: visible; /* Prevent the top-level Customizer controls from becoming visible when elements on the right of the details modal are focused. */
     1162.in-themes-panel #customize-controls .wp-full-overlay-sidebar-content {
     1163        -webkit-transform: none;
     1164        -ms-transform: none;
     1165        transform: none; /* Prevent creating new stacking contexts and containing blocks for themes modal. */
    11661166}
    11671167
    11681168.ie8 .wp-customizer .theme-overlay .theme-header,
  • src/wp-admin/css/customize-nav-menus.css

    diff --git a/src/wp-admin/css/customize-nav-menus.css b/src/wp-admin/css/customize-nav-menus.css
    index e2d5b46..7ecb9c0 100644
    a b  
    381381.reordering .menu-item-depth-10 > .menu-item-bar { margin-right: 150px; }
    382382.reordering .menu-item-depth-11 > .menu-item-bar { margin-right: 165px; }
    383383
    384 .control-section-nav_menu .menu .menu-item-edit-active {
     384.accordion-section-content.menu .menu-item-edit-active {
    385385        margin-left: 0;
    386386}
    387387
    388 .control-section-nav_menu .menu .menu-item-edit-active .menu-item-bar {
     388.accordion-section-content.menu .menu-item-edit-active .menu-item-bar {
    389389        margin-right: 0;
    390390}
    391391
    392 .control-section-nav_menu .menu .sortable-placeholder {
     392.accordion-section-content.menu .sortable-placeholder {
    393393        margin-top: 0;
    394394        margin-bottom: 1px;
    395395        max-width: -webkit-calc(100% - 2px);
     
    403403        float: none;
    404404}
    405405
    406 .control-section-nav_menu .menu ul.menu-item-transport .menu-item-bar {
     406.accordion-section-content.menu ul.menu-item-transport .menu-item-bar {
    407407        margin-top: 0;
    408408}
    409409
  • src/wp-admin/customize.php

    diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php
    index bd8e118..6c0b20d 100644
    a b  
    142142                        </div>
    143143
    144144                        <div id="customize-theme-controls">
    145                                 <ul><?php // Panels and sections are managed here via JavaScript ?></ul>
     145                                <ul class="customize-pane-parent"><?php // Panels and sections are managed here via JavaScript ?></ul>
    146146                        </div>
    147147                </div>
    148148                </div>
  • src/wp-admin/js/customize-controls.js

    diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
    index 7078cfd..fd54464 100644
    a b  
    11/* global _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer */
    22(function( exports, $ ){
    3         var Container, focus, api = wp.customize;
     3        var Container, focus, normalizedTransitionendEventName, api = wp.customize;
    44
    55        /**
    66         * A Customizer Setting.
     
    101101                params = params || {};
    102102                focus = function () {
    103103                        var focusContainer;
    104                         if ( construct.extended( api.Panel ) && construct.expanded && construct.expanded() ) {
    105                                 focusContainer = construct.container.find( 'ul.control-panel-content' );
    106                         } else if ( construct.extended( api.Section ) && construct.expanded && construct.expanded() ) {
    107                                 focusContainer = construct.container.find( 'ul.accordion-section-content' );
     104                        if ( ( construct.extended( api.Panel ) || construct.extended( api.Section ) ) && construct.expanded && construct.expanded() ) {
     105                                focusContainer = construct.contentContainer;
    108106                        } else {
    109107                                focusContainer = construct.container;
    110108                        }
     
    188186        };
    189187
    190188        /**
     189         * Return browser supported `transitionend` event name
     190         *
     191         * @since
     192         *
     193         * @returns {String}
     194         */
     195        normalizedTransitionendEventName = (function () {
     196                var el, transitions, prop;
     197                el = document.createElement( 'div' );
     198                transitions = {
     199                        'transition'      : 'transitionend',
     200                        'OTransition'     : 'oTransitionEnd',
     201                        'MozTransition'   : 'transitionend',
     202                        'WebkitTransition': 'webkitTransitionEnd'
     203                };
     204                prop = _.find( _.keys( transitions ), function( prop ) {
     205                        return ! _.isUndefined( el.style[ prop ] );
     206                } );
     207                if ( prop ) {
     208                        return transitions[ prop ];
     209                } else {
     210                        return null;
     211                }
     212        })();
     213
     214        /**
    191215         * Base class for Panel and Section.
    192216         *
    193217         * @since 4.1.0
     
    238262                        if ( 0 === container.container.length ) {
    239263                                container.container = $( container.getContainer() );
    240264                        }
     265                        container.headContainer = container.container;
     266                        container.contentContainer = container._getContent();
     267                        container.container = container.container.add( container.contentContainer );
    241268
    242269                        container.deferred = {
    243270                                embedded: new $.Deferred()
     
    325352                 * @param {Object}  args.completeCallback
    326353                 */
    327354                onChangeActive: function( active, args ) {
    328                         var duration, construct = this, expandedOtherPanel;
     355                        var construct = this,
     356                                headContainer = construct.headContainer,
     357                                duration, expandedOtherPanel;
     358
    329359                        if ( args.unchanged ) {
    330360                                if ( args.completeCallback ) {
    331361                                        args.completeCallback();
     
    352382                                }
    353383                        }
    354384
    355                         if ( ! $.contains( document, construct.container[0] ) ) {
     385                        if ( ! $.contains( document, headContainer ) ) {
    356386                                // jQuery.fn.slideUp is not hiding an element if it is not in the DOM
    357                                 construct.container.toggle( active );
     387                                headContainer.toggle( active );
    358388                                if ( args.completeCallback ) {
    359389                                        args.completeCallback();
    360390                                }
    361391                        } else if ( active ) {
    362                                 construct.container.stop( true, true ).slideDown( duration, args.completeCallback );
     392                                headContainer.stop( true, true ).slideDown( duration, args.completeCallback );
    363393                        } else {
    364394                                if ( construct.expanded() ) {
    365395                                        construct.collapse({
    366396                                                duration: duration,
    367397                                                completeCallback: function() {
    368                                                         construct.container.stop( true, true ).slideUp( duration, args.completeCallback );
     398                                                        headContainer.stop( true, true ).slideUp( duration, args.completeCallback );
    369399                                                }
    370400                                        });
    371401                                } else {
    372                                         construct.container.stop( true, true ).slideUp( duration, args.completeCallback );
     402                                        headContainer.stop( true, true ).slideUp( duration, args.completeCallback );
    373403                                }
    374404                        }
    375 
    376                         // Recalculate the margin-top immediately, not waiting for debounced reflow, to prevent momentary (100ms) vertical jiggle.
    377                         if ( expandedOtherPanel ) {
    378                                 expandedOtherPanel._recalculateTopMargin();
    379                         }
    380405                },
    381406
    382407                /**
     
    483508                },
    484509
    485510                /**
     511                 * Animate container state change if transitions are supported by the browser.
     512                 *
     513                 * @param {function} completeCallback Function to be called after transition is completed.
     514                 * @private
     515                 */
     516                _animateChangeExpanded: function( completeCallback ) {
     517                        // Return if CSS transitions are not supported.
     518                        if ( ! normalizedTransitionendEventName ) {
     519                                if ( completeCallback ) {
     520                                        completeCallback();
     521                                }
     522                                return;
     523                        }
     524
     525                        var construct = this,
     526                                content = construct.contentContainer,
     527                                overlay = content.closest( '.wp-full-overlay' ),
     528                                elements, transitionEndCallback;
     529
     530                        // Determine set of elements that are affected by the animation.
     531                        elements = overlay.add( content );
     532                        if ( _.isUndefined( construct.panel ) || '' === construct.panel() ) {
     533                                        elements = elements.add( '#customize-info, .customize-pane-parent' );
     534                        }
     535
     536                        // Handle `transitionEnd` event.
     537                        transitionEndCallback = function( e ) {
     538                                if ( 2 !== e.eventPhase || ! $( e.target ).is( content ) ) {
     539                                        return;
     540                                }
     541                                content.off( normalizedTransitionendEventName, transitionEndCallback );
     542                                elements.removeClass( 'busy' );
     543                                if ( completeCallback ) {
     544                                        completeCallback();
     545                                }
     546                        };
     547                        content.on( normalizedTransitionendEventName, transitionEndCallback );
     548                        elements.addClass( 'busy' );
     549
     550                        // Prevent screen flicker when pane has been scrolled before expanding.
     551                        _.defer( function() {
     552                                var container = content.closest( '.wp-full-overlay-sidebar-content' ),
     553                                        currentScrollTop = container.scrollTop(),
     554                                        previousScrollTop = content.data( 'previous-scrollTop' ) || 0,
     555                                        expanded = construct.expanded();
     556
     557                                if ( expanded && 0 < currentScrollTop ) {
     558                                        content.css( 'top', currentScrollTop + 'px' );
     559                                        content.data( 'previous-scrollTop', currentScrollTop );
     560                                } else if ( ! expanded && 0 < currentScrollTop + previousScrollTop ) {
     561                                        content.css( 'top', previousScrollTop - currentScrollTop + 'px' );
     562                                        container.scrollTop( previousScrollTop );
     563                                }
     564                        } );
     565                },
     566
     567                /**
    486568                 * Bring the container into view and then expand this and bring it into view
    487569                 * @param {Object} [params]
    488570                 */
     
    507589                        }
    508590
    509591                        return '<li></li>';
     592                },
     593
     594                /**
     595                 * Find content element, relate it to the parent container with `aria-owns`, detach and return.
     596                 *
     597                 * @returns {Object}
     598                 * @private
     599                 */
     600                _getContent: function() {
     601                        var container = this,
     602                                content = container.container.find( '.accordion-section-content, .control-panel-content' ).first(),
     603                                contentId = 'sub-accordion-list-' + container.id,
     604                                ownedElements = contentId,
     605                                alreadyOwnedElements = container.container.attr( 'aria-owns' );
     606
     607                        if ( alreadyOwnedElements ) {
     608                                ownedElements = ownedElements + ' ' + alreadyOwnedElements;
     609                        }
     610                        container.container.attr( 'aria-owns', ownedElements );
     611
     612                        return content.detach().attr( {
     613                                'id': contentId,
     614                                'class': 'customize-pane-child ' + content.attr( 'class' )
     615                        } );
    510616                }
    511617        });
    512618
     
    552658                        section.id = id;
    553659                        section.panel = new api.Value();
    554660                        section.panel.bind( function ( id ) {
    555                                 $( section.container ).toggleClass( 'control-subsection', !! id );
     661                                $( section.headContainer ).toggleClass( 'control-subsection', !! id );
    556662                        });
    557663                        section.panel.set( section.params.panel || '' );
    558664                        api.utils.bubbleChildValueChanges( section, [ 'panel' ] );
     
    569675                 * @since 4.1.0
    570676                 */
    571677                embed: function () {
    572                         var section = this, inject;
     678                        var inject,
     679                                section = this,
     680                                container = $( '#customize-theme-controls' );
    573681
    574682                        // Watch for changes to the panel state
    575683                        inject = function ( panelId ) {
     
    579687                                        api.panel( panelId, function ( panel ) {
    580688                                                // The panel has been registered, wait for it to become ready/initialized
    581689                                                panel.deferred.embedded.done( function () {
    582                                                         parentContainer = panel.container.find( 'ul:first' );
    583                                                         if ( ! section.container.parent().is( parentContainer ) ) {
    584                                                                 parentContainer.append( section.container );
     690                                                        parentContainer = panel.contentContainer;
     691                                                        if ( ! section.headContainer.parent().is( parentContainer ) ) {
     692                                                                parentContainer.append( section.headContainer );
     693                                                        }
     694                                                        if ( ! section.contentContainer.parent().is( section.headContainer ) ) {
     695                                                                container.append( section.contentContainer );
    585696                                                        }
    586697                                                        section.deferred.embedded.resolve();
    587698                                                });
    588699                                        } );
    589700                                } else {
    590701                                        // There is no panel, so embed the section in the root of the customizer
    591                                         parentContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
    592                                         if ( ! section.container.parent().is( parentContainer ) ) {
    593                                                 parentContainer.append( section.container );
     702                                        parentContainer = $( '.customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable
     703                                        if ( ! section.headContainer.parent().is( parentContainer ) ) {
     704                                                parentContainer.append( section.headContainer );
     705                                        }
     706                                        if ( ! section.contentContainer.parent().is( section.headContainer ) ) {
     707                                                container.append( section.contentContainer );
    594708                                        }
    595709                                        section.deferred.embedded.resolve();
    596710                                }
    597711                        };
    598712                        section.panel.bind( inject );
    599713                        inject( section.panel.get() ); // Since a section may never get a panel, assume that it won't ever get one
    600 
    601                         section.deferred.embedded.done(function() {
    602                                 // Fix the top margin after reflow.
    603                                 api.bind( 'pane-contents-reflowed', _.debounce( function() {
    604                                         section._recalculateTopMargin();
    605                                 }, 100 ) );
    606                         });
    607714                },
    608715
    609716                /**
     
    669776                 */
    670777                onChangeExpanded: function ( expanded, args ) {
    671778                        var section = this,
    672                                 container = section.container.closest( '.wp-full-overlay-sidebar-content' ),
    673                                 content = section.container.find( '.accordion-section-content' ),
    674                                 overlay = section.container.closest( '.wp-full-overlay' ),
    675                                 backBtn = section.container.find( '.customize-section-back' ),
    676                                 sectionTitle = section.container.find( '.accordion-section-title' ).first(),
    677                                 headerActionsHeight = $( '#customize-header-actions' ).height(),
    678                                 resizeContentHeight, expand, position, scroll;
     779                                container = section.headContainer.closest( '.wp-full-overlay-sidebar-content' ),
     780                                content = section.contentContainer,
     781                                overlay = section.headContainer.closest( '.wp-full-overlay' ),
     782                                backBtn = content.find( '.customize-section-back' ),
     783                                sectionTitle = section.headContainer.find( '.accordion-section-title' ).first(),
     784                                expand;
    679785
    680                         if ( expanded && ! section.container.hasClass( 'open' ) ) {
     786                        if ( expanded && ! content.hasClass( 'open' ) ) {
    681787
    682788                                if ( args.unchanged ) {
    683789                                        expand = args.completeCallback;
    684790                                } else {
    685                                         container.scrollTop( 0 );
    686                                         resizeContentHeight = function() {
    687                                                 var matchMedia, offset;
    688                                                 matchMedia = window.matchMedia || window.msMatchMedia;
    689                                                 offset = 90; // 45px for customize header actions + 45px for footer actions.
    690 
    691                                                 // No footer on small screens.
    692                                                 if ( matchMedia && matchMedia( '(max-width: 640px)' ).matches ) {
    693                                                         offset = 45;
    694                                                 }
    695                                                 content.css( 'height', ( window.innerHeight - offset ) );
    696                                         };
    697                                         expand = function() {
    698                                                 section.container.addClass( 'open' );
    699                                                 overlay.addClass( 'section-open' );
    700                                                 position = content.offset().top;
    701                                                 scroll = container.scrollTop();
    702                                                 content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
    703                                                 resizeContentHeight();
    704                                                 sectionTitle.attr( 'tabindex', '-1' );
    705                                                 backBtn.attr( 'tabindex', '0' );
    706                                                 backBtn.focus();
    707                                                 if ( args.completeCallback ) {
    708                                                         args.completeCallback();
    709                                                 }
     791                                        expand = $.proxy( function() {
     792                                                section._animateChangeExpanded( function() {
     793                                                        sectionTitle.attr( 'tabindex', '-1' );
     794                                                        backBtn.attr( 'tabindex', '0' );
    710795
    711                                                 // Fix the height after browser resize.
    712                                                 $( window ).on( 'resize.customizer-section', _.debounce( resizeContentHeight, 100 ) );
     796                                                        backBtn.focus();
     797                                                        content.css( 'top', '' );
     798                                                        container.scrollTop( 0 );
    713799
    714                                                 setTimeout( _.bind( section._recalculateTopMargin, section ), 0 );
    715                                         };
     800                                                        if ( args.completeCallback ) {
     801                                                                args.completeCallback();
     802                                                        }
     803                                                } );
     804
     805                                                content.addClass( 'open' );
     806                                                overlay.addClass( 'section-open' );
     807                                        }, this );
    716808                                }
    717809
    718810                                if ( ! args.allowMultiple ) {
     
    735827                                        expand();
    736828                                }
    737829
    738                         } else if ( ! expanded && section.container.hasClass( 'open' ) ) {
    739                                 section.container.removeClass( 'open' );
     830                        } else if ( ! expanded && content.hasClass( 'open' ) ) {
     831                                section._animateChangeExpanded( function() {
     832                                        backBtn.attr( 'tabindex', '-1' );
     833                                        sectionTitle.attr( 'tabindex', '0' );
     834
     835                                        sectionTitle.focus();
     836                                        content.css( 'top', '' );
     837
     838                                        if ( args.completeCallback ) {
     839                                                args.completeCallback();
     840                                        }
     841                                } );
     842
     843                                content.removeClass( 'open' );
    740844                                overlay.removeClass( 'section-open' );
    741                                 content.css( 'margin-top', '' );
    742                                 container.scrollTop( 0 );
    743                                 backBtn.attr( 'tabindex', '-1' );
    744                                 sectionTitle.attr( 'tabindex', '0' );
    745                                 sectionTitle.focus();
    746                                 if ( args.completeCallback ) {
    747                                         args.completeCallback();
    748                                 }
    749                                 $( window ).off( 'resize.customizer-section' );
     845
    750846                        } else {
    751847                                if ( args.completeCallback ) {
    752848                                        args.completeCallback();
    753849                                }
    754850                        }
    755                 },
    756 
    757                 /**
    758                  * Recalculate the top margin.
    759                  *
    760                  * @since 4.4.0
    761                  * @private
    762                  */
    763                 _recalculateTopMargin: function() {
    764                         var section = this, content, offset, headerActionsHeight;
    765                         content = section.container.find( '.accordion-section-content' );
    766                         if ( 0 === content.length ) {
    767                                 return;
    768                         }
    769                         headerActionsHeight = $( '#customize-header-actions' ).height();
    770                         offset = ( content.offset().top - headerActionsHeight );
    771                         if ( 0 < offset ) {
    772                                 content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - offset ) );
    773                         }
    774851                }
    775852        });
    776853
     
    804881                 */
    805882                ready: function () {
    806883                        var section = this;
    807                         section.overlay = section.container.find( '.theme-overlay' );
     884                        section.overlay = section.contentContainer.find( '.theme-overlay' );
    808885                        section.template = wp.template( 'customize-themes-details-view' );
    809886
    810887                        // Bind global keyboard events.
     
    851928                 * @since 4.2.0
    852929                 */
    853930                attachEvents: function () {
    854                         var section = this;
     931                        var section = this,
     932                                content = section.contentContainer;
    855933
    856934                        // Expand/Collapse section/panel.
    857935                        section.container.find( '.change-theme, .customize-theme' ).on( 'click keydown', function( event ) {
     
    868946                        });
    869947
    870948                        // Theme navigation in details view.
    871                         section.container.on( 'click keydown', '.left', function( event ) {
     949                        content.on( 'click keydown', '.left', function( event ) {
    872950                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    873951                                        return;
    874952                                }
     
    878956                                section.previousTheme();
    879957                        });
    880958
    881                         section.container.on( 'click keydown', '.right', function( event ) {
     959                        content.on( 'click keydown', '.right', function( event ) {
    882960                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    883961                                        return;
    884962                                }
     
    888966                                section.nextTheme();
    889967                        });
    890968
    891                         section.container.on( 'click keydown', '.theme-backdrop, .close', function( event ) {
     969                        content.on( 'click keydown', '.theme-backdrop, .close', function( event ) {
    892970                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    893971                                        return;
    894972                                }
     
    899977                        });
    900978
    901979                        var renderScreenshots = _.throttle( _.bind( section.renderScreenshots, this ), 100 );
    902                         section.container.on( 'input', '#themes-filter', function( event ) {
     980                        content.on( 'input', '#themes-filter', function( event ) {
    903981                                var count,
    904982                                        term = event.currentTarget.value.toLowerCase().trim().replace( '-', ' ' ),
    905983                                        controls = section.controls();
     
    911989                                renderScreenshots();
    912990
    913991                                // Update theme count.
    914                                 count = section.container.find( 'li.customize-control:visible' ).length;
    915                                 section.container.find( '.theme-count' ).text( count );
     992                                count = content.find( 'li.customize-control:visible' ).length;
     993                                content.find( '.theme-count' ).text( count );
    916994                        });
    917995
    918996                        // Pre-load the first 3 theme screenshots.
     
    9481026                        }
    9491027
    9501028                        // Note: there is a second argument 'args' passed
    951                         var position, scroll,
    952                                 panel = this,
    953                                 section = panel.container.closest( '.accordion-section' ),
     1029                        var panel = this,
     1030                                section = panel.contentContainer,
    9541031                                overlay = section.closest( '.wp-full-overlay' ),
    9551032                                container = section.closest( '.wp-full-overlay-sidebar-content' ),
    956                                 siblings = container.find( '.open' ),
    9571033                                customizeBtn = section.find( '.customize-theme' ),
    958                                 changeBtn = section.find( '.change-theme' ),
    959                                 content = section.find( '.control-panel-content' );
    960 
    961                         if ( expanded ) {
     1034                                changeBtn = panel.headContainer.find( '.change-theme' );
    9621035
     1036                        if ( expanded && ! section.hasClass( 'current-panel' ) ) {
    9631037                                // Collapse any sibling sections/panels
    9641038                                api.section.each( function ( otherSection ) {
    9651039                                        if ( otherSection !== panel ) {
     
    9701044                                        otherPanel.collapse( { duration: 0 } );
    9711045                                });
    9721046
    973                                 content.show( 0, function() {
    974                                         position = content.offset().top;
    975                                         scroll = container.scrollTop();
    976                                         content.css( 'margin-top', ( $( '#customize-header-actions' ).height() - position - scroll ) );
    977                                         section.addClass( 'current-panel' );
    978                                         overlay.addClass( 'in-themes-panel' );
     1047                                panel._animateChangeExpanded( function() {
     1048                                        changeBtn.attr( 'tabindex', '-1' );
     1049                                        customizeBtn.attr( 'tabindex', '0' );
     1050
     1051                                        customizeBtn.focus();
     1052                                        section.css( 'top', '' );
    9791053                                        container.scrollTop( 0 );
    980                                         _.delay( panel.renderScreenshots, 10 ); // Wait for the controls
    981                                         panel.$customizeSidebar.on( 'scroll.customize-themes-section', _.throttle( panel.renderScreenshots, 300 ) );
     1054
    9821055                                        if ( args.completeCallback ) {
    9831056                                                args.completeCallback();
    9841057                                        }
    9851058                                } );
    986                                 customizeBtn.focus();
    987                         } else {
    988                                 siblings.removeClass( 'open' );
    989                                 section.removeClass( 'current-panel' );
    990                                 overlay.removeClass( 'in-themes-panel' );
    991                                 panel.$customizeSidebar.off( 'scroll.customize-themes-section' );
    992                                 content.delay( 180 ).hide( 0, function() {
    993                                         content.css( 'margin-top', 'inherit' ); // Reset
     1059
     1060                                overlay.addClass( 'in-themes-panel' );
     1061                                section.addClass( 'current-panel' );
     1062
     1063                        } else if ( ! expanded && section.hasClass( 'current-panel' ) ) {
     1064                                panel._animateChangeExpanded( function() {
     1065                                        changeBtn.attr( 'tabindex', '0' );
     1066                                        customizeBtn.attr( 'tabindex', '-1' );
     1067
     1068                                        changeBtn.focus();
     1069                                        section.css( 'top', '' );
     1070
    9941071                                        if ( args.completeCallback ) {
    9951072                                                args.completeCallback();
    9961073                                        }
    9971074                                } );
    998                                 customizeBtn.attr( 'tabindex', '0' );
    999                                 changeBtn.focus();
    1000                                 container.scrollTop( 0 );
    1001                         }
    1002                 },
    10031075
    1004                 /**
    1005                  * Recalculate the top margin.
    1006                  *
    1007                  * @since 4.4.0
    1008                  * @private
    1009                  */
    1010                 _recalculateTopMargin: function() {
    1011                         api.Panel.prototype._recalculateTopMargin.call( this );
     1076                                overlay.removeClass( 'in-themes-panel' );
     1077                                section.removeClass( 'current-panel' );
     1078                        }
    10121079                },
    10131080
    10141081                /**
     
    12371304                 */
    12381305                embed: function () {
    12391306                        var panel = this,
    1240                                 parentContainer = $( '#customize-theme-controls > ul' ); // @todo This should be defined elsewhere, and to be configurable
     1307                                container = $( '#customize-theme-controls' ),
     1308                                parentContainer = $( '.customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable
    12411309
    1242                         if ( ! panel.container.parent().is( parentContainer ) ) {
    1243                                 parentContainer.append( panel.container );
     1310                        if ( ! panel.headContainer.parent().is( parentContainer ) ) {
     1311                                parentContainer.append( panel.headContainer );
     1312                        }
     1313                        if ( ! panel.contentContainer.parent().is( panel.headContainer ) ) {
     1314                                container.append( panel.contentContainer );
    12441315                                panel.renderContent();
    12451316                        }
    12461317
    1247                         api.bind( 'pane-contents-reflowed', _.debounce( function() {
    1248                                 panel._recalculateTopMargin();
    1249                         }, 100 ) );
    1250 
    12511318                        panel.deferred.embedded.resolve();
    12521319                },
    12531320
     
    12581325                        var meta, panel = this;
    12591326
    12601327                        // Expand/Collapse accordion sections on click.
    1261                         panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
     1328                        panel.headContainer.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
    12621329                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    12631330                                        return;
    12641331                                }
     
    12701337                        });
    12711338
    12721339                        // Close panel.
    1273                         panel.container.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
     1340                        panel.contentContainer.find( '.customize-panel-back' ).on( 'click keydown', function( event ) {
    12741341                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    12751342                                        return;
    12761343                                }
     
    12811348                                }
    12821349                        });
    12831350
    1284                         meta = panel.container.find( '.panel-meta:first' );
     1351                        meta = panel.contentContainer.find( '.panel-meta:first' );
    12851352
    12861353                        meta.find( '> .accordion-section-title .customize-help-toggle' ).on( 'click keydown', function( event ) {
    12871354                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
     
    12891356                                }
    12901357                                event.preventDefault(); // Keep this AFTER the key filter above
    12911358
    1292                                 meta = panel.container.find( '.panel-meta' );
    12931359                                if ( meta.hasClass( 'cannot-expand' ) ) {
    12941360                                        return;
    12951361                                }
     
    13051371                                        $( this ).attr( 'aria-expanded', true );
    13061372                                }
    13071373                        });
    1308 
    13091374                },
    13101375
    13111376                /**
     
    13591424                        }
    13601425
    13611426                        // Note: there is a second argument 'args' passed
    1362                         var position, scroll,
    1363                                 panel = this,
    1364                                 accordionSection = panel.container.closest( '.accordion-section' ),
     1427                        var panel = this,
     1428                                accordionSection = panel.contentContainer,
    13651429                                overlay = accordionSection.closest( '.wp-full-overlay' ),
    13661430                                container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ),
    1367                                 siblings = container.find( '.open' ),
    1368                                 topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ),
    1369                                 backBtn = accordionSection.find( '.customize-panel-back' ),
    1370                                 panelTitle = accordionSection.find( '.accordion-section-title' ).first(),
    1371                                 content = accordionSection.find( '.control-panel-content' ),
    1372                                 headerActionsHeight = $( '#customize-header-actions' ).height();
    1373 
    1374                         if ( expanded ) {
     1431                                topPanel = panel.headContainer.find( '.accordion-section-title' ),
     1432                                backBtn = accordionSection.find( '.customize-panel-back' );
    13751433
     1434                        if ( expanded && ! accordionSection.hasClass( 'current-panel' ) ) {
    13761435                                // Collapse any sibling sections/panels
    13771436                                api.section.each( function ( section ) {
    13781437                                        if ( panel.id !== section.panel() ) {
     
    13851444                                        }
    13861445                                });
    13871446
    1388                                 content.show( 0, function() {
    1389                                         content.parent().show();
    1390                                         position = content.offset().top;
    1391                                         scroll = container.scrollTop();
    1392                                         content.css( 'margin-top', ( headerActionsHeight - position - scroll ) );
    1393                                         accordionSection.addClass( 'current-panel' );
    1394                                         overlay.addClass( 'in-sub-panel' );
     1447                                panel._animateChangeExpanded( function() {
     1448                                        topPanel.attr( 'tabindex', '-1' );
     1449                                        backBtn.attr( 'tabindex', '0' );
     1450
     1451                                        backBtn.focus();
     1452                                        accordionSection.css( 'top', '' );
    13951453                                        container.scrollTop( 0 );
     1454
    13961455                                        if ( args.completeCallback ) {
    13971456                                                args.completeCallback();
    13981457                                        }
    13991458                                } );
    1400                                 topPanel.attr( 'tabindex', '-1' );
    1401                                 backBtn.attr( 'tabindex', '0' );
    1402                                 backBtn.focus();
    1403                                 panel._recalculateTopMargin();
    1404                         } else {
    1405                                 siblings.removeClass( 'open' );
    1406                                 accordionSection.removeClass( 'current-panel' );
    1407                                 overlay.removeClass( 'in-sub-panel' );
    1408                                 content.delay( 180 ).hide( 0, function() {
    1409                                         content.css( 'margin-top', 'inherit' ); // Reset
     1459
     1460                                overlay.addClass( 'in-sub-panel' );
     1461                                accordionSection.addClass( 'current-panel' );
     1462
     1463                        } else if ( ! expanded && accordionSection.hasClass( 'current-panel' ) ) {
     1464                                panel._animateChangeExpanded( function() {
     1465                                        topPanel.attr( 'tabindex', '0' );
     1466                                        backBtn.attr( 'tabindex', '-1' );
     1467
     1468                                        topPanel.focus();
     1469                                        accordionSection.css( 'top', '' );
     1470
    14101471                                        if ( args.completeCallback ) {
    14111472                                                args.completeCallback();
    14121473                                        }
    14131474                                } );
    1414                                 topPanel.attr( 'tabindex', '0' );
    1415                                 backBtn.attr( 'tabindex', '-1' );
    1416                                 panelTitle.focus();
    1417                                 container.scrollTop( 0 );
    1418                         }
    1419                 },
    14201475
    1421                 /**
    1422                  * Recalculate the top margin.
    1423                  *
    1424                  * @since 4.4.0
    1425                  * @private
    1426                  */
    1427                 _recalculateTopMargin: function() {
    1428                         var panel = this, headerActionsHeight, content, accordionSection;
    1429                         headerActionsHeight = $( '#customize-header-actions' ).height();
    1430                         accordionSection = panel.container.closest( '.accordion-section' );
    1431                         content = accordionSection.find( '.control-panel-content' );
    1432                         content.css( 'margin-top', ( parseInt( content.css( 'margin-top' ), 10 ) - ( content.offset().top - headerActionsHeight ) ) );
     1476                                overlay.removeClass( 'in-sub-panel' );
     1477                                accordionSection.removeClass( 'current-panel' );
     1478                        }
    14331479                },
    14341480
    14351481                /**
     
    14491495                        } else {
    14501496                                template = wp.template( 'customize-panel-default-content' );
    14511497                        }
    1452                         if ( template && panel.container ) {
    1453                                 panel.container.find( '.accordion-sub-container' ).html( template( panel.params ) );
     1498                        if ( template && panel.headContainer ) {
     1499                                panel.contentContainer.html( template( panel.params ) );
    14541500                        }
    14551501                }
    14561502        });
     
    16261672                                api.section( sectionId, function ( section ) {
    16271673                                        // Wait for the section to be ready/initialized
    16281674                                        section.deferred.embedded.done( function () {
    1629                                                 parentContainer = section.container.find( 'ul:first' );
     1675                                                parentContainer = ( section.contentContainer.is( 'ul' ) ) ? section.contentContainer : section.contentContainer.find( 'ul:first' );
    16301676                                                if ( ! control.container.parent().is( parentContainer ) ) {
    16311677                                                        parentContainer.append( control.container );
    16321678                                                        control.renderContent();
     
    35423588         */
    35433589        api.reflowPaneContents = _.bind( function () {
    35443590
    3545                 var appendContainer, activeElement, rootContainers, rootNodes = [], wasReflowed = false;
     3591                var appendContainer, activeElement, rootHeadContainers, rootNodes = [], wasReflowed = false;
    35463592
    35473593                if ( document.activeElement ) {
    35483594                        activeElement = $( document.activeElement );
     
    35513597                // Sort the sections within each panel
    35523598                api.panel.each( function ( panel ) {
    35533599                        var sections = panel.sections(),
    3554                                 sectionContainers = _.pluck( sections, 'container' );
     3600                                sectionHeadContainers = _.pluck( sections, 'headContainer' );
    35553601                        rootNodes.push( panel );
    3556                         appendContainer = panel.container.find( 'ul:first' );
    3557                         if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
     3602                        appendContainer = ( panel.contentContainer.is( 'ul' ) ) ? panel.contentContainer : panel.contentContainer.find( 'ul:first' );
     3603                        if ( ! api.utils.areElementListsEqual( sectionHeadContainers, appendContainer.children( '[id]' ) ) ) {
    35583604                                _( sections ).each( function ( section ) {
    3559                                         appendContainer.append( section.container );
     3605                                        appendContainer.append( section.headContainer );
    35603606                                } );
    35613607                                wasReflowed = true;
    35623608                        }
     
    35693615                        if ( ! section.panel() ) {
    35703616                                rootNodes.push( section );
    35713617                        }
    3572                         appendContainer = section.container.find( 'ul:first' );
     3618                        appendContainer = ( section.contentContainer.is( 'ul' ) ) ? section.contentContainer : section.contentContainer.find( 'ul:first' );
    35733619                        if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
    35743620                                _( controls ).each( function ( control ) {
    35753621                                        appendContainer.append( control.container );
     
    35803626
    35813627                // Sort the root panels and sections
    35823628                rootNodes.sort( api.utils.prioritySort );
    3583                 rootContainers = _.pluck( rootNodes, 'container' );
    3584                 appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
    3585                 if ( ! api.utils.areElementListsEqual( rootContainers, appendContainer.children() ) ) {
     3629                rootHeadContainers = _.pluck( rootNodes, 'headContainer' );
     3630                appendContainer = $( '#customize-theme-controls .customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable
     3631                if ( ! api.utils.areElementListsEqual( rootHeadContainers, appendContainer.children() ) ) {
    35863632                        _( rootNodes ).each( function ( rootNode ) {
    3587                                 appendContainer.append( rootNode.container );
     3633                                appendContainer.append( rootNode.headContainer );
    35883634                        } );
    35893635                        wasReflowed = true;
    35903636                }
  • src/wp-admin/js/customize-nav-menus.js

    diff --git a/src/wp-admin/js/customize-nav-menus.js b/src/wp-admin/js/customize-nav-menus.js
    index e514a0a..676b76e 100644
    a b  
    833833                        section.refreshAssignedLocations();
    834834
    835835                        api.bind( 'pane-contents-reflowed', function() {
     836                                var content = section.contentContainer;
     837
    836838                                // Skip menus that have been removed.
    837                                 if ( ! section.container.parent().length ) {
     839                                if ( ! content.parent().length ) {
    838840                                        return;
    839841                                }
    840                                 section.container.find( '.menu-item .menu-item-reorder-nav button' ).attr({ 'tabindex': '0', 'aria-hidden': 'false' });
    841                                 section.container.find( '.menu-item.move-up-disabled .menus-move-up' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
    842                                 section.container.find( '.menu-item.move-down-disabled .menus-move-down' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
    843                                 section.container.find( '.menu-item.move-left-disabled .menus-move-left' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
    844                                 section.container.find( '.menu-item.move-right-disabled .menus-move-right' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
     842                                content.find( '.menu-item .menu-item-reorder-nav button' ).attr({ 'tabindex': '0', 'aria-hidden': 'false' });
     843                                content.find( '.menu-item.move-up-disabled .menus-move-up' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
     844                                content.find( '.menu-item.move-down-disabled .menus-move-down' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
     845                                content.find( '.menu-item.move-left-disabled .menus-move-left' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
     846                                content.find( '.menu-item.move-right-disabled .menus-move-right' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
    845847                        } );
    846848                },
    847849
     
    952954                        var section = this;
    953955
    954956                        if ( expanded ) {
    955                                 wpNavMenu.menuList = section.container.find( '.accordion-section-content:first' );
     957                                wpNavMenu.menuList = section.contentContainer;
    956958                                wpNavMenu.targetList = wpNavMenu.menuList;
    957959
    958960                                // Add attributes needed by wpNavMenu
     
    10141016                onChangeExpanded: function( expanded ) {
    10151017                        var section = this,
    10161018                                button = section.container.find( '.add-menu-toggle' ),
    1017                                 content = section.container.find( '.new-menu-section-content' ),
    1018                                 customizer = section.container.closest( '.wp-full-overlay-sidebar-content' );
     1019                                content = section.contentContainer,
     1020                                customizer = section.headContainer.closest( '.wp-full-overlay-sidebar-content' );
    10191021                        if ( expanded ) {
    10201022                                button.addClass( 'open' );
    10211023                                button.attr( 'aria-expanded', 'true' );
     
    10281030                                content.slideUp( 'fast' );
    10291031                                content.find( '.menu-name-field' ).removeClass( 'invalid' );
    10301032                        }
     1033                },
     1034
     1035                /**
     1036                 * Detach and return the content html, extracted from the container html, if it exists.
     1037                 *
     1038                 * @since
     1039                 */
     1040                _getContent: function () {
     1041                        return this.container.find( 'ul:first' );
    10311042                }
    10321043        });
    10331044
     
    19841995                 */
    19851996                ready: function() {
    19861997                        var control = this,
     1998                                section = api.section( control.section() ),
    19871999                                menuId = control.params.menu_id,
    19882000                                menu = control.setting(),
    19892001                                name,
     
    20002012                         * being deactivated.
    20012013                         */
    20022014                        control.active.validate = function() {
    2003                                 var value, section = api.section( control.section() );
     2015                                var value;
    20042016                                if ( section ) {
    20052017                                        value = section.active();
    20062018                                } else {
     
    20092021                                return value;
    20102022                        };
    20112023
    2012                         control.$controlSection = control.container.closest( '.control-section' );
     2024                        control.$controlSection = section.headContainer;
    20132025                        control.$sectionContent = control.container.closest( '.accordion-section-content' );
    20142026
    20152027                        this._setupModel();
     
    22832295                                        return;
    22842296                                }
    22852297
    2286                                 var section = control.container.closest( '.accordion-section' ),
     2298                                var section = api.section( control.section() ),
    22872299                                        menuId = control.params.menu_id,
    2288                                         controlTitle = section.find( '.accordion-section-title' ),
    2289                                         sectionTitle = section.find( '.customize-section-title h3' ),
    2290                                         location = section.find( '.menu-in-location' ),
     2300                                        controlTitle = section.headContainer.find( '.accordion-section-title' ),
     2301                                        sectionTitle = section.contentContainer.find( '.customize-section-title h3' ),
     2302                                        location = section.headContainer.find( '.menu-in-location' ),
    22912303                                        action = sectionTitle.find( '.customize-action' ),
    22922304                                        name = displayNavMenuName( menu.name );
    22932305
     
    23112323                                } );
    23122324
    23132325                                // Update the nav menu name in all location checkboxes.
    2314                                 section.find( '.customize-control-checkbox input' ).each( function() {
     2326                                section.contentContainer.find( '.customize-control-checkbox input' ).each( function() {
    23152327                                        if ( $( this ).prop( 'checked' ) ) {
    23162328                                                $( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( name );
    23172329                                        }
     
    26252637
    26262638                        // Focus on the new menu section.
    26272639                        api.section( customizeId ).focus(); // @todo should we focus on the new menu's control and open the add-items panel? Thinking user flow...
    2628 
    2629                         // Fix an issue with extra space at top immediately after creating new menu.
    2630                         $( '#menu-to-edit' ).css( 'margin-top', 0 );
    26312640                }
    26322641        });
    26332642
  • tests/qunit/wp-admin/js/customize-controls.js

    diff --git a/tests/qunit/wp-admin/js/customize-controls.js b/tests/qunit/wp-admin/js/customize-controls.js
    index d806e46..e39b571 100644
    a b jQuery( window ).load( function (){ 
    211211                section = wp.customize.section( id );
    212212                ok( ! section.params.content );
    213213                ok( !! section.container );
    214                 ok( section.container.is( '.control-section.control-section-default' ) );
    215                 ok( 1 === section.container.find( '> .accordion-section-title' ).length );
    216                 ok( 1 === section.container.find( '> .accordion-section-content' ).length );
     214                ok( !! section.headContainer );
     215                ok( !! section.contentContainer );
     216                ok( section.container.has( section.headContainer ) );
     217                ok( section.container.has( section.contentContainer ) );
     218                ok( section.headContainer.is( '.control-section.control-section-default' ) );
     219                ok( 1 === section.headContainer.find( '> .accordion-section-title' ).length );
     220                ok( section.contentContainer.is( '.accordion-section-content' ) );
     221                equal( section.headContainer.attr( 'aria-owns' ), section.contentContainer.attr( 'id' ) );
    217222        } );
    218223
    219224        module( 'Customizer Custom Type (titleless) Section with Template in Fixture' );
    jQuery( window ).load( function (){ 
    225230                section = wp.customize.section( id );
    226231                ok( ! section.params.content );
    227232                ok( !! section.container );
     233                ok( !! section.headContainer );
     234                ok( !! section.contentContainer );
     235                ok( section.container.has( section.headContainer ) );
     236                ok( section.container.has( section.contentContainer ) );
    228237                ok( section.container.is( '.control-section.control-section-titleless' ) );
    229                 ok( 0 === section.container.find( '> .accordion-section-title' ).length );
    230                 ok( 1 === section.container.find( '> .accordion-section-content' ).length );
     238                ok( 0 === section.headContainer.find( '> .accordion-section-title' ).length );
     239                ok( section.contentContainer.is( '.accordion-section-content' ) );
     240                equal( section.headContainer.attr( 'aria-owns' ), section.contentContainer.attr( 'id' ) );
    231241        } );
    232242        module( 'Customizer Custom Type Section Lacking Specific Template' );
    233243        test( 'Fixture section has expected content', function () {
    jQuery( window ).load( function (){ 
    235245                section = wp.customize.section( id );
    236246                ok( ! section.params.content );
    237247                ok( !! section.container );
    238                 ok( section.container.is( '.control-section.control-section-' + section.params.type ) );
    239                 ok( 1 === section.container.find( '> .accordion-section-title' ).length );
    240                 ok( 1 === section.container.find( '> .accordion-section-content' ).length );
     248                ok( !! section.headContainer );
     249                ok( !! section.contentContainer );
     250                ok( section.container.has( section.headContainer ) );
     251                ok( section.container.has( section.contentContainer ) );
     252                ok( section.headContainer.is( '.control-section.control-section-' + section.params.type ) );
     253                ok( 1 === section.headContainer.find( '> .accordion-section-title' ).length );
     254                ok( section.contentContainer.is( '.accordion-section-content' ) );
     255                equal( section.headContainer.attr( 'aria-owns' ), section.contentContainer.attr( 'id' ) );
    241256        } );
    242257        module( 'Customizer Section lacking any params' );
    243258        test( 'Fixture section has default params supplied', function () {
    jQuery( window ).load( function (){ 
    270285                var panel = wp.customize.panel( 'fixture-panel' );
    271286                ok( !! panel.params.content );
    272287                ok( !! panel.container );
     288                ok( !! panel.headContainer );
     289                ok( !! panel.contentContainer );
     290                ok( panel.container.has( panel.headContainer ) );
     291                ok( panel.container.has( panel.contentContainer ) );
    273292        } );
    274293        test( 'Fixture panel has section among its sections()', function () {
    275294                var panel = wp.customize.panel( 'fixture-panel' );
    jQuery( window ).load( function (){ 
    304323                panel = wp.customize.panel( id );
    305324                ok( ! panel.params.content );
    306325                ok( !! panel.container );
    307                 ok( panel.container.is( '.control-panel.control-panel-default' ) );
    308                 ok( 1 === panel.container.find( '> .accordion-section-title' ).length );
    309                 ok( 1 === panel.container.find( '> .control-panel-content' ).length );
     326                ok( !! panel.headContainer );
     327                ok( !! panel.contentContainer );
     328                ok( panel.container.has( panel.headContainer ) );
     329                ok( panel.container.has( panel.contentContainer ) );
     330                ok( panel.headContainer.is( '.control-panel.control-panel-default' ) );
     331                ok( 1 === panel.headContainer.find( '> .accordion-section-title' ).length );
     332                ok( panel.contentContainer.is( '.control-panel-content' ) );
     333                equal( panel.headContainer.attr( 'aria-owns' ), panel.contentContainer.attr( 'id' ) );
    310334        } );
    311335
    312336        module( 'Customizer Custom Type Panel (titleless) with Template in Fixture' );
    jQuery( window ).load( function (){ 
    318342                panel = wp.customize.panel( id );
    319343                ok( ! panel.params.content );
    320344                ok( !! panel.container );
    321                 ok( panel.container.is( '.control-panel.control-panel-titleless' ) );
    322                 ok( 0 === panel.container.find( '> .accordion-section-title' ).length );
    323                 ok( 1 === panel.container.find( '> .control-panel-content' ).length );
     345                ok( !! panel.headContainer );
     346                ok( !! panel.contentContainer );
     347                ok( panel.container.has( panel.headContainer ) );
     348                ok( panel.container.has( panel.contentContainer ) );
     349                ok( panel.headContainer.is( '.control-panel.control-panel-titleless' ) );
     350                ok( 0 === panel.headContainer.find( '> .accordion-section-title' ).length );
     351                ok( panel.contentContainer.is( '.control-panel-content' ) );
     352                equal( panel.headContainer.attr( 'aria-owns' ), panel.contentContainer.attr( 'id' ) );
    324353        } );
    325354
    326355        module( 'Customizer Custom Type Panel Lacking Specific Template' );
    jQuery( window ).load( function (){ 
    329358                panel = wp.customize.panel( id );
    330359                ok( ! panel.params.content );
    331360                ok( !! panel.container );
    332                 ok( panel.container.is( '.control-panel.control-panel-' + panel.params.type ) );
    333                 ok( 1 === panel.container.find( '> .accordion-section-title' ).length );
    334                 ok( 1 === panel.container.find( '> .control-panel-content' ).length );
     361                ok( !! panel.headContainer );
     362                ok( !! panel.contentContainer );
     363                ok( panel.container.has( panel.headContainer ) );
     364                ok( panel.container.has( panel.contentContainer ) );
     365                ok( panel.headContainer.is( '.control-panel.control-panel-' + panel.params.type ) );
     366                ok( 1 === panel.headContainer.find( '> .accordion-section-title' ).length );
     367                ok( panel.contentContainer.is( '.control-panel-content' ) );
     368                equal( panel.headContainer.attr( 'aria-owns' ), panel.contentContainer.attr( 'id' ) );
    335369        } );
    336370        module( 'Customizer Panel lacking any params' );
    337371        test( 'Fixture panel has default params supplied', function () {
  • tests/qunit/wp-admin/js/customize-widgets.js

    diff --git a/tests/qunit/wp-admin/js/customize-widgets.js b/tests/qunit/wp-admin/js/customize-widgets.js
    index 225d155..5f754a4 100644
    a b jQuery( window ).load( function() { 
    5858                ok( panel.extended( api.Widgets.WidgetsPanel ) );
    5959
    6060                panel.deferred.embedded.done( function() {
    61                         ok( 1 === panel.container.find( '.no-widget-areas-rendered-notice' ).length );
    62                         ok( panel.container.find( '.no-widget-areas-rendered-notice' ).is( ':visible' ) );
     61                        ok( 1 === panel.contentContainer.find( '.no-widget-areas-rendered-notice' ).length );
     62                        ok( panel.contentContainer.find( '.no-widget-areas-rendered-notice' ).is( ':visible' ) );
    6363                        api.section( 'sidebar-widgets-sidebar-1' ).active( true );
    6464                        api.control( 'sidebars_widgets[sidebar-1]' ).active( true );
    6565                        api.trigger( 'pane-contents-reflowed' );
    66                         ok( ! panel.container.find( '.no-widget-areas-rendered-notice' ).is( ':visible' ) );
     66                        ok( ! panel.contentContainer.find( '.no-widget-areas-rendered-notice' ).is( ':visible' ) );
    6767                } );
    6868
    6969                expect( 4 );