Make WordPress Core

Changeset 37867


Ignore:
Timestamp:
06/26/2016 11:54:20 AM (10 years ago)
Author:
westonruter
Message:

Customize: Always define functions reflowPaneContents, findControlsForSettings, and _handleSettingValidities on wp.customize.

Moves definitions of functions outside of a jQuery.ready() callback, as these functions needn't be deferred to DOM ready. This change also ensures that the functions are available if customize-controls is enqueued outside of the Customizer context, as the ready callback short-circuits if _wpCustomizeSettings is not defined. The findControlsForSettings and _handleSettingValidities functions were misplaced in r37700.

See #34893.
See #36944.
See #29071.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/customize-controls.js

    r37701 r37867  
    34203420        };
    34213421
     3422        /**
     3423         * Handle setting_validities in an error response for the customize-save request.
     3424         *
     3425         * Add notifications to the settings and focus on the first control that has an invalid setting.
     3426         *
     3427         * @since 4.6.0
     3428         * @private
     3429         *
     3430         * @param {object}  args
     3431         * @param {object}  args.settingValidities
     3432         * @param {boolean} [args.focusInvalidControl=false]
     3433         * @returns {void}
     3434         */
     3435        api._handleSettingValidities = function handleSettingValidities( args ) {
     3436                var invalidSettingControls, invalidSettings = [], wasFocused = false;
     3437
     3438                // Find the controls that correspond to each invalid setting.
     3439                _.each( args.settingValidities, function( validity, settingId ) {
     3440                        var setting = api( settingId );
     3441                        if ( setting ) {
     3442
     3443                                // Add notifications for invalidities.
     3444                                if ( _.isObject( validity ) ) {
     3445                                        _.each( validity, function( params, code ) {
     3446                                                var notification = new api.Notification( code, params ), existingNotification, needsReplacement = false;
     3447
     3448                                                // Remove existing notification if already exists for code but differs in parameters.
     3449                                                existingNotification = setting.notifications( notification.code );
     3450                                                if ( existingNotification ) {
     3451                                                        needsReplacement = ( notification.type !== existingNotification.type ) || ! _.isEqual( notification.data, existingNotification.data );
     3452                                                }
     3453                                                if ( needsReplacement ) {
     3454                                                        setting.notifications.remove( code );
     3455                                                }
     3456
     3457                                                if ( ! setting.notifications.has( notification.code ) ) {
     3458                                                        setting.notifications.add( code, notification );
     3459                                                }
     3460                                                invalidSettings.push( setting.id );
     3461                                        } );
     3462                                }
     3463
     3464                                // Remove notification errors that are no longer valid.
     3465                                setting.notifications.each( function( notification ) {
     3466                                        if ( 'error' === notification.type && ( true === validity || ! validity[ notification.code ] ) ) {
     3467                                                setting.notifications.remove( notification.code );
     3468                                        }
     3469                                } );
     3470                        }
     3471                } );
     3472
     3473                if ( args.focusInvalidControl ) {
     3474                        invalidSettingControls = api.findControlsForSettings( invalidSettings );
     3475
     3476                        // Focus on the first control that is inside of an expanded section (one that is visible).
     3477                        _( _.values( invalidSettingControls ) ).find( function( controls ) {
     3478                                return _( controls ).find( function( control ) {
     3479                                        var isExpanded = control.section() && api.section.has( control.section() ) && api.section( control.section() ).expanded();
     3480                                        if ( isExpanded && control.expanded ) {
     3481                                                isExpanded = control.expanded();
     3482                                        }
     3483                                        if ( isExpanded ) {
     3484                                                control.focus();
     3485                                                wasFocused = true;
     3486                                        }
     3487                                        return wasFocused;
     3488                                } );
     3489                        } );
     3490
     3491                        // Focus on the first invalid control.
     3492                        if ( ! wasFocused && ! _.isEmpty( invalidSettingControls ) ) {
     3493                                _.values( invalidSettingControls )[0][0].focus();
     3494                        }
     3495                }
     3496        };
     3497
     3498        /**
     3499         * Find all controls associated with the given settings.
     3500         *
     3501         * @since 4.6.0
     3502         * @param {string[]} settingIds Setting IDs.
     3503         * @returns {object<string, wp.customize.Control>} Mapping setting ids to arrays of controls.
     3504         */
     3505        api.findControlsForSettings = function findControlsForSettings( settingIds ) {
     3506                var controls = {}, settingControls;
     3507                _.each( _.unique( settingIds ), function( settingId ) {
     3508                        var setting = api( settingId );
     3509                        if ( setting ) {
     3510                                settingControls = setting.findControls();
     3511                                if ( settingControls && settingControls.length > 0 ) {
     3512                                        controls[ settingId ] = settingControls;
     3513                                }
     3514                        }
     3515                } );
     3516                return controls;
     3517        };
     3518
     3519        /**
     3520         * Sort panels, sections, controls by priorities. Hide empty sections and panels.
     3521         *
     3522         * @since 4.1.0
     3523         */
     3524        api.reflowPaneContents = _.bind( function () {
     3525
     3526                var appendContainer, activeElement, rootContainers, rootNodes = [], wasReflowed = false;
     3527
     3528                if ( document.activeElement ) {
     3529                        activeElement = $( document.activeElement );
     3530                }
     3531
     3532                // Sort the sections within each panel
     3533                api.panel.each( function ( panel ) {
     3534                        var sections = panel.sections(),
     3535                                sectionContainers = _.pluck( sections, 'container' );
     3536                        rootNodes.push( panel );
     3537                        appendContainer = panel.container.find( 'ul:first' );
     3538                        if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
     3539                                _( sections ).each( function ( section ) {
     3540                                        appendContainer.append( section.container );
     3541                                } );
     3542                                wasReflowed = true;
     3543                        }
     3544                } );
     3545
     3546                // Sort the controls within each section
     3547                api.section.each( function ( section ) {
     3548                        var controls = section.controls(),
     3549                                controlContainers = _.pluck( controls, 'container' );
     3550                        if ( ! section.panel() ) {
     3551                                rootNodes.push( section );
     3552                        }
     3553                        appendContainer = section.container.find( 'ul:first' );
     3554                        if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
     3555                                _( controls ).each( function ( control ) {
     3556                                        appendContainer.append( control.container );
     3557                                } );
     3558                                wasReflowed = true;
     3559                        }
     3560                } );
     3561
     3562                // Sort the root panels and sections
     3563                rootNodes.sort( api.utils.prioritySort );
     3564                rootContainers = _.pluck( rootNodes, 'container' );
     3565                appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
     3566                if ( ! api.utils.areElementListsEqual( rootContainers, appendContainer.children() ) ) {
     3567                        _( rootNodes ).each( function ( rootNode ) {
     3568                                appendContainer.append( rootNode.container );
     3569                        } );
     3570                        wasReflowed = true;
     3571                }
     3572
     3573                // Now re-trigger the active Value callbacks to that the panels and sections can decide whether they can be rendered
     3574                api.panel.each( function ( panel ) {
     3575                        var value = panel.active();
     3576                        panel.active.callbacks.fireWith( panel.active, [ value, value ] );
     3577                } );
     3578                api.section.each( function ( section ) {
     3579                        var value = section.active();
     3580                        section.active.callbacks.fireWith( section.active, [ value, value ] );
     3581                } );
     3582
     3583                // Restore focus if there was a reflow and there was an active (focused) element
     3584                if ( wasReflowed && activeElement ) {
     3585                        activeElement.focus();
     3586                }
     3587                api.trigger( 'pane-contents-reflowed' );
     3588        }, api );
     3589
    34223590        $( function() {
    34233591                api.settings = window._wpCustomizeSettings;
    … …  
    37103878                });
    37113879
    3712                 /**
    3713                  * Handle setting_validities in an error response for the customize-save request.
    3714                  *
    3715                  * Add notifications to the settings and focus on the first control that has an invalid setting.
    3716                  *
    3717                  * @since 4.6.0
    3718                  * @private
    3719                  *
    3720                  * @param {object}  args
    3721                  * @param {object}  args.settingValidities
    3722                  * @param {boolean} [args.focusInvalidControl=false]
    3723                  * @returns {void}
    3724                  */
    3725                 api._handleSettingValidities = function handleSettingValidities( args ) {
    3726                         var invalidSettingControls, invalidSettings = [], wasFocused = false;
    3727 
    3728                         // Find the controls that correspond to each invalid setting.
    3729                         _.each( args.settingValidities, function( validity, settingId ) {
    3730                                 var setting = api( settingId );
    3731                                 if ( setting ) {
    3732 
    3733                                         // Add notifications for invalidities.
    3734                                         if ( _.isObject( validity ) ) {
    3735                                                 _.each( validity, function( params, code ) {
    3736                                                         var notification = new api.Notification( code, params ), existingNotification, needsReplacement = false;
    3737 
    3738                                                         // Remove existing notification if already exists for code but differs in parameters.
    3739                                                         existingNotification = setting.notifications( notification.code );
    3740                                                         if ( existingNotification ) {
    3741                                                                 needsReplacement = ( notification.type !== existingNotification.type ) || ! _.isEqual( notification.data, existingNotification.data );
    3742                                                         }
    3743                                                         if ( needsReplacement ) {
    3744                                                                 setting.notifications.remove( code );
    3745                                                         }
    3746 
    3747                                                         if ( ! setting.notifications.has( notification.code ) ) {
    3748                                                                 setting.notifications.add( code, notification );
    3749                                                         }
    3750                                                         invalidSettings.push( setting.id );
    3751                                                 } );
    3752                                         }
    3753 
    3754                                         // Remove notification errors that are no longer valid.
    3755                                         setting.notifications.each( function( notification ) {
    3756                                                 if ( 'error' === notification.type && ( true === validity || ! validity[ notification.code ] ) ) {
    3757                                                         setting.notifications.remove( notification.code );
    3758                                                 }
    3759                                         } );
    3760                                 }
    3761                         } );
    3762 
    3763                         if ( args.focusInvalidControl ) {
    3764                                 invalidSettingControls = api.findControlsForSettings( invalidSettings );
    3765 
    3766                                 // Focus on the first control that is inside of an expanded section (one that is visible).
    3767                                 _( _.values( invalidSettingControls ) ).find( function( controls ) {
    3768                                         return _( controls ).find( function( control ) {
    3769                                                 var isExpanded = control.section() && api.section.has( control.section() ) && api.section( control.section() ).expanded();
    3770                                                 if ( isExpanded && control.expanded ) {
    3771                                                         isExpanded = control.expanded();
    3772                                                 }
    3773                                                 if ( isExpanded ) {
    3774                                                         control.focus();
    3775                                                         wasFocused = true;
    3776                                                 }
    3777                                                 return wasFocused;
    3778                                         } );
    3779                                 } );
    3780 
    3781                                 // Focus on the first invalid control.
    3782                                 if ( ! wasFocused && ! _.isEmpty( invalidSettingControls ) ) {
    3783                                         _.values( invalidSettingControls )[0][0].focus();
    3784                                 }
    3785                         }
    3786                 };
    3787 
    3788                 /**
    3789                  * Find all controls associated with the given settings.
    3790                  *
    3791                  * @since 4.6.0
    3792                  * @param {string[]} settingIds Setting IDs.
    3793                  * @returns {object<string, wp.customize.Control>} Mapping setting ids to arrays of controls.
    3794                  */
    3795                 api.findControlsForSettings = function findControlsForSettings( settingIds ) {
    3796                         var controls = {}, settingControls;
    3797                         _.each( _.unique( settingIds ), function( settingId ) {
    3798                                 var setting = api( settingId );
    3799                                 if ( setting ) {
    3800                                         settingControls = setting.findControls();
    3801                                         if ( settingControls && settingControls.length > 0 ) {
    3802                                                 controls[ settingId ] = settingControls;
    3803                                         }
    3804                                 }
    3805                         } );
    3806                         return controls;
    3807                 };
    3808 
    3809                 /**
    3810                  * Sort panels, sections, controls by priorities. Hide empty sections and panels.
    3811                  *
    3812                  * @since 4.1.0
    3813                  */
    3814                 api.reflowPaneContents = _.bind( function () {
    3815 
    3816                         var appendContainer, activeElement, rootContainers, rootNodes = [], wasReflowed = false;
    3817 
    3818                         if ( document.activeElement ) {
    3819                                 activeElement = $( document.activeElement );
    3820                         }
    3821 
    3822                         // Sort the sections within each panel
    3823                         api.panel.each( function ( panel ) {
    3824                                 var sections = panel.sections(),
    3825                                         sectionContainers = _.pluck( sections, 'container' );
    3826                                 rootNodes.push( panel );
    3827                                 appendContainer = panel.container.find( 'ul:first' );
    3828                                 if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
    3829                                         _( sections ).each( function ( section ) {
    3830                                                 appendContainer.append( section.container );
    3831                                         } );
    3832                                         wasReflowed = true;
    3833                                 }
    3834                         } );
    3835 
    3836                         // Sort the controls within each section
    3837                         api.section.each( function ( section ) {
    3838                                 var controls = section.controls(),
    3839                                         controlContainers = _.pluck( controls, 'container' );
    3840                                 if ( ! section.panel() ) {
    3841                                         rootNodes.push( section );
    3842                                 }
    3843                                 appendContainer = section.container.find( 'ul:first' );
    3844                                 if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
    3845                                         _( controls ).each( function ( control ) {
    3846                                                 appendContainer.append( control.container );
    3847                                         } );
    3848                                         wasReflowed = true;
    3849                                 }
    3850                         } );
    3851 
    3852                         // Sort the root panels and sections
    3853                         rootNodes.sort( api.utils.prioritySort );
    3854                         rootContainers = _.pluck( rootNodes, 'container' );
    3855                         appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
    3856                         if ( ! api.utils.areElementListsEqual( rootContainers, appendContainer.children() ) ) {
    3857                                 _( rootNodes ).each( function ( rootNode ) {
    3858                                         appendContainer.append( rootNode.container );
    3859                                 } );
    3860                                 wasReflowed = true;
    3861                         }
    3862 
    3863                         // Now re-trigger the active Value callbacks to that the panels and sections can decide whether they can be rendered
    3864                         api.panel.each( function ( panel ) {
    3865                                 var value = panel.active();
    3866                                 panel.active.callbacks.fireWith( panel.active, [ value, value ] );
    3867                         } );
    3868                         api.section.each( function ( section ) {
    3869                                 var value = section.active();
    3870                                 section.active.callbacks.fireWith( section.active, [ value, value ] );
    3871                         } );
    3872 
    3873                         // Restore focus if there was a reflow and there was an active (focused) element
    3874                         if ( wasReflowed && activeElement ) {
    3875                                 activeElement.focus();
    3876                         }
    3877                         api.trigger( 'pane-contents-reflowed' );
    3878                 }, api );
    38793880                api.bind( 'ready', api.reflowPaneContents );
    3880                 api.reflowPaneContents = _.debounce( api.reflowPaneContents, 100 );
    38813881                $( [ api.panel, api.section, api.control ] ).each( function ( i, values ) {
    3882                         values.bind( 'add', api.reflowPaneContents );
    3883                         values.bind( 'change', api.reflowPaneContents );
    3884                         values.bind( 'remove', api.reflowPaneContents );
     3882                        var debouncedReflowPaneContents = _.debounce( api.reflowPaneContents, 100 );
     3883                        values.bind( 'add', debouncedReflowPaneContents );
     3884                        values.bind( 'change', debouncedReflowPaneContents );
     3885                        values.bind( 'remove', debouncedReflowPaneContents );
    38853886                } );
    38863887
    … …  
    39293930
    39303931                        activated.bind( function( to ) {
    3931                                 if ( to )
     3932                                if ( to ) {
    39323933                                        api.trigger( 'activated' );
     3934                                }
    39333935                        });
    39343936
Note: See TracChangeset for help on using the changeset viewer.