| 2381 | | nodes = control.container.find('[data-customize-setting-link]'); |
| 2382 | | radios = {}; |
| 2383 | | |
| 2384 | | nodes.each( function() { |
| 2385 | | var node = $( this ), |
| 2386 | | name; |
| 2387 | | |
| 2388 | | if ( node.is( ':radio' ) ) { |
| 2389 | | name = node.prop( 'name' ); |
| 2390 | | if ( radios[ name ] ) { |
| 2391 | | return; |
| 2392 | | } |
| 2393 | | |
| 2394 | | radios[ name ] = true; |
| 2395 | | node = nodes.filter( '[name="' + name + '"]' ); |
| 2396 | | } |
| 2397 | | |
| 2398 | | api( node.data( 'customizeSettingLink' ), function( setting ) { |
| 2399 | | var element = new api.Element( node ); |
| 2400 | | control.elements.push( element ); |
| 2401 | | element.sync( setting ); |
| 2402 | | element.set( setting() ); |
| 2403 | | }); |
| 2404 | | }); |
| 2405 | | |
| 2422 | | settings = $.map( control.params.settings, function( value ) { |
| 2423 | | return value; |
| 2424 | | }); |
| 2425 | | |
| 2426 | | if ( 0 === settings.length ) { |
| 2427 | | control.setting = null; |
| 2428 | | control.settings = {}; |
| 2429 | | control.embed(); |
| 2430 | | } else { |
| 2431 | | api.apply( api, settings.concat( function() { |
| 2432 | | var key; |
| 2433 | | |
| 2434 | | control.settings = {}; |
| 2435 | | for ( key in control.params.settings ) { |
| 2436 | | control.settings[ key ] = api( control.params.settings[ key ] ); |
| 2437 | | } |
| 2438 | | |
| 2439 | | control.setting = control.settings['default'] || null; |
| | 2398 | _.each( control.params.settings, function( setting, key ) { |
| | 2399 | if ( _.isObject( setting ) ) { |
| | 2400 | control.settings[ key ] = setting; |
| | 2401 | } else { |
| | 2402 | deferredSettingIds.push( setting ); |
| | 2403 | } |
| | 2404 | } ); |
| 2441 | | // Add setting notifications to the control notification. |
| 2442 | | _.each( control.settings, function( setting ) { |
| 2443 | | setting.notifications.bind( 'add', function( settingNotification ) { |
| 2444 | | var controlNotification, code, params; |
| 2445 | | code = setting.id + ':' + settingNotification.code; |
| 2446 | | params = _.extend( |
| 2447 | | {}, |
| 2448 | | settingNotification, |
| 2449 | | { |
| 2450 | | setting: setting.id |
| 2451 | | } |
| 2452 | | ); |
| 2453 | | controlNotification = new api.Notification( code, params ); |
| 2454 | | control.notifications.add( controlNotification.code, controlNotification ); |
| 2455 | | } ); |
| 2456 | | setting.notifications.bind( 'remove', function( settingNotification ) { |
| 2457 | | control.notifications.remove( setting.id + ':' + settingNotification.code ); |
| 2458 | | } ); |
| | 2406 | if ( deferredSettingIds.length > 0 ) { |
| | 2407 | api.apply( api, deferredSettingIds.concat( function() { |
| | 2408 | _.each( control.params.settings, function( settingId, key ) { |
| | 2409 | if ( _.isString( settingId ) ) { |
| | 2410 | control.settings[ key ] = api( settingId ); |
| | 2411 | } |
| 2467 | | /* |
| 2468 | | * Note that this debounced/deferred rendering is needed for two reasons: |
| 2469 | | * 1) The 'remove' event is triggered just _before_ the notification is actually removed. |
| 2470 | | * 2) Improve performance when adding/removing multiple notifications at a time. |
| 2471 | | */ |
| 2472 | | var debouncedRenderNotifications = _.debounce( function renderNotifications() { |
| 2473 | | control.renderNotifications(); |
| | 2424 | control.linkElements(); |
| | 2425 | control.setupNotifications(); |
| | 2426 | control.ready(); |
| | 2427 | }); |
| | 2428 | }, |
| | 2429 | |
| | 2430 | /** |
| | 2431 | * Link elements between settings and inputs. |
| | 2432 | * |
| | 2433 | * @since 4.7.0 |
| | 2434 | * @access public |
| | 2435 | * |
| | 2436 | * @returns {void} |
| | 2437 | */ |
| | 2438 | linkElements: function() { |
| | 2439 | var control = this, nodes, radios, element; |
| | 2440 | |
| | 2441 | nodes = control.container.find( '[data-customize-setting-link], [data-customize-value-link]' ); |
| | 2442 | radios = {}; |
| | 2443 | |
| | 2444 | nodes.each( function() { |
| | 2445 | var node = $( this ), name, setting; |
| | 2446 | |
| | 2447 | if ( node.data( 'customizeSettingLinked' ) ) { |
| | 2448 | return; |
| | 2449 | } |
| | 2450 | node.data( 'customizeSettingLinked', true ); // Prevent re-linking element. |
| | 2451 | |
| | 2452 | if ( node.is( ':radio' ) ) { |
| | 2453 | name = node.prop( 'name' ); |
| | 2454 | if ( radios[ name ] ) { |
| | 2455 | return; |
| | 2456 | } |
| | 2457 | |
| | 2458 | radios[ name ] = true; |
| | 2459 | node = nodes.filter( '[name="' + name + '"]' ); |
| | 2460 | } |
| | 2461 | |
| | 2462 | // Let link by default refer to setting ID. If it doesn't exist, fallback to looking up by setting key. |
| | 2463 | if ( node.data( 'customizeSettingLink' ) ) { |
| | 2464 | setting = api( node.data( 'customizeSettingLink' ) ); |
| | 2465 | } |
| | 2466 | if ( ! setting ) { |
| | 2467 | setting = control.settings[ node.data( 'customizeValueLink' ) ]; |
| | 2468 | } |
| | 2469 | |
| | 2470 | if ( setting ) { |
| | 2471 | element = new api.Element( node ); |
| | 2472 | control.elements.push( element ); |
| | 2473 | element.sync( setting ); |
| | 2474 | element.set( setting() ); |
| | 2475 | } |
| | 2476 | }); |
| | 2477 | }, |
| | 2478 | |
| | 2479 | /** |
| | 2480 | * Sync setting notifications to the control notifications and render when notifications are aded/removed. |
| | 2481 | * |
| | 2482 | * @since 4.7.0 |
| | 2483 | * @returns {void} |
| | 2484 | */ |
| | 2485 | setupNotifications: function() { |
| | 2486 | var control = this, debouncedRenderNotifications; |
| | 2487 | |
| | 2488 | _.each( control.settings, function( setting, settingKey ) { |
| | 2489 | setting.notifications.bind( 'add', function( settingNotification ) { |
| | 2490 | var controlNotification, code, params; |
| | 2491 | code = ( setting.id || settingKey ) + ':' + settingNotification.code; |
| | 2492 | params = _.extend( |
| | 2493 | {}, |
| | 2494 | settingNotification, |
| | 2495 | { |
| | 2496 | setting: setting.id || null // @todo Let this be the setting object itself? |
| | 2497 | } |
| | 2498 | ); |
| | 2499 | controlNotification = new api.Notification( code, params ); |
| | 2500 | control.notifications.add( controlNotification.code, controlNotification ); |
| 2482 | | control.ready(); |
| 2483 | | }); |
| | 2507 | /* |
| | 2508 | * Note that this debounced/deferred rendering is needed for two reasons: |
| | 2509 | * 1) The 'remove' event is triggered just _before_ the notification is actually removed. |
| | 2510 | * 2) Improve performance when adding/removing multiple notifications at a time. |
| | 2511 | */ |
| | 2512 | debouncedRenderNotifications = _.debounce( function renderNotifications() { |
| | 2513 | control.renderNotifications(); |
| | 2514 | } ); |
| | 2515 | control.notifications.bind( 'add', function( notification ) { |
| | 2516 | wp.a11y.speak( notification.message, 'assertive' ); |
| | 2517 | debouncedRenderNotifications(); |
| | 2518 | } ); |
| | 2519 | control.notifications.bind( 'remove', debouncedRenderNotifications ); |
| | 2520 | control.renderNotifications(); |