Make WordPress Core

Changeset 27986


Ignore:
Timestamp:
04/07/2014 02:09:53 PM (12 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.