Changeset 37867
- Timestamp:
- 06/26/2016 11:54:20 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/customize-controls.js
r37701 r37867 3420 3420 }; 3421 3421 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 3422 3590 $( function() { 3423 3591 api.settings = window._wpCustomizeSettings; … … 3710 3878 }); 3711 3879 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.03718 * @private3719 *3720 * @param {object} args3721 * @param {object} args.settingValidities3722 * @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.03792 * @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.03813 */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 panel3823 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 section3837 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 sections3853 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 configurable3856 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 rendered3864 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) element3874 if ( wasReflowed && activeElement ) {3875 activeElement.focus();3876 }3877 api.trigger( 'pane-contents-reflowed' );3878 }, api );3879 3880 api.bind( 'ready', api.reflowPaneContents ); 3880 api.reflowPaneContents = _.debounce( api.reflowPaneContents, 100 );3881 3881 $( [ 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 ); 3885 3886 } ); 3886 3887 … … 3929 3930 3930 3931 activated.bind( function( to ) { 3931 if ( to ) 3932 if ( to ) { 3932 3933 api.trigger( 'activated' ); 3934 } 3933 3935 }); 3934 3936
Note: See TracChangeset
for help on using the changeset viewer.