WordPress.org

Make WordPress Core

Ticket #33901: 33901.3.diff

File 33901.3.diff, 31.7 KB (added by westonruter, 4 years ago)

QUnit: https://github.com/xwp/wordpress-develop/commit/19bcb60fb41e389614486f28fcbdbbf9eea20f1c

  • src/wp-admin/includes/widgets.php

    diff --git src/wp-admin/includes/widgets.php src/wp-admin/includes/widgets.php
    index 356970f..19fd390 100644
    function wp_widget_control( $sidebar_args ) { 
    181181        $multi_number = isset($sidebar_args['_multi_num']) ? $sidebar_args['_multi_num'] : '';
    182182        $add_new = isset($sidebar_args['_add']) ? $sidebar_args['_add'] : '';
    183183
     184        $before_form = isset( $sidebar_args['before_form'] ) ? $sidebar_args['before_form'] : '<form method="post">';
     185        $after_form = isset( $sidebar_args['after_form'] ) ? $sidebar_args['after_form'] : '</form>';
     186        $before_widget_content = isset( $sidebar_args['before_widget_content'] ) ? $sidebar_args['before_widget_content'] : '<div class="widget-content">';
     187        $after_widget_content = isset( $sidebar_args['after_widget_content'] ) ? $sidebar_args['after_widget_content'] : '</div>';
     188
    184189        $query_arg = array( 'editwidget' => $widget['id'] );
    185190        if ( $add_new ) {
    186191                $query_arg['addnew'] = 1;
    function wp_widget_control( $sidebar_args ) { 
    225230        </div>
    226231
    227232        <div class="widget-inside">
    228         <form method="post">
    229         <div class="widget-content">
    230 <?php
    231         if ( isset($control['callback']) )
     233        <?php echo $before_form; ?>
     234        <?php echo $before_widget_content; ?>
     235        <?php
     236        if ( isset( $control['callback'] ) ) {
    232237                $has_form = call_user_func_array( $control['callback'], $control['params'] );
    233         else
    234                 echo "\t\t<p>" . __('There are no options for this widget.') . "</p>\n"; ?>
    235         </div>
     238        } else {
     239                echo "\t\t<p>" . __('There are no options for this widget.') . "</p>\n";
     240        }
     241        ?>
     242        <?php echo $after_widget_content; ?>
    236243        <input type="hidden" name="widget-id" class="widget-id" value="<?php echo esc_attr($id_format); ?>" />
    237244        <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" />
    238245        <input type="hidden" name="widget-width" class="widget-width" value="<?php if (isset( $control['width'] )) echo esc_attr($control['width']); ?>" />
    function wp_widget_control( $sidebar_args ) { 
    252259                </div>
    253260                <br class="clear" />
    254261        </div>
    255         </form>
     262        <?php echo $after_form; ?>
    256263        </div>
    257264
    258265        <div class="widget-description">
  • src/wp-admin/js/customize-widgets.js

    diff --git src/wp-admin/js/customize-widgets.js src/wp-admin/js/customize-widgets.js
    index 6a640e0..8edc02c 100644
     
    417417                /**
    418418                 * @since 4.1.0
    419419                 */
    420                 initialize: function ( id, options ) {
     420                initialize: function( id, options ) {
    421421                        var control = this;
    422                         api.Control.prototype.initialize.call( control, id, options );
    423                         control.expanded = new api.Value();
     422
     423                        control.widgetControlEmbedded = false;
     424                        control.widgetContentEmbedded = false;
     425                        control.expanded = new api.Value( false );
    424426                        control.expandedArgumentsQueue = [];
    425                         control.expanded.bind( function ( expanded ) {
     427                        control.expanded.bind( function( expanded ) {
    426428                                var args = control.expandedArgumentsQueue.shift();
    427429                                args = $.extend( {}, control.defaultExpandedArguments, args );
    428430                                control.onChangeExpanded( expanded, args );
    429431                        });
    430                         control.expanded.set( false );
     432
     433                        api.Control.prototype.initialize.call( control, id, options );
    431434                },
    432435
    433436                /**
    434                  * Set up the control
     437                 * Set up the control.
     438                 *
     439                 * @since 3.9.0
    435440                 */
    436441                ready: function() {
    437                         this._setupModel();
    438                         this._setupWideWidget();
    439                         this._setupControlToggle();
    440                         this._setupWidgetTitle();
    441                         this._setupReorderUI();
    442                         this._setupHighlightEffects();
    443                         this._setupUpdateUI();
    444                         this._setupRemoveUI();
     442                        var control = this;
     443
     444                        /*
     445                         * Embed a placeholder once the section is expanded. The full widget
     446                         * form content will be embedded once the control itself is expanded,
     447                         * and at this point the widget-added event will be triggered.
     448                         */
     449                        if ( ! control.section() ) {
     450                                control.embedWidgetControl();
     451                        } else {
     452                                api.section( control.section(), function( section ) {
     453                                        var onExpanded = function( isExpanded ) {
     454                                                if ( isExpanded ) {
     455                                                        control.embedWidgetControl();
     456                                                        section.expanded.unbind( onExpanded );
     457                                                }
     458                                        };
     459                                        if ( section.expanded() ) {
     460                                                onExpanded( true );
     461                                        } else {
     462                                                section.expanded.bind( onExpanded );
     463                                        }
     464                                } );
     465                        }
     466                },
     467
     468                /**
     469                 * Embed the .widget element inside the li container.
     470                 *
     471                 * @since 4.4.0
     472                 */
     473                embedWidgetControl: function() {
     474                        var control = this, widgetControl;
     475
     476                        if ( control.widgetControlEmbedded ) {
     477                                return;
     478                        }
     479                        control.widgetControlEmbedded = true;
     480
     481                        widgetControl = $( control.params.widget_control );
     482                        control.container.append( widgetControl );
     483
     484                        control._setupModel();
     485                        control._setupWideWidget();
     486                        control._setupControlToggle();
     487
     488                        control._setupWidgetTitle();
     489                        control._setupReorderUI();
     490                        control._setupHighlightEffects();
     491                        control._setupUpdateUI();
     492                        control._setupRemoveUI();
     493                },
     494
     495                /**
     496                 * Embed the actual widget form inside of .widget-content and finally trigger the widget-added event.
     497                 *
     498                 * @since 4.4.0
     499                 */
     500                embedWidgetContent: function() {
     501                        var control = this, widgetContent;
     502
     503                        control.embedWidgetControl();
     504                        if ( control.widgetContentEmbedded ) {
     505                                return;
     506                        }
     507                        control.widgetContentEmbedded = true;
     508
     509                        widgetContent = $( control.params.widget_content );
     510                        control.container.find( '.widget-content:first' ).append( widgetContent );
    445511
    446512                        /*
    447513                         * Trigger widget-added event so that plugins can attach any event
    448514                         * listeners and dynamic UI elements.
    449515                         */
    450                         $( document ).trigger( 'widget-added', [ this.container.find( '.widget:first' ) ] );
     516                        $( document ).trigger( 'widget-added', [ control.container.find( '.widget:first' ) ] );
     517
    451518                },
    452519
    453520                /**
     
    10081075                        var self = this, instanceOverride, completeCallback, $widgetRoot, $widgetContent,
    10091076                                updateNumber, params, data, $inputs, processing, jqxhr, isChanged;
    10101077
     1078                        // The updateWidget logic requires that the form fields to be fully present.
     1079                        self.embedWidgetContent();
     1080
    10111081                        args = $.extend( {
    10121082                                instance: null,
    10131083                                complete: null,
     
    12551325                onChangeExpanded: function ( expanded, args ) {
    12561326                        var self = this, $widget, $inside, complete, prevComplete;
    12571327
     1328                        self.embedWidgetControl(); // Make sure the outer form is embedded so that the expanded state can be set in the UI.
     1329                        if ( expanded ) {
     1330                                self.embedWidgetContent();
     1331                        }
     1332
    12581333                        // If the expanded state is unchanged only manipulate container expanded states
    12591334                        if ( args.unchanged ) {
    12601335                                if ( expanded ) {
  • src/wp-includes/class-wp-customize-control.php

    diff --git src/wp-includes/class-wp-customize-control.php src/wp-includes/class-wp-customize-control.php
    index f105ab1..b6ffa1a 100644
    class WP_Widget_Form_Customize_Control extends WP_Customize_Control { 
    14871487        public $height;
    14881488        public $is_wide = false;
    14891489
     1490        /**
     1491         * Gather control params for exporting to JavaScript.
     1492         *
     1493         * @global array $wp_registered_widgets
     1494         */
    14901495        public function to_json() {
     1496                global $wp_registered_widgets;
     1497
    14911498                parent::to_json();
    14921499                $exported_properties = array( 'widget_id', 'widget_id_base', 'sidebar_id', 'width', 'height', 'is_wide' );
    14931500                foreach ( $exported_properties as $key ) {
    14941501                        $this->json[ $key ] = $this->$key;
    14951502                }
    1496         }
    14971503
    1498         /**
    1499          *
    1500          * @global array $wp_registered_widgets
    1501          */
    1502         public function render_content() {
    1503                 global $wp_registered_widgets;
     1504                // Get the widget_control and widget_content.
    15041505                require_once ABSPATH . '/wp-admin/includes/widgets.php';
    15051506
    15061507                $widget = $wp_registered_widgets[ $this->widget_id ];
    class WP_Widget_Form_Customize_Control extends WP_Customize_Control { 
    15141515                );
    15151516
    15161517                $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
    1517                 echo $this->manager->widgets->get_widget_control( $args );
     1518                $widget_control_parts = $this->manager->widgets->get_widget_control_parts( $args );
     1519
     1520                $this->json['widget_control'] = $widget_control_parts['control'];
     1521                $this->json['widget_content'] = $widget_control_parts['content'];
    15181522        }
    15191523
    15201524        /**
     1525         * Override render_content to be no-op since content is exported via to_json for deferred embedding.
     1526         */
     1527        public function render_content() {}
     1528
     1529        /**
    15211530         * Whether the current widget is rendered on the page.
    15221531         *
    15231532         * @since 4.0.0
  • src/wp-includes/class-wp-customize-widgets.php

    diff --git src/wp-includes/class-wp-customize-widgets.php src/wp-includes/class-wp-customize-widgets.php
    index 8569228..a003393 100644
    final class WP_Customize_Widgets { 
    898898         * @return string Widget control form HTML markup.
    899899         */
    900900        public function get_widget_control( $args ) {
     901                $args[0]['before_form'] = '<div class="form">';
     902                $args[0]['after_form'] = '</div><!-- .form -->';
     903                $args[0]['before_widget_content'] = '<div class="widget-content">';
     904                $args[0]['after_widget_content'] = '</div><!-- .widget-content -->';
    901905                ob_start();
    902 
    903906                call_user_func_array( 'wp_widget_control', $args );
    904                 $replacements = array(
    905                         '<form method="post">' => '<div class="form">',
    906                         '</form>' => '</div><!-- .form -->',
    907                 );
    908 
    909907                $control_tpl = ob_get_clean();
     908                return $control_tpl;
     909        }
    910910
    911                 $control_tpl = str_replace( array_keys( $replacements ), array_values( $replacements ), $control_tpl );
     911        /**
     912         * Get the widget control markup parts.
     913         *
     914         * @since 4.4.0
     915         * @access public
     916         *
     917         * @param array $args Widget control arguments.
     918         * @return array {
     919         *     @type string $control  Markup for widget control wrapping form.
     920         *     @type string $content  The contents of the widget form itself.
     921         * }
     922         */
     923        public function get_widget_control_parts( $args ) {
     924                $args[0]['before_widget_content'] = '<div class="widget-content">';
     925                $args[0]['after_widget_content'] = '</div><!-- .widget-content -->';
     926                $control_markup = $this->get_widget_control( $args );
     927
     928                $content_start_pos = strpos( $control_markup, $args[0]['before_widget_content'] );
     929                $content_end_pos = strrpos( $control_markup, $args[0]['after_widget_content'] );
     930
     931                $control = substr( $control_markup, 0, $content_start_pos + strlen( $args[0]['before_widget_content'] ) );
     932                $control .= substr( $control_markup, $content_end_pos );
     933                $content = trim( substr(
     934                        $control_markup,
     935                        $content_start_pos + strlen( $args[0]['before_widget_content'] ),
     936                        $content_end_pos - $content_start_pos - strlen( $args[0]['before_widget_content'] )
     937                ) );
    912938
    913                 return $control_tpl;
     939                return compact( 'control', 'content' );
    914940        }
    915941
    916942        /**
  • tests/phpunit/tests/customize/widgets.php

    diff --git tests/phpunit/tests/customize/widgets.php tests/phpunit/tests/customize/widgets.php
    index 9f30b94..50aab18 100644
    class Tests_WP_Customize_Widgets extends WP_UnitTestCase { 
    195195                $unsanitized_from_js = $this->manager->widgets->sanitize_widget_instance( $sanitized_for_js );
    196196                $this->assertEquals( $unsanitized_from_js, $new_categories_instance );
    197197        }
     198
     199        /**
     200         * Get the widget control args for tests.
     201         *
     202         * @return array
     203         */
     204        function get_test_widget_control_args() {
     205                global $wp_registered_widgets;
     206                require_once ABSPATH . '/wp-admin/includes/widgets.php';
     207                $widget_id = 'search-2';
     208                $widget = $wp_registered_widgets[ $widget_id ];
     209                $args = array(
     210                        'widget_id' => $widget['id'],
     211                        'widget_name' => $widget['name'],
     212                );
     213                $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
     214                return $args;
     215        }
     216
     217        /**
     218         * @see WP_Customize_Widgets::get_widget_control()
     219         */
     220        function test_get_widget_control() {
     221                $this->do_customize_boot_actions();
     222                $widget_control = $this->manager->widgets->get_widget_control( $this->get_test_widget_control_args() );
     223
     224                $this->assertContains( '<div class="form">', $widget_control );
     225                $this->assertContains( '<div class="widget-content">', $widget_control );
     226                $this->assertContains( '<input type="hidden" name="id_base" class="id_base" value="search"', $widget_control );
     227                $this->assertContains( '<input class="widefat"', $widget_control );
     228        }
     229
     230        /**
     231         * @see WP_Customize_Widgets::get_widget_control_parts()
     232         */
     233        function test_get_widget_control_parts() {
     234                $this->do_customize_boot_actions();
     235                $widget_control_parts = $this->manager->widgets->get_widget_control_parts( $this->get_test_widget_control_args() );
     236                $this->assertArrayHasKey( 'content', $widget_control_parts );
     237                $this->assertArrayHasKey( 'control', $widget_control_parts );
     238
     239                $this->assertContains( '<div class="form">', $widget_control_parts['control'] );
     240                $this->assertContains( '<div class="widget-content">', $widget_control_parts['control'] );
     241                $this->assertContains( '<input type="hidden" name="id_base" class="id_base" value="search"', $widget_control_parts['control'] );
     242                $this->assertNotContains( '<input class="widefat"', $widget_control_parts['control'] );
     243                $this->assertContains( '<input class="widefat"', $widget_control_parts['content'] );
     244        }
     245
     246        /**
     247         * @see WP_Widget_Form_Customize_Control::json()
     248         */
     249        function test_wp_widget_form_customize_control_json() {
     250                $this->do_customize_boot_actions();
     251                $control = $this->manager->get_control( 'widget_search[2]' );
     252                $params = $control->json();
     253
     254                $this->assertEquals( 'widget_form', $params['type'] );
     255                $this->assertRegExp( '#^<li[^>]+>\s+</li>$#', $params['content'] );
     256                $this->assertRegExp( '#^<div[^>]*class=\'widget\'[^>]*#s', $params['widget_control'] );
     257                $this->assertContains( '<div class="widget-content"></div>', $params['widget_control'] );
     258                $this->assertNotContains( '<input class="widefat"', $params['widget_control'] );
     259                $this->assertContains( '<input class="widefat"', $params['widget_content'] );
     260                $this->assertEquals( 'search-2', $params['widget_id'] );
     261                $this->assertEquals( 'search', $params['widget_id_base'] );
     262                $this->assertArrayHasKey( 'sidebar_id', $params );
     263                $this->assertArrayHasKey( 'width', $params );
     264                $this->assertArrayHasKey( 'height', $params );
     265                $this->assertInternalType( 'bool', $params['is_wide'] );
     266
     267        }
    198268}
  • tests/phpunit/tests/widgets.php

    diff --git tests/phpunit/tests/widgets.php tests/phpunit/tests/widgets.php
    index 443d3f3..c0dfe08 100644
    class Tests_Widgets extends WP_UnitTestCase { 
    293293                $this->assertArrayNotHasKey( 2, $option_value );
    294294        }
    295295
     296        /**
     297         * @see wp_widget_control()
     298         */
     299        function test_wp_widget_control() {
     300                global $wp_registered_widgets;
     301
     302                wp_widgets_init();
     303                require_once ABSPATH . '/wp-admin/includes/widgets.php';
     304                $widget_id = 'search-2';
     305                $widget = $wp_registered_widgets[ $widget_id ];
     306                $params = array(
     307                        'widget_id' => $widget['id'],
     308                        'widget_name' => $widget['name'],
     309                );
     310                $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $params, 1 => $widget['params'][0] ) );
     311
     312                ob_start();
     313                call_user_func_array( 'wp_widget_control', $args );
     314                $control = ob_get_clean();
     315                $this->assertNotEmpty( $control );
     316
     317                $this->assertContains( '<div class="widget-top">', $control );
     318                $this->assertContains( '<div class="widget-title-action">', $control );
     319                $this->assertContains( '<div class="widget-title">', $control );
     320                $this->assertContains( '<form method="post">', $control );
     321                $this->assertContains( '<div class="widget-content">', $control );
     322                $this->assertContains( '<input class="widefat"', $control );
     323                $this->assertContains( '<input type="hidden" name="id_base" class="id_base" value="search"', $control );
     324                $this->assertContains( '<div class="widget-control-actions">', $control );
     325                $this->assertContains( '<div class="alignleft">', $control );
     326                $this->assertContains( 'widget-control-remove', $control );
     327                $this->assertContains( 'widget-control-close', $control );
     328                $this->assertContains( '<div class="alignright">', $control );
     329                $this->assertContains( '<input type="submit" name="savewidget"', $control );
     330
     331                $param_overrides = array(
     332                        'before_form' => '<!-- before_form -->',
     333                        'after_form' => '<!-- after_form -->',
     334                        'before_widget_content' => '<!-- before_widget_content -->',
     335                        'after_widget_content' => '<!-- after_widget_content -->',
     336                );
     337                $params = array_merge( $params, $param_overrides );
     338                $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $params, 1 => $widget['params'][0] ) );
     339
     340                ob_start();
     341                call_user_func_array( 'wp_widget_control', $args );
     342                $control = ob_get_clean();
     343                $this->assertNotEmpty( $control );
     344                $this->assertNotContains( '<form method="post">', $control );
     345                $this->assertNotContains( '<div class="widget-content">', $control );
     346
     347                foreach ( $param_overrides as $contained ) {
     348                        $this->assertContains( $contained, $control );
     349                }
     350        }
     351
    296352}
  • tests/qunit/fixtures/customize-settings.js

    diff --git tests/qunit/fixtures/customize-settings.js tests/qunit/fixtures/customize-settings.js
    index af1a2cf..39a49f5 100644
     
    11window.wp = window.wp || {};
    2 window.wp.customize = window.wp.customize || { get: function(){} };
     2window.wp.customize = window.wp.customize || { get: function() {} };
    33
    44var customizerRootElement;
    55customizerRootElement = jQuery( '<div id="customize-theme-controls"><ul></ul></div>' );
    6 customizerRootElement.css( { position: 'absolute', left: -10000, top: -10000 } ); // remove from view
     6customizerRootElement.css( { position: 'absolute', left: -10000, top: -10000 } ); // Remove from view.
    77jQuery( document.body ).append( customizerRootElement );
    88
    99window._wpCustomizeSettings = {
  • new file tests/qunit/fixtures/customize-widgets.js

    diff --git tests/qunit/fixtures/customize-widgets.js tests/qunit/fixtures/customize-widgets.js
    new file mode 100644
    index 0000000..d3f8bb0
    - +  
     1window._wpCustomizeWidgetsSettings = {
     2        'nonce': '12cc9d3284',
     3        'registeredSidebars': [{
     4                'name': 'Widget Area',
     5                'id': 'sidebar-1',
     6                'description': 'Add widgets here to appear in your sidebar.',
     7                'class': '',
     8                'before_widget': '<aside id="%1$s" class="widget %2$s">',
     9                'after_widget': '</aside>',
     10                'before_title': '<h2 class="widget-title">',
     11                'after_title': '</h2>'
     12        }],
     13        'registeredWidgets': {
     14                'search-2': {
     15                        'name': 'Search',
     16                        'id': 'search-2',
     17                        'params': [
     18                                {
     19                                        'number': 2
     20                                }
     21                        ],
     22                        'classname': 'widget_search',
     23                        'description': 'A search form for your site.'
     24                }
     25        },
     26        'availableWidgets': [
     27                {
     28                        'name': 'Search',
     29                        'id': 'search-2',
     30                        'params': [
     31                                {
     32                                        'number': 2
     33                                }
     34                        ],
     35                        'classname': 'widget_search',
     36                        'description': 'A search form for your site.',
     37                        'temp_id': 'search-__i__',
     38                        'is_multi': true,
     39                        'multi_number': 3,
     40                        'is_disabled': false,
     41                        'id_base': 'search',
     42                        'transport': 'refresh',
     43                        'width': 250,
     44                        'height': 200,
     45                        'is_wide': false
     46                }
     47        ],
     48        'l10n': {
     49                'saveBtnLabel': 'Apply',
     50                'saveBtnTooltip': 'Save and preview changes before publishing them.',
     51                'removeBtnLabel': 'Remove',
     52                'removeBtnTooltip': 'Trash widget by moving it to the inactive widgets sidebar.',
     53                'error': 'An error has occurred. Please reload the page and try again.',
     54                'widgetMovedUp': 'Widget moved up',
     55                'widgetMovedDown': 'Widget moved down'
     56        },
     57        'tpl': {
     58                'widgetReorderNav': '<div class="widget-reorder-nav"><span class="move-widget" tabindex="0">Move to another area&hellip;</span><span class="move-widget-down" tabindex="0">Move down</span><span class="move-widget-up" tabindex="0">Move up</span></div>',
     59                'moveWidgetArea': '<div class="move-widget-area"> <p class="description">Select an area to move this widget into:</p> <ul class="widget-area-select"> <% _.each( sidebars, function ( sidebar ){ %> <li class="" data-id="<%- sidebar.id %>" title="<%- sidebar.description %>" tabindex="0"><%- sidebar.name %></li> <% }); %> </ul> <div class="move-widget-actions"> <button class="move-widget-btn button-secondary" type="button">Move</button> </div> </div>'
     60        }
     61};
     62
     63window._wpCustomizeSettings.panels.widgets = {
     64        'id': 'widgets',
     65        'description': 'Widgets are independent sections of content that can be placed into widgetized areas provided by your theme (commonly called sidebars).',
     66        'priority': 110,
     67        'type': 'default',
     68        'title': 'Widgets',
     69        'content': '',
     70        'active': true,
     71        'instanceNumber': 1
     72};
     73
     74window._wpCustomizeSettings.sections['sidebar-widgets-sidebar-1'] = {
     75        'id': 'sidebar-widgets-sidebar-1',
     76        'description': 'Add widgets here to appear in your sidebar.',
     77        'priority': 0,
     78        'panel': 'widgets',
     79        'type': 'sidebar',
     80        'title': 'Widget Area',
     81        'content': '',
     82        'active': false,
     83        'instanceNumber': 1,
     84        'customizeAction': 'Customizing &#9656; Widgets',
     85        'sidebarId': 'sidebar-1'
     86};
     87
     88window._wpCustomizeSettings.settings['widget_search[2]'] = {
     89        'value': {
     90                'encoded_serialized_instance': 'YToxOntzOjU6InRpdGxlIjtzOjY6IkJ1c2NhciI7fQ==',
     91                'title': 'Buscar',
     92                'is_widget_customizer_js_value': true,
     93                'instance_hash_key': '45f0a7f15e50bd3be86b141e2a8b3aaf'
     94        },
     95        'transport': 'refresh',
     96        'dirty': false
     97};
     98window._wpCustomizeSettings.settings['sidebars_widgets[sidebar-1]'] = {
     99        'value': [ 'search-2' ],
     100        'transport': 'refresh',
     101        'dirty': false
     102};
     103
     104window._wpCustomizeSettings.controls['widget_search[2]'] = {
     105        'settings': {
     106                'default': 'widget_search[2]'
     107        },
     108        'type': 'widget_form',
     109        'priority': 0,
     110        'active': false,
     111        'section': 'sidebar-widgets-sidebar-1',
     112        'content': '<li id="customize-control-widget_search-2" class="customize-control customize-control-widget_form"> <\/li>',
     113        'label': 'Search',
     114        'description': '',
     115        'instanceNumber': 2,
     116        'widget_id': 'search-2',
     117        'widget_id_base': 'search',
     118        'sidebar_id': 'sidebar-1',
     119        'width': 250,
     120        'height': 200,
     121        'is_wide': false,
     122        'widget_control': '<div id="widget-15_search-2" class="widget"> <div class="widget-top"> <div class="widget-title-action"> <a class="widget-action hide-if-no-js" href="#available-widgets"><\/a> <a class="widget-control-edit hide-if-js" href="\/wp-admin\/customize.php?editwidget=search-2&#038;key=-1"> <span class="edit">Edit<\/span> <span class="add">Add<\/span> <span class="screen-reader-text">Search<\/span> <\/a> <\/div> <div class="widget-title"><h4>Search<span class="in-widget-title"><\/span><\/h4><\/div> <\/div> <div class="widget-inside"> <div class="form"> <div class="widget-content"><\/div><!-- .widget-content --> <input type="hidden" name="widget-id" class="widget-id" value="search-2" \/> <input type="hidden" name="id_base" class="id_base" value="search" \/> <input type="hidden" name="widget-width" class="widget-width" value="250" \/> <input type="hidden" name="widget-height" class="widget-height" value="200" \/> <input type="hidden" name="widget_number" class="widget_number" value="2" \/> <input type="hidden" name="multi_number" class="multi_number" value="" \/> <input type="hidden" name="add_new" class="add_new" value="" \/> <div class="widget-control-actions"> <div class="alignleft"> <a class="widget-control-remove" href="#remove">Delete<\/a> |   <a class="widget-control-close" href="#close">Close<\/a> <\/div> <div class="alignright"> <input type="submit" name="savewidget" id="widget-search-2-savewidget" class="button button-primary widget-control-save right" value="Save"  \/> <span class="spinner"><\/span> <\/div> <br class="clear" \/> <\/div> <\/div><!-- .form --> <\/div> <div class="widget-description"> A search form for your site.  <\/div> <\/div>',
     123        'widget_content': '<p><label for="widget-search-2-title">Title: <input class="widefat" id="widget-search-2-title" name="widget-search[2][title]" type="text" value="Buscar" \/><\/label><\/p>'
     124};
     125window._wpCustomizeSettings.controls['sidebars_widgets[sidebar-1]'] = {
     126        'settings': {
     127                'default': 'sidebars_widgets[sidebar-1]'
     128        },
     129        'type': 'sidebar_widgets',
     130        'priority': 99,
     131        'active': true,
     132        'section': 'sidebar-widgets-sidebar-1',
     133        'content': '<li id="customize-control-sidebars_widgets-sidebar-1" class="customize-control customize-control-sidebar_widgets"> <span class="button-secondary add-new-widget" tabindex="0">    Add a Widget  <\/span> <span class="reorder-toggle" tabindex="0"> <span class="reorder">Reorder<\/span> <span class="reorder-done">Done<\/span> <\/span> <\/li>',
     134        'label': '',
     135        'description': '',
     136        'instanceNumber': 1,
     137        'sidebar_id': 'sidebar-1'
     138};
  • tests/qunit/index.html

    diff --git tests/qunit/index.html tests/qunit/index.html
    index 71599d4..aa454a9 100644
     
    2525                        <script src="fixtures/customize-header.js"></script>
    2626                        <script src="fixtures/customize-settings.js"></script>
    2727                        <script src="fixtures/customize-menus.js"></script>
     28                        <script src="fixtures/customize-widgets.js"></script>
    2829                </div>
    2930                <p><a href="editor">TinyMCE tests</a></p>
    3031
     
    4445
    4546                <script src="../../src/wp-admin/js/nav-menu.js"></script>
    4647                <script src="../../src/wp-admin/js/customize-nav-menus.js"></script>
     48                <script src="../../src/wp-admin/js/customize-widgets.js"></script>
    4749                <script src="../../src/wp-admin/js/word-count.js"></script>
    4850
    4951                <!-- Unit tests -->
     
    5456                <script src="wp-admin/js/customize-controls.js"></script>
    5557                <script src="wp-admin/js/customize-controls-utils.js"></script>
    5658                <script src="wp-admin/js/customize-nav-menus.js"></script>
     59                <script src="wp-admin/js/customize-widgets.js"></script>
    5760                <script src="wp-admin/js/word-count.js"></script>
    5861
    5962                <!-- Customizer templates for sections -->
     
    267270                        <div class="menu-item-reorder-nav">
    268271                                <button type="button" class="menus-move-up">Move up</button><button type="button" class="menus-move-down">Move down</button><button type="button" class="menus-move-left">Move one level up</button><button type="button" class="menus-move-right">Move one level down</button>                 </div>
    269272                </script>
     273
     274                <script type="text/html" id="tmpl-customize-section-sidebar">
     275                        <li id="accordion-section-{{ data.id }}" class="accordion-section control-section control-section-{{ data.type }}">
     276                        <h3 class="accordion-section-title" tabindex="0">
     277                                {{ data.title }}
     278                                <span class="screen-reader-text">Press return or enter to open</span>
     279                        </h3>
     280                        <ul class="accordion-section-content">
     281                                <li class="customize-section-description-container">
     282                                        <div class="customize-section-title">
     283                                                <button class="customize-section-back" tabindex="-1">
     284                                                        <span class="screen-reader-text">Back</span>
     285                                                </button>
     286                                                <h3>
     287                                                        <span class="customize-action">
     288                                                                {{{ data.customizeAction }}}
     289                                                        </span>
     290                                                        {{ data.title }}
     291                                                </h3>
     292                                        </div>
     293                                        <# if ( data.description ) { #>
     294                                                <div class="description customize-section-description">
     295                                                        {{{ data.description }}}
     296                                                </div>
     297                                        <# } #>
     298                                </li>
     299                        </ul>
     300                        </li>
     301                </script>
     302
    270303                <div hidden>
    271304                        <div id="available-menu-items" class="accordion-container">
    272305                        <div class="customize-section-title">
     
    375408                                                </div><!-- #available-menu-items -->
    376409                        </div><!-- end nav menu templates -->
    377410
     411                <div hidden>
     412                        <div id="widgets-left"><!-- compatibility with JS which looks for widget templates here -->
     413                                <div id="available-widgets">
     414                                        <div class="customize-section-title">
     415                                                <button class="customize-section-back" tabindex="-1">
     416                                                        <span class="screen-reader-text">Back</span>
     417                                                </button>
     418                                                <h3>
     419                                                        <span class="customize-action">Customizing &#9656; Widgets</span>
     420                                                        Add a Widget                            </h3>
     421                                        </div>
     422                                        <div id="available-widgets-filter">
     423                                                <label class="screen-reader-text" for="widgets-search">Search Widgets</label>
     424                                                <input type="search" id="widgets-search" placeholder="Search widgets&hellip;" />
     425                                        </div>
     426                                        <div id="available-widgets-list">
     427                                                                        <div id="widget-tpl-search-2" data-widget-id="search-2" class="widget-tpl search-2" tabindex="0">
     428                                                        <div id='widget-11_search-__i__' class='widget'>        <div class="widget-top">
     429                        <div class="widget-title-action">
     430                                <a class="widget-action hide-if-no-js" href="#available-widgets"></a>
     431                                <a class="widget-control-edit hide-if-js" href="/wp-admin/customize.php?editwidget=search-2&#038;addnew=1&#038;num=3&#038;base=search">
     432                                        <span class="edit">Edit</span>
     433                                        <span class="add">Add</span>
     434                                        <span class="screen-reader-text">Search</span>
     435                                </a>
     436                        </div>
     437                        <div class="widget-title"><h4>Search<span class="in-widget-title"></span></h4></div>
     438                        </div>
    378439
     440                        <div class="widget-inside">
     441                        <div class="form">
     442                        <div class="widget-content">
     443                                <p><label for="widget-search-__i__-title">Title: <input class="widefat" id="widget-search-__i__-title" name="widget-search[__i__][title]" type="text" value="" /></label></p>
     444                        </div>
     445                        <input type="hidden" name="widget-id" class="widget-id" value="search-__i__" />
     446                        <input type="hidden" name="id_base" class="id_base" value="search" />
     447                        <input type="hidden" name="widget-width" class="widget-width" value="250" />
     448                        <input type="hidden" name="widget-height" class="widget-height" value="200" />
     449                        <input type="hidden" name="widget_number" class="widget_number" value="2" />
     450                        <input type="hidden" name="multi_number" class="multi_number" value="3" />
     451                        <input type="hidden" name="add_new" class="add_new" value="multi" />
     452
     453                        <div class="widget-control-actions">
     454                                <div class="alignleft">
     455                                <a class="widget-control-remove" href="#remove">Delete</a> |
     456                                <a class="widget-control-close" href="#close">Close</a>
     457                                </div>
     458                                <div class="alignright">
     459                                        <input type="submit" name="savewidget" id="widget-search-__i__-savewidget" class="button button-primary widget-control-save right" value="Save"  />                     <span class="spinner"></span>
     460                                </div>
     461                                <br class="clear" />
     462                        </div>
     463                        </div><!-- .form -->
     464                        </div>
     465
     466                        <div class="widget-description">
     467                A search form for your site.
     468                        </div>
     469                </div>                          </div>
     470                                        </div><!-- #available-widgets-list -->
     471                                </div><!-- #available-widgets -->
     472                        </div><!-- #widgets-left -->
     473                </div><!-- end widget templates -->
    379474                <script src="../../src/wp-includes/js/tinymce/tinymce.js"></script>
    380475                <script src="editor/js/utils.js"></script>
    381476                <script src="wp-includes/js/tinymce/plugins/wptextpattern/plugin.js"></script>
  • new file tests/qunit/wp-admin/js/customize-widgets.js

    diff --git tests/qunit/wp-admin/js/customize-widgets.js tests/qunit/wp-admin/js/customize-widgets.js
    new file mode 100644
    index 0000000..3a8a3e3
    - +  
     1/* global wp */
     2jQuery( window ).load( function() {
     3
     4        var api = wp.customize, $ = jQuery;
     5
     6        module( 'Customize Widgets' );
     7
     8        test( 'fixtures should be present', function() {
     9                var widgetControl;
     10                ok( api.panel( 'widgets' ) );
     11                ok( api.section( 'sidebar-widgets-sidebar-1' ) );
     12                widgetControl = api.control( 'widget_search[2]' );
     13                ok( widgetControl );
     14                ok( api.control( 'sidebars_widgets[sidebar-1]' ) );
     15                ok( api( 'widget_search[2]' ) );
     16                ok( api( 'sidebars_widgets[sidebar-1]' ) );
     17                ok( widgetControl.params.content );
     18                ok( widgetControl.params.widget_control );
     19                ok( widgetControl.params.widget_content );
     20                ok( widgetControl.params.widget_id );
     21                ok( widgetControl.params.widget_id_base );
     22        });
     23
     24        test( 'widget contents should embed (with widget-added event) when section and control expand', function() {
     25                var control, section, widgetAddedEvent = null, widgetControlRootElement = null;
     26                control = api.control( 'widget_search[2]' );
     27                section = api.section( 'sidebar-widgets-sidebar-1' );
     28
     29                $( document ).on( 'widget-added', function( event, widgetElement ) {
     30                        widgetAddedEvent = event;
     31                        widgetControlRootElement = widgetElement;
     32                });
     33
     34                ok( ! section.expanded() );
     35                ok( 0 === control.container.find( '> .widget' ).length );
     36
     37                section.expand();
     38                ok( ! widgetAddedEvent );
     39                ok( 1 === control.container.find( '> .widget' ).length );
     40                ok( 0 === control.container.find( '.widget-content' ).children().length );
     41
     42                control.expand();
     43                ok( 1 === control.container.find( '.widget-content' ).children().length );
     44                ok( widgetAddedEvent );
     45                ok( widgetControlRootElement.is( control.container.find( '> .widget' ) ) );
     46                ok( 1 === control.container.find( '.widget-content #widget-search-2-title' ).length );
     47
     48                $( document ).off( 'widget-added' );
     49        });
     50});