Make WordPress Core

Changeset 27986


Ignore:
Timestamp:
04/07/2014 02:09:53 PM (11 years ago)
Author:
ocean90
Message:

Widget Customizer: Make the available widgets panel a Backbone view.

see #27690.

File:
1 edited

Legend:

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

    r27985 r27986  
    1616
    1717    /**
    18      * Set up model
     18     * wp.customize.Widgets.WidgetModel
     19     *
     20     * A single widget model.
     21     *
     22     * @constructor
     23     * @augments Backbone.Model
    1924     */
    2025    api.Widgets.WidgetModel = Backbone.Model.extend({
     
    3540    });
    3641
     42    /**
     43     * wp.customize.Widgets.WidgetCollection
     44     *
     45     * Collection for widget models.
     46     *
     47     * @constructor
     48     * @augments Backbone.Model
     49     */
    3750    api.Widgets.WidgetCollection = Backbone.Collection.extend({
    3851        model: api.Widgets.WidgetModel,
     
    93106    api.Widgets.availableWidgets = new api.Widgets.WidgetCollection( api.Widgets.data.availableWidgets );
    94107
     108    /**
     109     * wp.customize.Widgets.SidebarModel
     110     *
     111     * A single sidebar model.
     112     *
     113     * @constructor
     114     * @augments Backbone.Model
     115     */
    95116    api.Widgets.SidebarModel = Backbone.Model.extend({
    96117        after_title: null,
     
    105126    });
    106127
     128    /**
     129     * wp.customize.Widgets.SidebarCollection
     130     *
     131     * Collection for sidebar models.
     132     *
     133     * @constructor
     134     * @augments Backbone.Collection
     135     */
    107136    api.Widgets.SidebarCollection = Backbone.Collection.extend({
    108137        model: api.Widgets.SidebarModel
    109138    });
    110139    api.Widgets.registeredSidebars = new api.Widgets.SidebarCollection( api.Widgets.data.registeredSidebars );
     140
     141    /**
     142     * wp.customize.Widgets.AvailableWidgetsPanelView
     143     *
     144     * View class for the available widgets panel.
     145     *
     146     * @constructor
     147     * @augments wp.Backbone.View
     148     * @augments Backbone.View
     149     */
     150    api.Widgets.AvailableWidgetsPanelView = wp.Backbone.View.extend({
     151
     152        el: '#available-widgets',
     153
     154        events: {
     155            'input #widgets-search': 'search',
     156            'keyup #widgets-search': 'search',
     157            'change #widgets-search': 'search',
     158            'search #widgets-search': 'search',
     159            'focus .widget-tpl' : 'focus',
     160            'click .widget-tpl' : '_submit',
     161            'keypress .widget-tpl' : '_submit',
     162            'keydown' : 'keyboardAccessible'
     163        },
     164
     165        // Cache current selected widget
     166        selected: null,
     167
     168        // Cache sidebar control which has opened panel
     169        currentSidebarControl: null,
     170        $search: null,
     171
     172        initialize: function() {
     173            var self = this;
     174
     175            this.$search = $( '#widgets-search' );
     176
     177            _.bindAll( this, 'close' );
     178
     179            this.listenTo( this.collection, 'update', this.updateList );
     180
     181            this.updateList();
     182
     183            // If the available widgets panel is open and the customize controls are
     184            // interacted with (i.e. available widgets panel is blurred) then close the
     185            // available widgets panel.
     186            $( '#customize-controls' ).on( 'click keydown', function( e ) {
     187                var isAddNewBtn = $( e.target ).is( '.add-new-widget, .add-new-widget *' );
     188                if ( $( 'body' ).hasClass( 'adding-widget' ) && ! isAddNewBtn ) {
     189                    self.close();
     190                }
     191            } );
     192
     193            // Close the panel if the URL in the preview changes
     194            api.Widgets.Previewer.bind( 'url', this.close );
     195        },
     196
     197        // Performs a search and handles selected widget
     198        search: function( event ) {
     199            var firstVisible;
     200
     201            this.collection.doSearch( event.target.value );
     202
     203            // Remove a widget from being selected if it is no longer visible
     204            if ( this.selected && ! this.selected.is( ':visible' ) ) {
     205                this.selected.removeClass( 'selected' );
     206                this.selected = null;
     207            }
     208
     209            // If a widget was selected but the filter value has been cleared out, clear selection
     210            if ( this.selected && ! event.target.value ) {
     211                this.selected.removeClass( 'selected' );
     212                this.selected = null;
     213            }
     214
     215            // If a filter has been entered and a widget hasn't been selected, select the first one shown
     216            if ( ! this.selected && event.target.value ) {
     217                firstVisible = this.$el.find( '> .widget-tpl:visible:first' );
     218                if ( firstVisible.length ) {
     219                    this.select( firstVisible );
     220                }
     221            }
     222        },
     223
     224        // Changes visibilty of available widgets
     225        updateList: function() {
     226            // First hide all widgets...
     227            this.$el.find( '.widget-tpl' ).hide();
     228
     229            // ..and then show only available widgets which could be filtered
     230            this.collection.each( function( widget ) {
     231                var widgetTpl = $( '#widget-tpl-' + widget.id );
     232                widgetTpl.toggle( ! widget.get( 'is_disabled' ) );
     233                if ( widget.get( 'is_disabled' ) && widgetTpl.is( this.selected ) ) {
     234                    this.selected = null;
     235                }
     236            } );
     237        },
     238
     239        // Hightlights a widget
     240        select: function( widgetTpl ) {
     241            this.selected = $( widgetTpl );
     242            this.selected.siblings( '.widget-tpl' ).removeClass( 'selected' );
     243            this.selected.addClass( 'selected' );
     244        },
     245
     246        // Hightlights a widget on focus
     247        focus: function( event ) {
     248            this.select( $( event.currentTarget ) );
     249        },
     250
     251        // Submit handler for keypress and click on widget
     252        _submit: function( event ) {
     253            // Only proceed with keypress if it is Enter or Spacebar
     254            if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
     255                return;
     256            }
     257
     258            this.submit( $( event.currentTarget ) );
     259        },
     260
     261        // Adds a selected widget to the sidebar
     262        submit: function( widgetTpl ) {
     263            var widgetId, widget;
     264
     265            if ( ! widgetTpl ) {
     266                widgetTpl = this.selected;
     267            }
     268
     269            if ( ! widgetTpl || ! this.currentSidebarControl ) {
     270                return;
     271            }
     272
     273            this.select( widgetTpl );
     274
     275            widgetId = $( this.selected ).data( 'widget-id' );
     276            widget = this.collection.findWhere( { id: widgetId } );
     277            if ( ! widget ) {
     278                return;
     279            }
     280
     281            this.currentSidebarControl.addWidget( widget.get( 'id_base' ) );
     282
     283            this.close();
     284        },
     285
     286        // Opens the panel
     287        open: function( sidebarControl ) {
     288            this.currentSidebarControl = sidebarControl;
     289
     290            // Wide widget controls appear over the preview, and so they need to be collapsed when the panel opens
     291            _( this.currentSidebarControl.getWidgetFormControls() ).each( function( control ) {
     292                if ( control.params.is_wide ) {
     293                    control.collapseForm();
     294                }
     295            } );
     296
     297            $( 'body' ).addClass( 'adding-widget' );
     298
     299            this.$el.find( '.selected' ).removeClass( 'selected' );
     300
     301            // Reset search
     302            this.collection.doSearch( '' );
     303
     304            this.$search.focus();
     305        },
     306
     307        // Closes the panel
     308        close: function( options ) {
     309            options = options || {};
     310
     311            if ( options.returnFocus && this.currentSidebarControl ) {
     312                this.currentSidebarControl.container.find( '.add-new-widget' ).focus();
     313            }
     314
     315            this.currentSidebarControl = null;
     316            this.selected = null;
     317
     318            $( 'body' ).removeClass( 'adding-widget' );
     319
     320            this.$search.val( '' );
     321        },
     322
     323        // Add keyboard accessiblity to the panel
     324        keyboardAccessible: function( event ) {
     325            var isEnter = ( event.which === 13 ),
     326                isEsc = ( event.which === 27 ),
     327                isDown = ( event.which === 40 ),
     328                isUp = ( event.which === 38 ),
     329                selected = null,
     330                firstVisible = this.$el.find( '> .widget-tpl:visible:first' ),
     331                lastVisible = this.$el.find( '> .widget-tpl:visible:last' ),
     332                isSearchFocused = $( event.target ).is( this.$search );
     333
     334            if ( isDown || isUp ) {
     335                if ( isDown ) {
     336                    if ( isSearchFocused ) {
     337                        selected = firstVisible;
     338                    } else if ( this.selected && this.selected.nextAll( '.widget-tpl:visible' ).length !== 0 ) {
     339                        selected = this.selected.nextAll( '.widget-tpl:visible:first' );
     340                    }
     341                } else if ( isUp ) {
     342                    if ( isSearchFocused ) {
     343                        selected = lastVisible;
     344                    } else if ( this.selected && this.selected.prevAll( '.widget-tpl:visible' ).length !== 0 ) {
     345                        selected = this.selected.prevAll( '.widget-tpl:visible:first' );
     346                    }
     347                }
     348
     349                this.select( selected );
     350
     351                if ( selected ) {
     352                    selected.focus();
     353                } else {
     354                    this.$search.focus();
     355                }
     356
     357                return;
     358            }
     359
     360            // If enter pressed but nothing entered, don't do anything
     361            if ( isEnter && ! this.$search.val() ) {
     362                return;
     363            }
     364
     365            if ( isEnter ) {
     366                this.submit();
     367            } else if ( isEsc ) {
     368                this.close( { returnFocus: true } );
     369            }
     370        }
     371    });
    111372
    112373    /**
     
    122383         * @param {String} newForm
    123384         */
    124         rss: function ( e, widget, newForm ) {
     385        rss: function( e, widget, newForm ) {
    125386            var oldWidgetError = widget.find( '.widget-error:first' ),
    126387                newWidgetError = $( '<div>' + newForm + '</div>' ).find( '.widget-error:first' );
     
    137398
    138399    /**
    139      * Widget Form control
     400     * wp.customize.Widgets.WidgetControl
     401     *
     402     * Customizer control for widgets.
    140403     * Note that 'widget_form' must match the WP_Widget_Form_Customize_Control::$type
     404     *
     405     * @constructor
     406     * @augments wp.customize.Control
    141407     */
    142408    api.Widgets.WidgetControl = api.Control.extend({
     
    247513
    248514            // Reposition whenever a sidebar's widgets are changed
    249             api.each( function ( setting ) {
     515            api.each( function( setting ) {
    250516                if ( 0 === setting.id.indexOf( 'sidebars_widgets[' ) ) {
    251517                    setting.bind( function() {
     
    265531            var control = this, close_btn;
    266532
    267             control.container.find( '.widget-top' ).on( 'click', function ( e ) {
     533            control.container.find( '.widget-top' ).on( 'click', function( e ) {
    268534                e.preventDefault();
    269535                var sidebar_widgets_control = control.getSidebarWidgetsControl();
     
    276542            close_btn = control.container.find( '.widget-control-close' );
    277543            // @todo Hitting Enter on this link does nothing; will be resolved in core with <http://core.trac.wordpress.org/ticket/26633>
    278             close_btn.on( 'click', function ( e ) {
     544            close_btn.on( 'click', function( e ) {
    279545                e.preventDefault();
    280546                control.collapseForm();
     
    318584             * @param {jQuery} li
    319585             */
    320             select_sidebar_item = function ( li ) {
     586            select_sidebar_item = function( li ) {
    321587                li.siblings( '.selected' ).removeClass( 'selected' );
    322588                li.addClass( 'selected' );
     
    364630             */
    365631            reorder_nav = control.container.find( '.widget-reorder-nav' );
    366             reorder_nav.find( '.move-widget, .move-widget-down, .move-widget-up' ).on( 'click keypress', function ( event ) {
     632            reorder_nav.find( '.move-widget, .move-widget-down, .move-widget-up' ).on( 'click keypress', function( event ) {
    367633                if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
    368634                    return;
     
    394660             * Handle selecting a sidebar to move to
    395661             */
    396             control.container.find( '.widget-area-select' ).on( 'click keypress', 'li', function ( e ) {
     662            control.container.find( '.widget-area-select' ).on( 'click keypress', 'li', function( e ) {
    397663                if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
    398664                    return;
     
    473739            save_btn.attr( 'title', l10n.saveBtnTooltip );
    474740            save_btn.removeClass( 'button-primary' ).addClass( 'button-secondary' );
    475             save_btn.on( 'click', function ( e ) {
     741            save_btn.on( 'click', function( e ) {
    476742                e.preventDefault();
    477743                control.updateWidget( { disable_form: true } );
     
    492758
    493759            // Handle widgets that support live previews
    494             widget_content.on( 'change input propertychange', ':input', function ( e ) {
     760            widget_content.on( 'change input propertychange', ':input', function( e ) {
    495761                if ( control.live_update_mode ) {
    496762                    if ( e.type === 'change' ) {
     
    506772                control.container.removeClass( 'previewer-loading' );
    507773            } );
    508             api.Widgets.Previewer.bind( 'widget-updated', function ( updated_widget_id ) {
     774            api.Widgets.Previewer.bind( 'widget-updated', function( updated_widget_id ) {
    509775                if ( updated_widget_id === control.params.widget_id ) {
    510776                    control.container.removeClass( 'previewer-loading' );
     
    513779
    514780            // Update widget control to indicate whether it is currently rendered (cf. Widget Visibility)
    515             api.Widgets.Previewer.bind( 'rendered-widgets', function ( rendered_widgets ) {
     781            api.Widgets.Previewer.bind( 'rendered-widgets', function( rendered_widgets ) {
    516782                var is_rendered = !! rendered_widgets[control.params.widget_id];
    517783                control.container.toggleClass( 'widget-rendered', is_rendered );
     
    520786            form_update_event_handler = api.Widgets.formSyncHandlers[ control.params.widget_id_base ];
    521787            if ( form_update_event_handler ) {
    522                 $( document ).on( 'widget-synced', function ( e, widget_el ) {
     788                $( document ).on( 'widget-synced', function( e, widget_el ) {
    523789                    if ( widget_root.is( widget_el ) ) {
    524790                        form_update_event_handler.apply( document, arguments );
     
    539805            remove_btn = control.container.find( 'a.widget-control-remove' );
    540806            // @todo Hitting Enter on this link does nothing; will be resolved in core with <http://core.trac.wordpress.org/ticket/26633>
    541             remove_btn.on( 'click', function ( e ) {
     807            remove_btn.on( 'click', function( e ) {
    542808                e.preventDefault();
    543809
     
    593859         * @private
    594860         */
    595         _getInputs: function ( container ) {
     861        _getInputs: function( container ) {
    596862            return $( container ).find( ':input[name]' );
    597863        },
     
    605871         * @private
    606872         */
    607         _getInputsSignature: function ( inputs ) {
    608             var inputs_signatures = _( inputs ).map( function ( input ) {
     873        _getInputsSignature: function( inputs ) {
     874            var inputs_signatures = _( inputs ).map( function( input ) {
    609875                input = $( input );
    610876                var signature_parts;
     
    626892         * @private
    627893         */
    628         _getInputStatePropertyName: function ( input ) {
     894        _getInputStatePropertyName: function( input ) {
    629895            input = $( input );
    630896            if ( input.is( ':radio, :checkbox' ) ) {
     
    662928         * @param {Boolean} [args.ignore_active_element=false] Whether or not updating a field will be deferred if focus is still on the element.
    663929         */
    664         updateWidget: function ( args ) {
     930        updateWidget: function( args ) {
    665931            var control = this,
    666932                instance_override,
     
    727993            data += '&' + widget_content.find( '~ :input' ).serialize();
    728994
    729             jqxhr = $.post( wp.ajax.settings.url, data, function ( r ) {
     995            jqxhr = $.post( wp.ajax.settings.url, data, function( r ) {
    730996                var message,
    731997                    sanitized_form,
     
    7641030                    // Sync sanitized field states to existing fields if they are aligned
    7651031                    if ( has_same_inputs_in_response && control.live_update_mode ) {
    766                         inputs.each( function ( i ) {
     1032                        inputs.each( function( i ) {
    7671033                            var input = $( this ),
    7681034                                sanitized_input = $( sanitized_inputs[i] ),
     
    8281094                }
    8291095            } );
    830             jqxhr.fail( function ( jqXHR, textStatus ) {
     1096            jqxhr.fail( function( jqXHR, textStatus ) {
    8311097                if ( complete_callback ) {
    8321098                    complete_callback.call( control, textStatus );
     
    8731139         * @param {boolean|undefined} [do_expand] If not supplied, will be inverse of current visibility
    8741140         */
    875         toggleForm: function ( do_expand ) {
     1141        toggleForm: function( do_expand ) {
    8761142            var control = this, widget, inside, complete;
    8771143
     
    8891155            if ( do_expand ) {
    8901156                // Close all other widget controls before expanding this one
    891                 api.control.each( function ( other_control ) {
     1157                api.control.each( function( other_control ) {
    8921158                    if ( control.params.type === other_control.params.type && control !== other_control ) {
    8931159                        other_control.collapseForm();
     
    9751241         * @param {Number} offset 1|-1
    9761242         */
    977         _moveWidgetByOne: function ( offset ) {
     1243        _moveWidgetByOne: function( offset ) {
    9781244            var control = this,
    9791245                i,
     
    9981264         * @param {Boolean} [toggle]
    9991265         */
    1000         toggleWidgetMoveArea: function ( toggle ) {
     1266        toggleWidgetMoveArea: function( toggle ) {
    10011267            var control = this, move_widget_area;
    10021268            move_widget_area = control.container.find( '.move-widget-area' );
     
    10441310
    10451311    /**
    1046      * Sidebar Widgets control
     1312     * wp.customize.Widgets.SidebarControl
     1313     *
     1314     * Customizer control for widgets.
    10471315     * Note that 'sidebar_widgets' must match the WP_Widget_Area_Customize_Control::$type
     1316     *
     1317     * @constructor
     1318     * @augments wp.customize.Control
    10481319     */
    10491320    api.Widgets.SidebarControl = api.Control.extend({
     
    10751346
    10761347                // Filter out any persistent widget_ids for widgets which have been deactivated
    1077                 new_widget_ids = _( new_widget_ids ).filter( function ( new_widget_id ) {
     1348                new_widget_ids = _( new_widget_ids ).filter( function( new_widget_id ) {
    10781349                    var parsed_widget_id = parse_widget_id( new_widget_id );
    10791350                    return !! api.Widgets.availableWidgets.findWhere( { id_base: parsed_widget_id.id_base } );
    10801351                } );
    10811352
    1082                 widget_form_controls = _( new_widget_ids ).map( function ( widget_id ) {
     1353                widget_form_controls = _( new_widget_ids ).map( function( widget_id ) {
    10831354                    var widget_form_control = api.Widgets.getWidgetFormControlForWidget( widget_id );
    10841355                    if ( ! widget_form_control ) {
     
    10891360
    10901361                // Sort widget controls to their new positions
    1091                 widget_form_controls.sort( function ( a, b ) {
     1362                widget_form_controls.sort( function( a, b ) {
    10921363                    var a_index = _.indexOf( new_widget_ids, a.params.widget_id ),
    10931364                        b_index = _.indexOf( new_widget_ids, b.params.widget_id );
     
    11101381
    11111382                // If the widget was dragged into the sidebar, make sure the sidebar_id param is updated
    1112                 _( widget_form_controls ).each( function ( widget_form_control ) {
     1383                _( widget_form_controls ).each( function( widget_form_control ) {
    11131384                    widget_form_control.params.sidebar_id = control.params.sidebar_id;
    11141385                } );
    11151386
    11161387                // Cleanup after widget removal
    1117                 _( removed_widget_ids ).each( function ( removed_widget_id ) {
     1388                _( removed_widget_ids ).each( function( removed_widget_id ) {
    11181389
    11191390                    // Using setTimeout so that when moving a widget to another sidebar, the other sidebars_widgets settings get a chance to update
     
    11271398
    11281399                        // Check if the widget is in another sidebar
    1129                         api.each( function ( other_setting ) {
     1400                        api.each( function( other_setting ) {
    11301401                            if ( other_setting.id === control.setting.id || 0 !== other_setting.id.indexOf( 'sidebars_widgets[' ) || other_setting.id === 'sidebars_widgets[wp_inactive_widgets]' ) {
    11311402                                return;
     
    11791450
    11801451            // Update the model with whether or not the sidebar is rendered
    1181             api.Widgets.Previewer.bind( 'rendered-sidebars', function ( rendered_sidebars ) {
     1452            api.Widgets.Previewer.bind( 'rendered-sidebars', function( rendered_sidebars ) {
    11821453                var is_rendered = !! rendered_sidebars[control.params.sidebar_id];
    11831454                registered_sidebar.set( 'is_rendered', is_rendered );
     
    11851456
    11861457            // Show the sidebar section when it becomes visible
    1187             registered_sidebar.on( 'change:is_rendered', function ( ) {
     1458            registered_sidebar.on( 'change:is_rendered', function( ) {
    11881459                var section_selector = '#accordion-section-sidebar-widgets-' + this.get( 'id' ), section;
    11891460                section = $( section_selector );
     
    12201491                update: function() {
    12211492                    var widget_container_ids = control.section_content.sortable( 'toArray' ), widget_ids;
    1222                     widget_ids = $.map( widget_container_ids, function ( widget_container_id ) {
     1493                    widget_ids = $.map( widget_container_ids, function( widget_container_id ) {
    12231494                        return $( '#' + widget_container_id ).find( ':input[name=widget-id]' ).val();
    12241495                    } );
     
    13071578         * @param {Boolean} toggle to enable/disable reordering
    13081579         */
    1309         toggleReordering: function ( toggle ) {
     1580        toggleReordering: function( toggle ) {
    13101581            var control = this;
    13111582            toggle = Boolean( toggle );
     
    13181589
    13191590            if ( toggle ) {
    1320                 _( control.getWidgetFormControls() ).each( function ( form_control ) {
     1591                _( control.getWidgetFormControls() ).each( function( form_control ) {
    13211592                    form_control.collapseForm();
    13221593                } );
     
    13301601            var control = this, form_controls;
    13311602
    1332             form_controls = _( control.setting() ).map( function ( widget_id ) {
     1603            form_controls = _( control.setting() ).map( function( widget_id ) {
    13331604                var setting_id = widget_id_to_setting_id( widget_id ),
    13341605                    form_control = api.control( setting_id );
     
    13461617         * @returns {object} widget_form control instance
    13471618         */
    1348         addWidget: function ( widget_id ) {
     1619        addWidget: function( widget_id ) {
    13491620            var control = this,
    13501621                control_html,
     
    13781649            control_html = $( '#widget-tpl-' + widget.get( 'id' ) ).html();
    13791650            if ( widget.get( 'is_multi' ) ) {
    1380                 control_html = control_html.replace( /<[^<>]+>/g, function ( m ) {
     1651                control_html = control_html.replace( /<[^<>]+>/g, function( m ) {
    13811652                    return m.replace( /__i__|%i%/g, widget_number );
    13821653                } );
     
    14361707
    14371708            // Make sure widget is removed from the other sidebars
    1438             api.each( function ( other_setting ) {
     1709            api.each( function( other_setting ) {
    14391710                if ( other_setting.id === control.setting.id ) {
    14401711                    return;
     
    14631734                    widget_form_control.updateWidget( {
    14641735                        instance: widget_form_control.setting(),
    1465                         complete: function ( error ) {
     1736                        complete: function( error ) {
    14661737                            if ( error ) {
    14671738                                throw error;
     
    14891760    api.bind( 'ready', function() {
    14901761        // Set up the widgets panel
    1491         api.Widgets.availableWidgetsPanel.setup();
     1762        api.Widgets.availableWidgetsPanel = new api.Widgets.AvailableWidgetsPanelView({
     1763            collection: api.Widgets.availableWidgets
     1764        });
    14921765
    14931766        // Highlight widget control
     
    15411814     * @return {object|null}
    15421815     */
    1543     api.Widgets.getSidebarWidgetControlContainingWidget = function ( widget_id ) {
     1816    api.Widgets.getSidebarWidgetControlContainingWidget = function( widget_id ) {
    15441817        var found_control = null;
    15451818        // @todo this can use widget_id_to_setting_id(), then pass into wp.customize.control( x ).getSidebarWidgetsControl()
    1546         api.control.each( function ( control ) {
     1819        api.control.each( function( control ) {
    15471820            if ( control.params.type === 'sidebar_widgets' && -1 !== _.indexOf( control.setting(), widget_id ) ) {
    15481821                found_control = control;
     
    15581831     * @return {object|null}
    15591832     */
    1560     api.Widgets.getWidgetFormControlForWidget = function ( widget_id ) {
     1833    api.Widgets.getWidgetFormControlForWidget = function( widget_id ) {
    15611834        var found_control = null;
    15621835        // @todo We can just use widget_id_to_setting_id() here
    1563         api.control.each( function ( control ) {
     1836        api.control.each( function( control ) {
    15641837            if ( control.params.type === 'widget_form' && control.params.widget_id === widget_id ) {
    15651838                found_control = control;
     
    15681841
    15691842        return found_control;
    1570     };
    1571 
    1572     /**
    1573      * Available Widgets Panel
    1574      */
    1575     api.Widgets.availableWidgetsPanel = {
    1576         active_sidebar_widgets_control: null,
    1577         selected_widget_tpl: null,
    1578         container: null,
    1579         filter_input: null,
    1580 
    1581         /**
    1582          * Set up event listeners
    1583          */
    1584         setup: function() {
    1585             var panel = this;
    1586 
    1587             panel.container = $( '#available-widgets' );
    1588             panel.filter_input = $( '#available-widgets-filter' ).find( 'input' );
    1589 
    1590             api.Widgets.availableWidgets.on( 'change update', panel.update_available_widgets_list );
    1591             panel.update_available_widgets_list();
    1592 
    1593             // If the available widgets panel is open and the customize controls are
    1594             // interacted with (i.e. available widgets panel is blurred) then close the
    1595             // available widgets panel.
    1596             $( '#customize-controls' ).on( 'click keydown', function ( e ) {
    1597                 var is_add_new_widget_btn = $( e.target ).is( '.add-new-widget, .add-new-widget *' );
    1598                 if ( $( 'body' ).hasClass( 'adding-widget' ) && ! is_add_new_widget_btn ) {
    1599                     panel.close();
    1600                 }
    1601             } );
    1602 
    1603             // Close the panel if the URL in the preview changes
    1604             api.Widgets.Previewer.bind( 'url', function() {
    1605                 panel.close();
    1606             } );
    1607 
    1608             // Submit a selection when clicked or keypressed
    1609             panel.container.find( '.widget-tpl' ).on( 'click keypress', function( event ) {
    1610 
    1611                 // Only proceed with keypress if it is Enter or Spacebar
    1612                 if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
    1613                     return;
    1614                 }
    1615 
    1616                 panel.submit( this );
    1617             } );
    1618 
    1619             panel.filter_input.on( 'input keyup change', function( event ) {
    1620                 var first_visible_widget;
    1621 
    1622                 api.Widgets.availableWidgets.doSearch( event.target.value );
    1623 
    1624                 // Remove a widget from being selected if it is no longer visible
    1625                 if ( panel.selected_widget_tpl && ! panel.selected_widget_tpl.is( ':visible' ) ) {
    1626                     panel.selected_widget_tpl.removeClass( 'selected' );
    1627                     panel.selected_widget_tpl = null;
    1628                 }
    1629 
    1630                 // If a widget was selected but the filter value has been cleared out, clear selection
    1631                 if ( panel.selected_widget_tpl && ! event.target.value ) {
    1632                     panel.selected_widget_tpl.removeClass( 'selected' );
    1633                     panel.selected_widget_tpl = null;
    1634                 }
    1635 
    1636                 // If a filter has been entered and a widget hasn't been selected, select the first one shown
    1637                 if ( ! panel.selected_widget_tpl &&  event.target.value ) {
    1638                     first_visible_widget = panel.container.find( '> .widget-tpl:visible:first' );
    1639                     if ( first_visible_widget.length ) {
    1640                         panel.select( first_visible_widget );
    1641                     }
    1642                 }
    1643             } );
    1644 
    1645             // Select a widget when it is focused on
    1646             panel.container.find( ' > .widget-tpl' ).on( 'focus', function() {
    1647                 panel.select( this );
    1648             } );
    1649 
    1650             panel.container.on( 'keydown', function ( event ) {
    1651                 var is_enter = ( event.which === 13 ),
    1652                     is_esc = ( event.which === 27 ),
    1653                     is_down = ( event.which === 40 ),
    1654                     is_up = ( event.which === 38 ),
    1655                     selected_widget_tpl = null,
    1656                     first_visible_widget = panel.container.find( '> .widget-tpl:visible:first' ),
    1657                     last_visible_widget = panel.container.find( '> .widget-tpl:visible:last' ),
    1658                     is_input_focused = $( event.target ).is( panel.filter_input );
    1659 
    1660                 if ( is_down || is_up ) {
    1661                     if ( is_down ) {
    1662                         if ( is_input_focused ) {
    1663                             selected_widget_tpl = first_visible_widget;
    1664                         } else if ( panel.selected_widget_tpl && panel.selected_widget_tpl.nextAll( '.widget-tpl:visible' ).length !== 0 ) {
    1665                             selected_widget_tpl = panel.selected_widget_tpl.nextAll( '.widget-tpl:visible:first' );
    1666                         }
    1667                     } else if ( is_up ) {
    1668                         if ( is_input_focused ) {
    1669                             selected_widget_tpl = last_visible_widget;
    1670                         } else if ( panel.selected_widget_tpl && panel.selected_widget_tpl.prevAll( '.widget-tpl:visible' ).length !== 0 ) {
    1671                             selected_widget_tpl = panel.selected_widget_tpl.prevAll( '.widget-tpl:visible:first' );
    1672                         }
    1673                     }
    1674                     panel.select( selected_widget_tpl );
    1675                     if ( selected_widget_tpl ) {
    1676                         selected_widget_tpl.focus();
    1677                     } else {
    1678                         panel.filter_input.focus();
    1679                     }
    1680                     return;
    1681                 }
    1682 
    1683                 // If enter pressed but nothing entered, don't do anything
    1684                 if ( is_enter && ! panel.filter_input.val() ) {
    1685                     return;
    1686                 }
    1687 
    1688                 if ( is_enter ) {
    1689                     panel.submit();
    1690                 } else if ( is_esc ) {
    1691                     panel.close( { return_focus: true } );
    1692                 }
    1693             } );
    1694         },
    1695 
    1696         /**
    1697          * Updates widgets list.
    1698          */
    1699         update_available_widgets_list: function() {
    1700             var panel = api.Widgets.availableWidgetsPanel;
    1701 
    1702             // First hide all widgets...
    1703             panel.container.find( '.widget-tpl' ).hide();
    1704 
    1705             // ..and then show only available widgets which could be filtered
    1706             api.Widgets.availableWidgets.each( function ( widget ) {
    1707                 var widget_tpl = $( '#widget-tpl-' + widget.id );
    1708                 widget_tpl.toggle( ! widget.get( 'is_disabled' ) );
    1709                 if ( widget.get( 'is_disabled' ) && widget_tpl.is( panel.selected_widget_tpl ) ) {
    1710                     panel.selected_widget_tpl = null;
    1711                 }
    1712             } );
    1713         },
    1714 
    1715         /**
    1716          * @param widget_tpl
    1717          */
    1718         select: function ( widget_tpl ) {
    1719             var panel = this;
    1720             panel.selected_widget_tpl = $( widget_tpl );
    1721             panel.selected_widget_tpl.siblings( '.widget-tpl' ).removeClass( 'selected' );
    1722             panel.selected_widget_tpl.addClass( 'selected' );
    1723         },
    1724 
    1725         submit: function ( widget_tpl ) {
    1726             var panel = this, widget_id, widget;
    1727             if ( ! widget_tpl ) {
    1728                 widget_tpl = panel.selected_widget_tpl;
    1729             }
    1730             if ( ! widget_tpl || ! panel.active_sidebar_widgets_control ) {
    1731                 return;
    1732             }
    1733             panel.select( widget_tpl );
    1734 
    1735             widget_id = $( panel.selected_widget_tpl ).data( 'widget-id' );
    1736             widget = api.Widgets.availableWidgets.findWhere( {id: widget_id} );
    1737             if ( ! widget ) {
    1738                 throw new Error( 'Widget unexpectedly not found.' );
    1739             }
    1740             panel.active_sidebar_widgets_control.addWidget( widget.get( 'id_base' ) );
    1741             panel.close();
    1742         },
    1743 
    1744         /**
    1745          * @param sidebars_widgets_control
    1746          */
    1747         open: function ( sidebars_widgets_control ) {
    1748             var panel = this;
    1749             panel.active_sidebar_widgets_control = sidebars_widgets_control;
    1750 
    1751             // Wide widget controls appear over the preview, and so they need to be collapsed when the panel opens
    1752             _( sidebars_widgets_control.getWidgetFormControls() ).each( function ( control ) {
    1753                 if ( control.params.is_wide ) {
    1754                     control.collapseForm();
    1755                 }
    1756             } );
    1757 
    1758             $( 'body' ).addClass( 'adding-widget' );
    1759             panel.container.find( '.widget-tpl' ).removeClass( 'selected' );
    1760             api.Widgets.availableWidgets.doSearch( '' );
    1761             panel.filter_input.focus();
    1762         },
    1763 
    1764         /**
    1765          * Hide the panel
    1766          */
    1767         close: function ( options ) {
    1768             var panel = this;
    1769             options = options || {};
    1770             if ( options.return_focus && panel.active_sidebar_widgets_control ) {
    1771                 panel.active_sidebar_widgets_control.container.find( '.add-new-widget' ).focus();
    1772             }
    1773             panel.active_sidebar_widgets_control = null;
    1774             panel.selected_widget_tpl = null;
    1775             $( 'body' ).removeClass( 'adding-widget' );
    1776             panel.filter_input.val( '' );
    1777         }
    17781843    };
    17791844
Note: See TracChangeset for help on using the changeset viewer.