<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[27986] trunk/src/wp-admin/js/customize-widgets.js: Widget Customizer: Make the available widgets panel a Backbone view.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/27986">27986</a></dd>
<dt>Author</dt> <dd>ocean90</dd>
<dt>Date</dt> <dd>2014-04-07 14:09:53 +0000 (Mon, 07 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Widget Customizer: Make the available widgets panel a Backbone view.

see <a href="http://core.trac.wordpress.org/ticket/27690">#27690</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminjscustomizewidgetsjs">trunk/src/wp-admin/js/customize-widgets.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminjscustomizewidgetsjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-admin/js/customize-widgets.js (27985 => 27986)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-admin/js/customize-widgets.js       2014-04-07 09:03:18 UTC (rev 27985)
+++ trunk/src/wp-admin/js/customize-widgets.js  2014-04-07 14:09:53 UTC (rev 27986)
</span><span class="lines">@@ -15,7 +15,12 @@
</span><span class="cx">  delete api.Widgets.data.l10n;
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * Set up model
</del><ins>+         * wp.customize.Widgets.WidgetModel
+        *
+        * A single widget model.
+        *
+        * @constructor
+        * @augments Backbone.Model
</ins><span class="cx">    */
</span><span class="cx">  api.Widgets.WidgetModel = Backbone.Model.extend({
</span><span class="cx">          id: null,
</span><span class="lines">@@ -34,6 +39,14 @@
</span><span class="cx">          height: null
</span><span class="cx">  });
</span><span class="cx"> 
</span><ins>+       /**
+        * wp.customize.Widgets.WidgetCollection
+        *
+        * Collection for widget models.
+        *
+        * @constructor
+        * @augments Backbone.Model
+        */
</ins><span class="cx">   api.Widgets.WidgetCollection = Backbone.Collection.extend({
</span><span class="cx">          model: api.Widgets.WidgetModel,
</span><span class="cx"> 
</span><span class="lines">@@ -92,6 +105,14 @@
</span><span class="cx">  });
</span><span class="cx">  api.Widgets.availableWidgets = new api.Widgets.WidgetCollection( api.Widgets.data.availableWidgets );
</span><span class="cx"> 
</span><ins>+       /**
+        * wp.customize.Widgets.SidebarModel
+        *
+        * A single sidebar model.
+        *
+        * @constructor
+        * @augments Backbone.Model
+        */
</ins><span class="cx">   api.Widgets.SidebarModel = Backbone.Model.extend({
</span><span class="cx">          after_title: null,
</span><span class="cx">          after_widget: null,
</span><span class="lines">@@ -104,12 +125,252 @@
</span><span class="cx">          is_rendered: false
</span><span class="cx">  });
</span><span class="cx"> 
</span><ins>+       /**
+        * wp.customize.Widgets.SidebarCollection
+        *
+        * Collection for sidebar models.
+        *
+        * @constructor
+        * @augments Backbone.Collection
+        */
</ins><span class="cx">   api.Widgets.SidebarCollection = Backbone.Collection.extend({
</span><span class="cx">          model: api.Widgets.SidebarModel
</span><span class="cx">  });
</span><span class="cx">  api.Widgets.registeredSidebars = new api.Widgets.SidebarCollection( api.Widgets.data.registeredSidebars );
</span><span class="cx"> 
</span><span class="cx">  /**
</span><ins>+        * wp.customize.Widgets.AvailableWidgetsPanelView
+        *
+        * View class for the available widgets panel.
+        *
+        * @constructor
+        * @augments wp.Backbone.View
+        * @augments Backbone.View
+        */
+       api.Widgets.AvailableWidgetsPanelView = wp.Backbone.View.extend({
+
+               el: '#available-widgets',
+
+               events: {
+                       'input #widgets-search': 'search',
+                       'keyup #widgets-search': 'search',
+                       'change #widgets-search': 'search',
+                       'search #widgets-search': 'search',
+                       'focus .widget-tpl' : 'focus',
+                       'click .widget-tpl' : '_submit',
+                       'keypress .widget-tpl' : '_submit',
+                       'keydown' : 'keyboardAccessible'
+               },
+
+               // Cache current selected widget
+               selected: null,
+
+               // Cache sidebar control which has opened panel
+               currentSidebarControl: null,
+               $search: null,
+
+               initialize: function() {
+                       var self = this;
+
+                       this.$search = $( '#widgets-search' );
+
+                       _.bindAll( this, 'close' );
+
+                       this.listenTo( this.collection, 'update', this.updateList );
+
+                       this.updateList();
+
+                       // If the available widgets panel is open and the customize controls are
+                       // interacted with (i.e. available widgets panel is blurred) then close the
+                       // available widgets panel.
+                       $( '#customize-controls' ).on( 'click keydown', function( e ) {
+                               var isAddNewBtn = $( e.target ).is( '.add-new-widget, .add-new-widget *' );
+                               if ( $( 'body' ).hasClass( 'adding-widget' ) && ! isAddNewBtn ) {
+                                       self.close();
+                               }
+                       } );
+
+                       // Close the panel if the URL in the preview changes
+                       api.Widgets.Previewer.bind( 'url', this.close );
+               },
+
+               // Performs a search and handles selected widget
+               search: function( event ) {
+                       var firstVisible;
+
+                       this.collection.doSearch( event.target.value );
+
+                       // Remove a widget from being selected if it is no longer visible
+                       if ( this.selected && ! this.selected.is( ':visible' ) ) {
+                               this.selected.removeClass( 'selected' );
+                               this.selected = null;
+                       }
+
+                       // If a widget was selected but the filter value has been cleared out, clear selection
+                       if ( this.selected && ! event.target.value ) {
+                               this.selected.removeClass( 'selected' );
+                               this.selected = null;
+                       }
+
+                       // If a filter has been entered and a widget hasn't been selected, select the first one shown
+                       if ( ! this.selected && event.target.value ) {
+                               firstVisible = this.$el.find( '> .widget-tpl:visible:first' );
+                               if ( firstVisible.length ) {
+                                       this.select( firstVisible );
+                               }
+                       }
+               },
+
+               // Changes visibilty of available widgets
+               updateList: function() {
+                       // First hide all widgets...
+                       this.$el.find( '.widget-tpl' ).hide();
+
+                       // ..and then show only available widgets which could be filtered
+                       this.collection.each( function( widget ) {
+                               var widgetTpl = $( '#widget-tpl-' + widget.id );
+                               widgetTpl.toggle( ! widget.get( 'is_disabled' ) );
+                               if ( widget.get( 'is_disabled' ) && widgetTpl.is( this.selected ) ) {
+                                       this.selected = null;
+                               }
+                       } );
+               },
+
+               // Hightlights a widget
+               select: function( widgetTpl ) {
+                       this.selected = $( widgetTpl );
+                       this.selected.siblings( '.widget-tpl' ).removeClass( 'selected' );
+                       this.selected.addClass( 'selected' );
+               },
+
+               // Hightlights a widget on focus
+               focus: function( event ) {
+                       this.select( $( event.currentTarget ) );
+               },
+
+               // Submit handler for keypress and click on widget
+               _submit: function( event ) {
+                       // Only proceed with keypress if it is Enter or Spacebar
+                       if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
+                               return;
+                       }
+
+                       this.submit( $( event.currentTarget ) );
+               },
+
+               // Adds a selected widget to the sidebar
+               submit: function( widgetTpl ) {
+                       var widgetId, widget;
+
+                       if ( ! widgetTpl ) {
+                               widgetTpl = this.selected;
+                       }
+
+                       if ( ! widgetTpl || ! this.currentSidebarControl ) {
+                               return;
+                       }
+
+                       this.select( widgetTpl );
+
+                       widgetId = $( this.selected ).data( 'widget-id' );
+                       widget = this.collection.findWhere( { id: widgetId } );
+                       if ( ! widget ) {
+                               return;
+                       }
+
+                       this.currentSidebarControl.addWidget( widget.get( 'id_base' ) );
+
+                       this.close();
+               },
+
+               // Opens the panel
+               open: function( sidebarControl ) {
+                       this.currentSidebarControl = sidebarControl;
+
+                       // Wide widget controls appear over the preview, and so they need to be collapsed when the panel opens
+                       _( this.currentSidebarControl.getWidgetFormControls() ).each( function( control ) {
+                               if ( control.params.is_wide ) {
+                                       control.collapseForm();
+                               }
+                       } );
+
+                       $( 'body' ).addClass( 'adding-widget' );
+
+                       this.$el.find( '.selected' ).removeClass( 'selected' );
+
+                       // Reset search
+                       this.collection.doSearch( '' );
+
+                       this.$search.focus();
+               },
+
+               // Closes the panel
+               close: function( options ) {
+                       options = options || {};
+
+                       if ( options.returnFocus && this.currentSidebarControl ) {
+                               this.currentSidebarControl.container.find( '.add-new-widget' ).focus();
+                       }
+
+                       this.currentSidebarControl = null;
+                       this.selected = null;
+
+                       $( 'body' ).removeClass( 'adding-widget' );
+
+                       this.$search.val( '' );
+               },
+
+               // Add keyboard accessiblity to the panel
+               keyboardAccessible: function( event ) {
+                       var isEnter = ( event.which === 13 ),
+                               isEsc = ( event.which === 27 ),
+                               isDown = ( event.which === 40 ),
+                               isUp = ( event.which === 38 ),
+                               selected = null,
+                               firstVisible = this.$el.find( '> .widget-tpl:visible:first' ),
+                               lastVisible = this.$el.find( '> .widget-tpl:visible:last' ),
+                               isSearchFocused = $( event.target ).is( this.$search );
+
+                       if ( isDown || isUp ) {
+                               if ( isDown ) {
+                                       if ( isSearchFocused ) {
+                                               selected = firstVisible;
+                                       } else if ( this.selected && this.selected.nextAll( '.widget-tpl:visible' ).length !== 0 ) {
+                                               selected = this.selected.nextAll( '.widget-tpl:visible:first' );
+                                       }
+                               } else if ( isUp ) {
+                                       if ( isSearchFocused ) {
+                                               selected = lastVisible;
+                                       } else if ( this.selected && this.selected.prevAll( '.widget-tpl:visible' ).length !== 0 ) {
+                                               selected = this.selected.prevAll( '.widget-tpl:visible:first' );
+                                       }
+                               }
+
+                               this.select( selected );
+
+                               if ( selected ) {
+                                       selected.focus();
+                               } else {
+                                       this.$search.focus();
+                               }
+
+                               return;
+                       }
+
+                       // If enter pressed but nothing entered, don't do anything
+                       if ( isEnter && ! this.$search.val() ) {
+                               return;
+                       }
+
+                       if ( isEnter ) {
+                               this.submit();
+                       } else if ( isEsc ) {
+                               this.close( { returnFocus: true } );
+                       }
+               }
+       });
+
+       /**
</ins><span class="cx">    * Handlers for the widget-synced event, organized by widget ID base.
</span><span class="cx">   * Other widgets may provide their own update handlers by adding
</span><span class="cx">   * listeners for the widget-synced event.
</span><span class="lines">@@ -121,7 +382,7 @@
</span><span class="cx">           * @param {jQuery} widget
</span><span class="cx">           * @param {String} newForm
</span><span class="cx">           */
</span><del>-               rss: function ( e, widget, newForm ) {
</del><ins>+                rss: function( e, widget, newForm ) {
</ins><span class="cx">                   var oldWidgetError = widget.find( '.widget-error:first' ),
</span><span class="cx">                          newWidgetError = $( '<div>' + newForm + '</div>' ).find( '.widget-error:first' );
</span><span class="cx"> 
</span><span class="lines">@@ -136,8 +397,13 @@
</span><span class="cx">  };
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * Widget Form control
</del><ins>+         * wp.customize.Widgets.WidgetControl
+        *
+        * Customizer control for widgets.
</ins><span class="cx">    * Note that 'widget_form' must match the WP_Widget_Form_Customize_Control::$type
</span><ins>+        *
+        * @constructor
+        * @augments wp.customize.Control
</ins><span class="cx">    */
</span><span class="cx">  api.Widgets.WidgetControl = api.Control.extend({
</span><span class="cx">          /**
</span><span class="lines">@@ -246,7 +512,7 @@
</span><span class="cx">                  } );
</span><span class="cx"> 
</span><span class="cx">                  // Reposition whenever a sidebar's widgets are changed
</span><del>-                       api.each( function ( setting ) {
</del><ins>+                        api.each( function( setting ) {
</ins><span class="cx">                           if ( 0 === setting.id.indexOf( 'sidebars_widgets[' ) ) {
</span><span class="cx">                                  setting.bind( function() {
</span><span class="cx">                                          if ( control.container.hasClass( 'expanded' ) ) {
</span><span class="lines">@@ -264,7 +530,7 @@
</span><span class="cx">          _setupControlToggle: function() {
</span><span class="cx">                  var control = this, close_btn;
</span><span class="cx"> 
</span><del>-                       control.container.find( '.widget-top' ).on( 'click', function ( e ) {
</del><ins>+                        control.container.find( '.widget-top' ).on( 'click', function( e ) {
</ins><span class="cx">                           e.preventDefault();
</span><span class="cx">                          var sidebar_widgets_control = control.getSidebarWidgetsControl();
</span><span class="cx">                          if ( sidebar_widgets_control.is_reordering ) {
</span><span class="lines">@@ -275,7 +541,7 @@
</span><span class="cx"> 
</span><span class="cx">                  close_btn = control.container.find( '.widget-control-close' );
</span><span class="cx">                  // @todo Hitting Enter on this link does nothing; will be resolved in core with <http://core.trac.wordpress.org/ticket/26633>
</span><del>-                       close_btn.on( 'click', function ( e ) {
</del><ins>+                        close_btn.on( 'click', function( e ) {
</ins><span class="cx">                           e.preventDefault();
</span><span class="cx">                          control.collapseForm();
</span><span class="cx">                          control.container.find( '.widget-top .widget-action:first' ).focus(); // keyboard accessibility
</span><span class="lines">@@ -317,7 +583,7 @@
</span><span class="cx">                   *
</span><span class="cx">                   * @param {jQuery} li
</span><span class="cx">                   */
</span><del>-                       select_sidebar_item = function ( li ) {
</del><ins>+                        select_sidebar_item = function( li ) {
</ins><span class="cx">                           li.siblings( '.selected' ).removeClass( 'selected' );
</span><span class="cx">                          li.addClass( 'selected' );
</span><span class="cx">                          var is_self_sidebar = ( li.data( 'id' ) === control.params.sidebar_id );
</span><span class="lines">@@ -363,7 +629,7 @@
</span><span class="cx">                   * Handle clicks for up/down/move on the reorder nav
</span><span class="cx">                   */
</span><span class="cx">                  reorder_nav = control.container.find( '.widget-reorder-nav' );
</span><del>-                       reorder_nav.find( '.move-widget, .move-widget-down, .move-widget-up' ).on( 'click keypress', function ( event ) {
</del><ins>+                        reorder_nav.find( '.move-widget, .move-widget-down, .move-widget-up' ).on( 'click keypress', function( event ) {
</ins><span class="cx">                           if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
</span><span class="cx">                                  return;
</span><span class="cx">                          }
</span><span class="lines">@@ -393,7 +659,7 @@
</span><span class="cx">                  /**
</span><span class="cx">                   * Handle selecting a sidebar to move to
</span><span class="cx">                   */
</span><del>-                       control.container.find( '.widget-area-select' ).on( 'click keypress', 'li', function ( e ) {
</del><ins>+                        control.container.find( '.widget-area-select' ).on( 'click keypress', 'li', function( e ) {
</ins><span class="cx">                           if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
</span><span class="cx">                                  return;
</span><span class="cx">                          }
</span><span class="lines">@@ -472,7 +738,7 @@
</span><span class="cx">                  save_btn.val( l10n.saveBtnLabel );
</span><span class="cx">                  save_btn.attr( 'title', l10n.saveBtnTooltip );
</span><span class="cx">                  save_btn.removeClass( 'button-primary' ).addClass( 'button-secondary' );
</span><del>-                       save_btn.on( 'click', function ( e ) {
</del><ins>+                        save_btn.on( 'click', function( e ) {
</ins><span class="cx">                           e.preventDefault();
</span><span class="cx">                          control.updateWidget( { disable_form: true } );
</span><span class="cx">                  } );
</span><span class="lines">@@ -491,7 +757,7 @@
</span><span class="cx">                  } );
</span><span class="cx"> 
</span><span class="cx">                  // Handle widgets that support live previews
</span><del>-                       widget_content.on( 'change input propertychange', ':input', function ( e ) {
</del><ins>+                        widget_content.on( 'change input propertychange', ':input', function( e ) {
</ins><span class="cx">                           if ( control.live_update_mode ) {
</span><span class="cx">                                  if ( e.type === 'change' ) {
</span><span class="cx">                                          control.updateWidget();
</span><span class="lines">@@ -505,21 +771,21 @@
</span><span class="cx">                  control.setting.previewer.channel.bind( 'synced', function() {
</span><span class="cx">                          control.container.removeClass( 'previewer-loading' );
</span><span class="cx">                  } );
</span><del>-                       api.Widgets.Previewer.bind( 'widget-updated', function ( updated_widget_id ) {
</del><ins>+                        api.Widgets.Previewer.bind( 'widget-updated', function( updated_widget_id ) {
</ins><span class="cx">                           if ( updated_widget_id === control.params.widget_id ) {
</span><span class="cx">                                  control.container.removeClass( 'previewer-loading' );
</span><span class="cx">                          }
</span><span class="cx">                  } );
</span><span class="cx"> 
</span><span class="cx">                  // Update widget control to indicate whether it is currently rendered (cf. Widget Visibility)
</span><del>-                       api.Widgets.Previewer.bind( 'rendered-widgets', function ( rendered_widgets ) {
</del><ins>+                        api.Widgets.Previewer.bind( 'rendered-widgets', function( rendered_widgets ) {
</ins><span class="cx">                           var is_rendered = !! rendered_widgets[control.params.widget_id];
</span><span class="cx">                          control.container.toggleClass( 'widget-rendered', is_rendered );
</span><span class="cx">                  } );
</span><span class="cx"> 
</span><span class="cx">                  form_update_event_handler = api.Widgets.formSyncHandlers[ control.params.widget_id_base ];
</span><span class="cx">                  if ( form_update_event_handler ) {
</span><del>-                               $( document ).on( 'widget-synced', function ( e, widget_el ) {
</del><ins>+                                $( document ).on( 'widget-synced', function( e, widget_el ) {
</ins><span class="cx">                                   if ( widget_root.is( widget_el ) ) {
</span><span class="cx">                                          form_update_event_handler.apply( document, arguments );
</span><span class="cx">                                  }
</span><span class="lines">@@ -538,7 +804,7 @@
</span><span class="cx">                  // Configure remove button
</span><span class="cx">                  remove_btn = control.container.find( 'a.widget-control-remove' );
</span><span class="cx">                  // @todo Hitting Enter on this link does nothing; will be resolved in core with <http://core.trac.wordpress.org/ticket/26633>
</span><del>-                       remove_btn.on( 'click', function ( e ) {
</del><ins>+                        remove_btn.on( 'click', function( e ) {
</ins><span class="cx">                           e.preventDefault();
</span><span class="cx"> 
</span><span class="cx">                          // Find an adjacent element to add focus to when this widget goes away
</span><span class="lines">@@ -592,7 +858,7 @@
</span><span class="cx">           * @returns {jQuery} inputs
</span><span class="cx">           * @private
</span><span class="cx">           */
</span><del>-               _getInputs: function ( container ) {
</del><ins>+                _getInputs: function( container ) {
</ins><span class="cx">                   return $( container ).find( ':input[name]' );
</span><span class="cx">          },
</span><span class="cx"> 
</span><span class="lines">@@ -604,8 +870,8 @@
</span><span class="cx">           * @returns {string}
</span><span class="cx">           * @private
</span><span class="cx">           */
</span><del>-               _getInputsSignature: function ( inputs ) {
-                       var inputs_signatures = _( inputs ).map( function ( input ) {
</del><ins>+                _getInputsSignature: function( inputs ) {
+                       var inputs_signatures = _( inputs ).map( function( input ) {
</ins><span class="cx">                           input = $( input );
</span><span class="cx">                          var signature_parts;
</span><span class="cx">                          if ( input.is( ':checkbox, :radio' ) ) {
</span><span class="lines">@@ -625,7 +891,7 @@
</span><span class="cx">           * @returns {string}
</span><span class="cx">           * @private
</span><span class="cx">           */
</span><del>-               _getInputStatePropertyName: function ( input ) {
</del><ins>+                _getInputStatePropertyName: function( input ) {
</ins><span class="cx">                   input = $( input );
</span><span class="cx">                  if ( input.is( ':radio, :checkbox' ) ) {
</span><span class="cx">                          return 'checked';
</span><span class="lines">@@ -661,7 +927,7 @@
</span><span class="cx">           * @param {Function|null} [args.complete=null]  Function which is called when the request finishes. Context is bound to the control. First argument is any error. Following arguments are for success.
</span><span class="cx">           * @param {Boolean} [args.ignore_active_element=false] Whether or not updating a field will be deferred if focus is still on the element.
</span><span class="cx">           */
</span><del>-               updateWidget: function ( args ) {
</del><ins>+                updateWidget: function( args ) {
</ins><span class="cx">                   var control = this,
</span><span class="cx">                          instance_override,
</span><span class="cx">                          complete_callback,
</span><span class="lines">@@ -726,7 +992,7 @@
</span><span class="cx">                  }
</span><span class="cx">                  data += '&' + widget_content.find( '~ :input' ).serialize();
</span><span class="cx"> 
</span><del>-                       jqxhr = $.post( wp.ajax.settings.url, data, function ( r ) {
</del><ins>+                        jqxhr = $.post( wp.ajax.settings.url, data, function( r ) {
</ins><span class="cx">                           var message,
</span><span class="cx">                                  sanitized_form,
</span><span class="cx">                                  sanitized_inputs,
</span><span class="lines">@@ -763,7 +1029,7 @@
</span><span class="cx"> 
</span><span class="cx">                                  // Sync sanitized field states to existing fields if they are aligned
</span><span class="cx">                                  if ( has_same_inputs_in_response && control.live_update_mode ) {
</span><del>-                                               inputs.each( function ( i ) {
</del><ins>+                                                inputs.each( function( i ) {
</ins><span class="cx">                                                   var input = $( this ),
</span><span class="cx">                                                          sanitized_input = $( sanitized_inputs[i] ),
</span><span class="cx">                                                          property = control._getInputStatePropertyName( this ),
</span><span class="lines">@@ -827,7 +1093,7 @@
</span><span class="cx">                                  }
</span><span class="cx">                          }
</span><span class="cx">                  } );
</span><del>-                       jqxhr.fail( function ( jqXHR, textStatus ) {
</del><ins>+                        jqxhr.fail( function( jqXHR, textStatus ) {
</ins><span class="cx">                           if ( complete_callback ) {
</span><span class="cx">                                  complete_callback.call( control, textStatus );
</span><span class="cx">                          }
</span><span class="lines">@@ -872,7 +1138,7 @@
</span><span class="cx">           *
</span><span class="cx">           * @param {boolean|undefined} [do_expand] If not supplied, will be inverse of current visibility
</span><span class="cx">           */
</span><del>-               toggleForm: function ( do_expand ) {
</del><ins>+                toggleForm: function( do_expand ) {
</ins><span class="cx">                   var control = this, widget, inside, complete;
</span><span class="cx"> 
</span><span class="cx">                  widget = control.container.find( 'div.widget:first' );
</span><span class="lines">@@ -888,7 +1154,7 @@
</span><span class="cx"> 
</span><span class="cx">                  if ( do_expand ) {
</span><span class="cx">                          // Close all other widget controls before expanding this one
</span><del>-                               api.control.each( function ( other_control ) {
</del><ins>+                                api.control.each( function( other_control ) {
</ins><span class="cx">                                   if ( control.params.type === other_control.params.type && control !== other_control ) {
</span><span class="cx">                                          other_control.collapseForm();
</span><span class="cx">                                  }
</span><span class="lines">@@ -974,7 +1240,7 @@
</span><span class="cx">           *
</span><span class="cx">           * @param {Number} offset 1|-1
</span><span class="cx">           */
</span><del>-               _moveWidgetByOne: function ( offset ) {
</del><ins>+                _moveWidgetByOne: function( offset ) {
</ins><span class="cx">                   var control = this,
</span><span class="cx">                          i,
</span><span class="cx">                          sidebar_widgets_setting,
</span><span class="lines">@@ -997,7 +1263,7 @@
</span><span class="cx">           *
</span><span class="cx">           * @param {Boolean} [toggle]
</span><span class="cx">           */
</span><del>-               toggleWidgetMoveArea: function ( toggle ) {
</del><ins>+                toggleWidgetMoveArea: function( toggle ) {
</ins><span class="cx">                   var control = this, move_widget_area;
</span><span class="cx">                  move_widget_area = control.container.find( '.move-widget-area' );
</span><span class="cx">                  if ( typeof toggle === 'undefined' ) {
</span><span class="lines">@@ -1043,8 +1309,13 @@
</span><span class="cx">  } );
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * Sidebar Widgets control
</del><ins>+         * wp.customize.Widgets.SidebarControl
+        *
+        * Customizer control for widgets.
</ins><span class="cx">    * Note that 'sidebar_widgets' must match the WP_Widget_Area_Customize_Control::$type
</span><ins>+        *
+        * @constructor
+        * @augments wp.customize.Control
</ins><span class="cx">    */
</span><span class="cx">  api.Widgets.SidebarControl = api.Control.extend({
</span><span class="cx">          /**
</span><span class="lines">@@ -1074,12 +1345,12 @@
</span><span class="cx">                                  removed_widget_ids = _( old_widget_ids ).difference( new_widget_ids );
</span><span class="cx"> 
</span><span class="cx">                          // Filter out any persistent widget_ids for widgets which have been deactivated
</span><del>-                               new_widget_ids = _( new_widget_ids ).filter( function ( new_widget_id ) {
</del><ins>+                                new_widget_ids = _( new_widget_ids ).filter( function( new_widget_id ) {
</ins><span class="cx">                                   var parsed_widget_id = parse_widget_id( new_widget_id );
</span><span class="cx">                                  return !! api.Widgets.availableWidgets.findWhere( { id_base: parsed_widget_id.id_base } );
</span><span class="cx">                          } );
</span><span class="cx"> 
</span><del>-                               widget_form_controls = _( new_widget_ids ).map( function ( widget_id ) {
</del><ins>+                                widget_form_controls = _( new_widget_ids ).map( function( widget_id ) {
</ins><span class="cx">                                   var widget_form_control = api.Widgets.getWidgetFormControlForWidget( widget_id );
</span><span class="cx">                                  if ( ! widget_form_control ) {
</span><span class="cx">                                          widget_form_control = control.addWidget( widget_id );
</span><span class="lines">@@ -1088,7 +1359,7 @@
</span><span class="cx">                          } );
</span><span class="cx"> 
</span><span class="cx">                          // Sort widget controls to their new positions
</span><del>-                               widget_form_controls.sort( function ( a, b ) {
</del><ins>+                                widget_form_controls.sort( function( a, b ) {
</ins><span class="cx">                                   var a_index = _.indexOf( new_widget_ids, a.params.widget_id ),
</span><span class="cx">                                          b_index = _.indexOf( new_widget_ids, b.params.widget_id );
</span><span class="cx">                                  if ( a_index === b_index ) {
</span><span class="lines">@@ -1109,12 +1380,12 @@
</span><span class="cx">                          control._applyCardinalOrderClassNames();
</span><span class="cx"> 
</span><span class="cx">                          // If the widget was dragged into the sidebar, make sure the sidebar_id param is updated
</span><del>-                               _( widget_form_controls ).each( function ( widget_form_control ) {
</del><ins>+                                _( widget_form_controls ).each( function( widget_form_control ) {
</ins><span class="cx">                                   widget_form_control.params.sidebar_id = control.params.sidebar_id;
</span><span class="cx">                          } );
</span><span class="cx"> 
</span><span class="cx">                          // Cleanup after widget removal
</span><del>-                               _( removed_widget_ids ).each( function ( removed_widget_id ) {
</del><ins>+                                _( removed_widget_ids ).each( function( removed_widget_id ) {
</ins><span class="cx"> 
</span><span class="cx">                                  // Using setTimeout so that when moving a widget to another sidebar, the other sidebars_widgets settings get a chance to update
</span><span class="cx">                                  setTimeout( function() {
</span><span class="lines">@@ -1126,7 +1397,7 @@
</span><span class="cx">                                                  widget;
</span><span class="cx"> 
</span><span class="cx">                                          // Check if the widget is in another sidebar
</span><del>-                                               api.each( function ( other_setting ) {
</del><ins>+                                                api.each( function( other_setting ) {
</ins><span class="cx">                                                   if ( other_setting.id === control.setting.id || 0 !== other_setting.id.indexOf( 'sidebars_widgets[' ) || other_setting.id === 'sidebars_widgets[wp_inactive_widgets]' ) {
</span><span class="cx">                                                          return;
</span><span class="cx">                                                  }
</span><span class="lines">@@ -1178,13 +1449,13 @@
</span><span class="cx">                  } );
</span><span class="cx"> 
</span><span class="cx">                  // Update the model with whether or not the sidebar is rendered
</span><del>-                       api.Widgets.Previewer.bind( 'rendered-sidebars', function ( rendered_sidebars ) {
</del><ins>+                        api.Widgets.Previewer.bind( 'rendered-sidebars', function( rendered_sidebars ) {
</ins><span class="cx">                           var is_rendered = !! rendered_sidebars[control.params.sidebar_id];
</span><span class="cx">                          registered_sidebar.set( 'is_rendered', is_rendered );
</span><span class="cx">                  } );
</span><span class="cx"> 
</span><span class="cx">                  // Show the sidebar section when it becomes visible
</span><del>-                       registered_sidebar.on( 'change:is_rendered', function ( ) {
</del><ins>+                        registered_sidebar.on( 'change:is_rendered', function( ) {
</ins><span class="cx">                           var section_selector = '#accordion-section-sidebar-widgets-' + this.get( 'id' ), section;
</span><span class="cx">                          section = $( section_selector );
</span><span class="cx">                          if ( this.get( 'is_rendered' ) ) {
</span><span class="lines">@@ -1219,7 +1490,7 @@
</span><span class="cx">                          connectWith: '.accordion-section-content:has(.customize-control-sidebar_widgets)',
</span><span class="cx">                          update: function() {
</span><span class="cx">                                  var widget_container_ids = control.section_content.sortable( 'toArray' ), widget_ids;
</span><del>-                                       widget_ids = $.map( widget_container_ids, function ( widget_container_id ) {
</del><ins>+                                        widget_ids = $.map( widget_container_ids, function( widget_container_id ) {
</ins><span class="cx">                                           return $( '#' + widget_container_id ).find( ':input[name=widget-id]' ).val();
</span><span class="cx">                                  } );
</span><span class="cx">                                  control.setting( widget_ids );
</span><span class="lines">@@ -1306,7 +1577,7 @@
</span><span class="cx">           *
</span><span class="cx">           * @param {Boolean} toggle to enable/disable reordering
</span><span class="cx">           */
</span><del>-               toggleReordering: function ( toggle ) {
</del><ins>+                toggleReordering: function( toggle ) {
</ins><span class="cx">                   var control = this;
</span><span class="cx">                  toggle = Boolean( toggle );
</span><span class="cx">                  if ( toggle === control.section_content.hasClass( 'reordering' ) ) {
</span><span class="lines">@@ -1317,7 +1588,7 @@
</span><span class="cx">                  control.section_content.toggleClass( 'reordering', toggle );
</span><span class="cx"> 
</span><span class="cx">                  if ( toggle ) {
</span><del>-                               _( control.getWidgetFormControls() ).each( function ( form_control ) {
</del><ins>+                                _( control.getWidgetFormControls() ).each( function( form_control ) {
</ins><span class="cx">                                   form_control.collapseForm();
</span><span class="cx">                          } );
</span><span class="cx">                  }
</span><span class="lines">@@ -1329,7 +1600,7 @@
</span><span class="cx">          getWidgetFormControls: function() {
</span><span class="cx">                  var control = this, form_controls;
</span><span class="cx"> 
</span><del>-                       form_controls = _( control.setting() ).map( function ( widget_id ) {
</del><ins>+                        form_controls = _( control.setting() ).map( function( widget_id ) {
</ins><span class="cx">                           var setting_id = widget_id_to_setting_id( widget_id ),
</span><span class="cx">                                  form_control = api.control( setting_id );
</span><span class="cx"> 
</span><span class="lines">@@ -1345,7 +1616,7 @@
</span><span class="cx">           * @param {string} widget_id or an id_base for adding a previously non-existing widget
</span><span class="cx">           * @returns {object} widget_form control instance
</span><span class="cx">           */
</span><del>-               addWidget: function ( widget_id ) {
</del><ins>+                addWidget: function( widget_id ) {
</ins><span class="cx">                   var control = this,
</span><span class="cx">                          control_html,
</span><span class="cx">                          widget_el,
</span><span class="lines">@@ -1377,7 +1648,7 @@
</span><span class="cx"> 
</span><span class="cx">                  control_html = $( '#widget-tpl-' + widget.get( 'id' ) ).html();
</span><span class="cx">                  if ( widget.get( 'is_multi' ) ) {
</span><del>-                               control_html = control_html.replace( /<[^<>]+>/g, function ( m ) {
</del><ins>+                                control_html = control_html.replace( /<[^<>]+>/g, function( m ) {
</ins><span class="cx">                                   return m.replace( /__i__|%i%/g, widget_number );
</span><span class="cx">                          } );
</span><span class="cx">                  } else {
</span><span class="lines">@@ -1435,7 +1706,7 @@
</span><span class="cx">                  api.control.add( setting_id, widget_form_control );
</span><span class="cx"> 
</span><span class="cx">                  // Make sure widget is removed from the other sidebars
</span><del>-                       api.each( function ( other_setting ) {
</del><ins>+                        api.each( function( other_setting ) {
</ins><span class="cx">                           if ( other_setting.id === control.setting.id ) {
</span><span class="cx">                                  return;
</span><span class="cx">                          }
</span><span class="lines">@@ -1462,7 +1733,7 @@
</span><span class="cx">                                  widget_form_control.expandForm();
</span><span class="cx">                                  widget_form_control.updateWidget( {
</span><span class="cx">                                          instance: widget_form_control.setting(),
</span><del>-                                               complete: function ( error ) {
</del><ins>+                                                complete: function( error ) {
</ins><span class="cx">                                                   if ( error ) {
</span><span class="cx">                                                          throw error;
</span><span class="cx">                                                  }
</span><span class="lines">@@ -1488,7 +1759,9 @@
</span><span class="cx"> 
</span><span class="cx">  api.bind( 'ready', function() {
</span><span class="cx">          // Set up the widgets panel
</span><del>-               api.Widgets.availableWidgetsPanel.setup();
</del><ins>+                api.Widgets.availableWidgetsPanel = new api.Widgets.AvailableWidgetsPanelView({
+                       collection: api.Widgets.availableWidgets
+               });
</ins><span class="cx"> 
</span><span class="cx">          // Highlight widget control
</span><span class="cx">          api.Widgets.Previewer.bind( 'highlight-widget-control', api.Widgets.highlightWidgetFormControl );
</span><span class="lines">@@ -1540,10 +1813,10 @@
</span><span class="cx">   * @param {string} widget_id
</span><span class="cx">   * @return {object|null}
</span><span class="cx">   */
</span><del>-       api.Widgets.getSidebarWidgetControlContainingWidget = function ( widget_id ) {
</del><ins>+        api.Widgets.getSidebarWidgetControlContainingWidget = function( widget_id ) {
</ins><span class="cx">           var found_control = null;
</span><span class="cx">          // @todo this can use widget_id_to_setting_id(), then pass into wp.customize.control( x ).getSidebarWidgetsControl()
</span><del>-               api.control.each( function ( control ) {
</del><ins>+                api.control.each( function( control ) {
</ins><span class="cx">                   if ( control.params.type === 'sidebar_widgets' && -1 !== _.indexOf( control.setting(), widget_id ) ) {
</span><span class="cx">                          found_control = control;
</span><span class="cx">                  }
</span><span class="lines">@@ -1557,10 +1830,10 @@
</span><span class="cx">   * @param {string} widget_id
</span><span class="cx">   * @return {object|null}
</span><span class="cx">   */
</span><del>-       api.Widgets.getWidgetFormControlForWidget = function ( widget_id ) {
</del><ins>+        api.Widgets.getWidgetFormControlForWidget = function( widget_id ) {
</ins><span class="cx">           var found_control = null;
</span><span class="cx">          // @todo We can just use widget_id_to_setting_id() here
</span><del>-               api.control.each( function ( control ) {
</del><ins>+                api.control.each( function( control ) {
</ins><span class="cx">                   if ( control.params.type === 'widget_form' && control.params.widget_id === widget_id ) {
</span><span class="cx">                          found_control = control;
</span><span class="cx">                  }
</span><span class="lines">@@ -1570,214 +1843,6 @@
</span><span class="cx">  };
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * Available Widgets Panel
-        */
-       api.Widgets.availableWidgetsPanel = {
-               active_sidebar_widgets_control: null,
-               selected_widget_tpl: null,
-               container: null,
-               filter_input: null,
-
-               /**
-                * Set up event listeners
-                */
-               setup: function() {
-                       var panel = this;
-
-                       panel.container = $( '#available-widgets' );
-                       panel.filter_input = $( '#available-widgets-filter' ).find( 'input' );
-
-                       api.Widgets.availableWidgets.on( 'change update', panel.update_available_widgets_list );
-                       panel.update_available_widgets_list();
-
-                       // If the available widgets panel is open and the customize controls are
-                       // interacted with (i.e. available widgets panel is blurred) then close the
-                       // available widgets panel.
-                       $( '#customize-controls' ).on( 'click keydown', function ( e ) {
-                               var is_add_new_widget_btn = $( e.target ).is( '.add-new-widget, .add-new-widget *' );
-                               if ( $( 'body' ).hasClass( 'adding-widget' ) && ! is_add_new_widget_btn ) {
-                                       panel.close();
-                               }
-                       } );
-
-                       // Close the panel if the URL in the preview changes
-                       api.Widgets.Previewer.bind( 'url', function() {
-                               panel.close();
-                       } );
-
-                       // Submit a selection when clicked or keypressed
-                       panel.container.find( '.widget-tpl' ).on( 'click keypress', function( event ) {
-
-                               // Only proceed with keypress if it is Enter or Spacebar
-                               if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) {
-                                       return;
-                               }
-
-                               panel.submit( this );
-                       } );
-
-                       panel.filter_input.on( 'input keyup change', function( event ) {
-                               var first_visible_widget;
-
-                               api.Widgets.availableWidgets.doSearch( event.target.value );
-
-                               // Remove a widget from being selected if it is no longer visible
-                               if ( panel.selected_widget_tpl && ! panel.selected_widget_tpl.is( ':visible' ) ) {
-                                       panel.selected_widget_tpl.removeClass( 'selected' );
-                                       panel.selected_widget_tpl = null;
-                               }
-
-                               // If a widget was selected but the filter value has been cleared out, clear selection
-                               if ( panel.selected_widget_tpl && ! event.target.value ) {
-                                       panel.selected_widget_tpl.removeClass( 'selected' );
-                                       panel.selected_widget_tpl = null;
-                               }
-
-                               // If a filter has been entered and a widget hasn't been selected, select the first one shown
-                               if ( ! panel.selected_widget_tpl &&  event.target.value ) {
-                                       first_visible_widget = panel.container.find( '> .widget-tpl:visible:first' );
-                                       if ( first_visible_widget.length ) {
-                                               panel.select( first_visible_widget );
-                                       }
-                               }
-                       } );
-
-                       // Select a widget when it is focused on
-                       panel.container.find( ' > .widget-tpl' ).on( 'focus', function() {
-                               panel.select( this );
-                       } );
-
-                       panel.container.on( 'keydown', function ( event ) {
-                               var is_enter = ( event.which === 13 ),
-                                       is_esc = ( event.which === 27 ),
-                                       is_down = ( event.which === 40 ),
-                                       is_up = ( event.which === 38 ),
-                                       selected_widget_tpl = null,
-                                       first_visible_widget = panel.container.find( '> .widget-tpl:visible:first' ),
-                                       last_visible_widget = panel.container.find( '> .widget-tpl:visible:last' ),
-                                       is_input_focused = $( event.target ).is( panel.filter_input );
-
-                               if ( is_down || is_up ) {
-                                       if ( is_down ) {
-                                               if ( is_input_focused ) {
-                                                       selected_widget_tpl = first_visible_widget;
-                                               } else if ( panel.selected_widget_tpl && panel.selected_widget_tpl.nextAll( '.widget-tpl:visible' ).length !== 0 ) {
-                                                       selected_widget_tpl = panel.selected_widget_tpl.nextAll( '.widget-tpl:visible:first' );
-                                               }
-                                       } else if ( is_up ) {
-                                               if ( is_input_focused ) {
-                                                       selected_widget_tpl = last_visible_widget;
-                                               } else if ( panel.selected_widget_tpl && panel.selected_widget_tpl.prevAll( '.widget-tpl:visible' ).length !== 0 ) {
-                                                       selected_widget_tpl = panel.selected_widget_tpl.prevAll( '.widget-tpl:visible:first' );
-                                               }
-                                       }
-                                       panel.select( selected_widget_tpl );
-                                       if ( selected_widget_tpl ) {
-                                               selected_widget_tpl.focus();
-                                       } else {
-                                               panel.filter_input.focus();
-                                       }
-                                       return;
-                               }
-
-                               // If enter pressed but nothing entered, don't do anything
-                               if ( is_enter && ! panel.filter_input.val() ) {
-                                       return;
-                               }
-
-                               if ( is_enter ) {
-                                       panel.submit();
-                               } else if ( is_esc ) {
-                                       panel.close( { return_focus: true } );
-                               }
-                       } );
-               },
-
-               /**
-                * Updates widgets list.
-                */
-               update_available_widgets_list: function() {
-                       var panel = api.Widgets.availableWidgetsPanel;
-
-                       // First hide all widgets...
-                       panel.container.find( '.widget-tpl' ).hide();
-
-                       // ..and then show only available widgets which could be filtered
-                       api.Widgets.availableWidgets.each( function ( widget ) {
-                               var widget_tpl = $( '#widget-tpl-' + widget.id );
-                               widget_tpl.toggle( ! widget.get( 'is_disabled' ) );
-                               if ( widget.get( 'is_disabled' ) && widget_tpl.is( panel.selected_widget_tpl ) ) {
-                                       panel.selected_widget_tpl = null;
-                               }
-                       } );
-               },
-
-               /**
-                * @param widget_tpl
-                */
-               select: function ( widget_tpl ) {
-                       var panel = this;
-                       panel.selected_widget_tpl = $( widget_tpl );
-                       panel.selected_widget_tpl.siblings( '.widget-tpl' ).removeClass( 'selected' );
-                       panel.selected_widget_tpl.addClass( 'selected' );
-               },
-
-               submit: function ( widget_tpl ) {
-                       var panel = this, widget_id, widget;
-                       if ( ! widget_tpl ) {
-                               widget_tpl = panel.selected_widget_tpl;
-                       }
-                       if ( ! widget_tpl || ! panel.active_sidebar_widgets_control ) {
-                               return;
-                       }
-                       panel.select( widget_tpl );
-
-                       widget_id = $( panel.selected_widget_tpl ).data( 'widget-id' );
-                       widget = api.Widgets.availableWidgets.findWhere( {id: widget_id} );
-                       if ( ! widget ) {
-                               throw new Error( 'Widget unexpectedly not found.' );
-                       }
-                       panel.active_sidebar_widgets_control.addWidget( widget.get( 'id_base' ) );
-                       panel.close();
-               },
-
-               /**
-                * @param sidebars_widgets_control
-                */
-               open: function ( sidebars_widgets_control ) {
-                       var panel = this;
-                       panel.active_sidebar_widgets_control = sidebars_widgets_control;
-
-                       // Wide widget controls appear over the preview, and so they need to be collapsed when the panel opens
-                       _( sidebars_widgets_control.getWidgetFormControls() ).each( function ( control ) {
-                               if ( control.params.is_wide ) {
-                                       control.collapseForm();
-                               }
-                       } );
-
-                       $( 'body' ).addClass( 'adding-widget' );
-                       panel.container.find( '.widget-tpl' ).removeClass( 'selected' );
-                       api.Widgets.availableWidgets.doSearch( '' );
-                       panel.filter_input.focus();
-               },
-
-               /**
-                * Hide the panel
-                */
-               close: function ( options ) {
-                       var panel = this;
-                       options = options || {};
-                       if ( options.return_focus && panel.active_sidebar_widgets_control ) {
-                               panel.active_sidebar_widgets_control.container.find( '.add-new-widget' ).focus();
-                       }
-                       panel.active_sidebar_widgets_control = null;
-                       panel.selected_widget_tpl = null;
-                       $( 'body' ).removeClass( 'adding-widget' );
-                       panel.filter_input.val( '' );
-               }
-       };
-
-       /**
</del><span class="cx">    * @param {String} widget_id
</span><span class="cx">   * @returns {Object}
</span><span class="cx">   */
</span></span></pre>
</div>
</div>

</body>
</html>