Ticket #27690: 27690.2.patch
| File 27690.2.patch, 27.9 KB (added by , 12 years ago) |
|---|
-
src/wp-admin/js/customize-widgets.js
121 121 * @param {jQuery} widget 122 122 * @param {String} newForm 123 123 */ 124 rss: function ( e, widget, newForm ) {124 rss: function( e, widget, newForm ) { 125 125 var oldWidgetError = widget.find( '.widget-error:first' ), 126 126 newWidgetError = $( '<div>' + newForm + '</div>' ).find( '.widget-error:first' ); 127 127 … … 246 246 } ); 247 247 248 248 // Reposition whenever a sidebar's widgets are changed 249 api.each( function ( setting ) {249 api.each( function( setting ) { 250 250 if ( 0 === setting.id.indexOf( 'sidebars_widgets[' ) ) { 251 251 setting.bind( function() { 252 252 if ( control.container.hasClass( 'expanded' ) ) { … … 264 264 _setupControlToggle: function() { 265 265 var control = this, close_btn; 266 266 267 control.container.find( '.widget-top' ).on( 'click', function ( e ) {267 control.container.find( '.widget-top' ).on( 'click', function( e ) { 268 268 e.preventDefault(); 269 269 var sidebar_widgets_control = control.getSidebarWidgetsControl(); 270 270 if ( sidebar_widgets_control.is_reordering ) { … … 275 275 276 276 close_btn = control.container.find( '.widget-control-close' ); 277 277 // @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 ) {278 close_btn.on( 'click', function( e ) { 279 279 e.preventDefault(); 280 280 control.collapseForm(); 281 281 control.container.find( '.widget-top .widget-action:first' ).focus(); // keyboard accessibility … … 317 317 * 318 318 * @param {jQuery} li 319 319 */ 320 select_sidebar_item = function ( li ) {320 select_sidebar_item = function( li ) { 321 321 li.siblings( '.selected' ).removeClass( 'selected' ); 322 322 li.addClass( 'selected' ); 323 323 var is_self_sidebar = ( li.data( 'id' ) === control.params.sidebar_id ); … … 363 363 * Handle clicks for up/down/move on the reorder nav 364 364 */ 365 365 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 ) {366 reorder_nav.find( '.move-widget, .move-widget-down, .move-widget-up' ).on( 'click keypress', function( event ) { 367 367 if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) { 368 368 return; 369 369 } … … 393 393 /** 394 394 * Handle selecting a sidebar to move to 395 395 */ 396 control.container.find( '.widget-area-select' ).on( 'click keypress', 'li', function ( e ) {396 control.container.find( '.widget-area-select' ).on( 'click keypress', 'li', function( e ) { 397 397 if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) { 398 398 return; 399 399 } … … 472 472 save_btn.val( l10n.saveBtnLabel ); 473 473 save_btn.attr( 'title', l10n.saveBtnTooltip ); 474 474 save_btn.removeClass( 'button-primary' ).addClass( 'button-secondary' ); 475 save_btn.on( 'click', function ( e ) {475 save_btn.on( 'click', function( e ) { 476 476 e.preventDefault(); 477 477 control.updateWidget( { disable_form: true } ); 478 478 } ); … … 491 491 } ); 492 492 493 493 // Handle widgets that support live previews 494 widget_content.on( 'change input propertychange', ':input', function ( e ) {494 widget_content.on( 'change input propertychange', ':input', function( e ) { 495 495 if ( control.live_update_mode ) { 496 496 if ( e.type === 'change' ) { 497 497 control.updateWidget(); … … 505 505 control.setting.previewer.channel.bind( 'synced', function() { 506 506 control.container.removeClass( 'previewer-loading' ); 507 507 } ); 508 api.Widgets.Previewer.bind( 'widget-updated', function ( updated_widget_id ) {508 api.Widgets.Previewer.bind( 'widget-updated', function( updated_widget_id ) { 509 509 if ( updated_widget_id === control.params.widget_id ) { 510 510 control.container.removeClass( 'previewer-loading' ); 511 511 } 512 512 } ); 513 513 514 514 // Update widget control to indicate whether it is currently rendered (cf. Widget Visibility) 515 api.Widgets.Previewer.bind( 'rendered-widgets', function ( rendered_widgets ) {515 api.Widgets.Previewer.bind( 'rendered-widgets', function( rendered_widgets ) { 516 516 var is_rendered = !! rendered_widgets[control.params.widget_id]; 517 517 control.container.toggleClass( 'widget-rendered', is_rendered ); 518 518 } ); 519 519 520 520 form_update_event_handler = api.Widgets.formSyncHandlers[ control.params.widget_id_base ]; 521 521 if ( form_update_event_handler ) { 522 $( document ).on( 'widget-synced', function ( e, widget_el ) {522 $( document ).on( 'widget-synced', function( e, widget_el ) { 523 523 if ( widget_root.is( widget_el ) ) { 524 524 form_update_event_handler.apply( document, arguments ); 525 525 } … … 538 538 // Configure remove button 539 539 remove_btn = control.container.find( 'a.widget-control-remove' ); 540 540 // @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 ) {541 remove_btn.on( 'click', function( e ) { 542 542 e.preventDefault(); 543 543 544 544 // Find an adjacent element to add focus to when this widget goes away … … 592 592 * @returns {jQuery} inputs 593 593 * @private 594 594 */ 595 _getInputs: function ( container ) {595 _getInputs: function( container ) { 596 596 return $( container ).find( ':input[name]' ); 597 597 }, 598 598 … … 604 604 * @returns {string} 605 605 * @private 606 606 */ 607 _getInputsSignature: function ( inputs ) {608 var inputs_signatures = _( inputs ).map( function ( input ) {607 _getInputsSignature: function( inputs ) { 608 var inputs_signatures = _( inputs ).map( function( input ) { 609 609 input = $( input ); 610 610 var signature_parts; 611 611 if ( input.is( ':checkbox, :radio' ) ) { … … 625 625 * @returns {string} 626 626 * @private 627 627 */ 628 _getInputStatePropertyName: function ( input ) {628 _getInputStatePropertyName: function( input ) { 629 629 input = $( input ); 630 630 if ( input.is( ':radio, :checkbox' ) ) { 631 631 return 'checked'; … … 661 661 * @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. 662 662 * @param {Boolean} [args.ignore_active_element=false] Whether or not updating a field will be deferred if focus is still on the element. 663 663 */ 664 updateWidget: function ( args ) {664 updateWidget: function( args ) { 665 665 var control = this, 666 666 instance_override, 667 667 complete_callback, … … 726 726 } 727 727 data += '&' + widget_content.find( '~ :input' ).serialize(); 728 728 729 jqxhr = $.post( wp.ajax.settings.url, data, function ( r ) {729 jqxhr = $.post( wp.ajax.settings.url, data, function( r ) { 730 730 var message, 731 731 sanitized_form, 732 732 sanitized_inputs, … … 763 763 764 764 // Sync sanitized field states to existing fields if they are aligned 765 765 if ( has_same_inputs_in_response && control.live_update_mode ) { 766 inputs.each( function ( i ) {766 inputs.each( function( i ) { 767 767 var input = $( this ), 768 768 sanitized_input = $( sanitized_inputs[i] ), 769 769 property = control._getInputStatePropertyName( this ), … … 827 827 } 828 828 } 829 829 } ); 830 jqxhr.fail( function ( jqXHR, textStatus ) {830 jqxhr.fail( function( jqXHR, textStatus ) { 831 831 if ( complete_callback ) { 832 832 complete_callback.call( control, textStatus ); 833 833 } … … 872 872 * 873 873 * @param {boolean|undefined} [do_expand] If not supplied, will be inverse of current visibility 874 874 */ 875 toggleForm: function ( do_expand ) {875 toggleForm: function( do_expand ) { 876 876 var control = this, widget, inside, complete; 877 877 878 878 widget = control.container.find( 'div.widget:first' ); … … 888 888 889 889 if ( do_expand ) { 890 890 // Close all other widget controls before expanding this one 891 api.control.each( function ( other_control ) {891 api.control.each( function( other_control ) { 892 892 if ( control.params.type === other_control.params.type && control !== other_control ) { 893 893 other_control.collapseForm(); 894 894 } … … 974 974 * 975 975 * @param {Number} offset 1|-1 976 976 */ 977 _moveWidgetByOne: function ( offset ) {977 _moveWidgetByOne: function( offset ) { 978 978 var control = this, 979 979 i, 980 980 sidebar_widgets_setting, … … 997 997 * 998 998 * @param {Boolean} [toggle] 999 999 */ 1000 toggleWidgetMoveArea: function ( toggle ) {1000 toggleWidgetMoveArea: function( toggle ) { 1001 1001 var control = this, move_widget_area; 1002 1002 move_widget_area = control.container.find( '.move-widget-area' ); 1003 1003 if ( typeof toggle === 'undefined' ) { … … 1074 1074 removed_widget_ids = _( old_widget_ids ).difference( new_widget_ids ); 1075 1075 1076 1076 // Filter out any persistent widget_ids for widgets which have been deactivated 1077 new_widget_ids = _( new_widget_ids ).filter( function ( new_widget_id ) {1077 new_widget_ids = _( new_widget_ids ).filter( function( new_widget_id ) { 1078 1078 var parsed_widget_id = parse_widget_id( new_widget_id ); 1079 1079 return !! api.Widgets.availableWidgets.findWhere( { id_base: parsed_widget_id.id_base } ); 1080 1080 } ); 1081 1081 1082 widget_form_controls = _( new_widget_ids ).map( function ( widget_id ) {1082 widget_form_controls = _( new_widget_ids ).map( function( widget_id ) { 1083 1083 var widget_form_control = api.Widgets.getWidgetFormControlForWidget( widget_id ); 1084 1084 if ( ! widget_form_control ) { 1085 1085 widget_form_control = control.addWidget( widget_id ); … … 1088 1088 } ); 1089 1089 1090 1090 // Sort widget controls to their new positions 1091 widget_form_controls.sort( function ( a, b ) {1091 widget_form_controls.sort( function( a, b ) { 1092 1092 var a_index = _.indexOf( new_widget_ids, a.params.widget_id ), 1093 1093 b_index = _.indexOf( new_widget_ids, b.params.widget_id ); 1094 1094 if ( a_index === b_index ) { … … 1109 1109 control._applyCardinalOrderClassNames(); 1110 1110 1111 1111 // 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 ) {1112 _( widget_form_controls ).each( function( widget_form_control ) { 1113 1113 widget_form_control.params.sidebar_id = control.params.sidebar_id; 1114 1114 } ); 1115 1115 1116 1116 // Cleanup after widget removal 1117 _( removed_widget_ids ).each( function ( removed_widget_id ) {1117 _( removed_widget_ids ).each( function( removed_widget_id ) { 1118 1118 1119 1119 // Using setTimeout so that when moving a widget to another sidebar, the other sidebars_widgets settings get a chance to update 1120 1120 setTimeout( function() { … … 1126 1126 widget; 1127 1127 1128 1128 // Check if the widget is in another sidebar 1129 api.each( function ( other_setting ) {1129 api.each( function( other_setting ) { 1130 1130 if ( other_setting.id === control.setting.id || 0 !== other_setting.id.indexOf( 'sidebars_widgets[' ) || other_setting.id === 'sidebars_widgets[wp_inactive_widgets]' ) { 1131 1131 return; 1132 1132 } … … 1178 1178 } ); 1179 1179 1180 1180 // Update the model with whether or not the sidebar is rendered 1181 api.Widgets.Previewer.bind( 'rendered-sidebars', function ( rendered_sidebars ) {1181 api.Widgets.Previewer.bind( 'rendered-sidebars', function( rendered_sidebars ) { 1182 1182 var is_rendered = !! rendered_sidebars[control.params.sidebar_id]; 1183 1183 registered_sidebar.set( 'is_rendered', is_rendered ); 1184 1184 } ); 1185 1185 1186 1186 // Show the sidebar section when it becomes visible 1187 registered_sidebar.on( 'change:is_rendered', function ( ) {1187 registered_sidebar.on( 'change:is_rendered', function( ) { 1188 1188 var section_selector = '#accordion-section-sidebar-widgets-' + this.get( 'id' ), section; 1189 1189 section = $( section_selector ); 1190 1190 if ( this.get( 'is_rendered' ) ) { … … 1219 1219 connectWith: '.accordion-section-content:has(.customize-control-sidebar_widgets)', 1220 1220 update: function() { 1221 1221 var widget_container_ids = control.section_content.sortable( 'toArray' ), widget_ids; 1222 widget_ids = $.map( widget_container_ids, function ( widget_container_id ) {1222 widget_ids = $.map( widget_container_ids, function( widget_container_id ) { 1223 1223 return $( '#' + widget_container_id ).find( ':input[name=widget-id]' ).val(); 1224 1224 } ); 1225 1225 control.setting( widget_ids ); … … 1306 1306 * 1307 1307 * @param {Boolean} toggle to enable/disable reordering 1308 1308 */ 1309 toggleReordering: function ( toggle ) {1309 toggleReordering: function( toggle ) { 1310 1310 var control = this; 1311 1311 toggle = Boolean( toggle ); 1312 1312 if ( toggle === control.section_content.hasClass( 'reordering' ) ) { … … 1317 1317 control.section_content.toggleClass( 'reordering', toggle ); 1318 1318 1319 1319 if ( toggle ) { 1320 _( control.getWidgetFormControls() ).each( function ( form_control ) {1320 _( control.getWidgetFormControls() ).each( function( form_control ) { 1321 1321 form_control.collapseForm(); 1322 1322 } ); 1323 1323 } … … 1329 1329 getWidgetFormControls: function() { 1330 1330 var control = this, form_controls; 1331 1331 1332 form_controls = _( control.setting() ).map( function ( widget_id ) {1332 form_controls = _( control.setting() ).map( function( widget_id ) { 1333 1333 var setting_id = widget_id_to_setting_id( widget_id ), 1334 1334 form_control = api.control( setting_id ); 1335 1335 … … 1345 1345 * @param {string} widget_id or an id_base for adding a previously non-existing widget 1346 1346 * @returns {object} widget_form control instance 1347 1347 */ 1348 addWidget: function ( widget_id ) {1348 addWidget: function( widget_id ) { 1349 1349 var control = this, 1350 1350 control_html, 1351 1351 widget_el, … … 1377 1377 1378 1378 control_html = $( '#widget-tpl-' + widget.get( 'id' ) ).html(); 1379 1379 if ( widget.get( 'is_multi' ) ) { 1380 control_html = control_html.replace( /<[^<>]+>/g, function ( m ) {1380 control_html = control_html.replace( /<[^<>]+>/g, function( m ) { 1381 1381 return m.replace( /__i__|%i%/g, widget_number ); 1382 1382 } ); 1383 1383 } else { … … 1435 1435 api.control.add( setting_id, widget_form_control ); 1436 1436 1437 1437 // Make sure widget is removed from the other sidebars 1438 api.each( function ( other_setting ) {1438 api.each( function( other_setting ) { 1439 1439 if ( other_setting.id === control.setting.id ) { 1440 1440 return; 1441 1441 } … … 1462 1462 widget_form_control.expandForm(); 1463 1463 widget_form_control.updateWidget( { 1464 1464 instance: widget_form_control.setting(), 1465 complete: function ( error ) {1465 complete: function( error ) { 1466 1466 if ( error ) { 1467 1467 throw error; 1468 1468 } … … 1488 1488 1489 1489 api.bind( 'ready', function() { 1490 1490 // Set up the widgets panel 1491 api.Widgets.availableWidgetsPanel.setup(); 1491 api.Widgets.availableWidgetsPanel = new api.Widgets.AvailableWidgetsPanelView({ 1492 collection: api.Widgets.availableWidgets 1493 }); 1492 1494 1493 1495 // Highlight widget control 1494 1496 api.Widgets.Previewer.bind( 'highlight-widget-control', api.Widgets.highlightWidgetFormControl ); … … 1540 1542 * @param {string} widget_id 1541 1543 * @return {object|null} 1542 1544 */ 1543 api.Widgets.getSidebarWidgetControlContainingWidget = function ( widget_id ) {1545 api.Widgets.getSidebarWidgetControlContainingWidget = function( widget_id ) { 1544 1546 var found_control = null; 1545 1547 // @todo this can use widget_id_to_setting_id(), then pass into wp.customize.control( x ).getSidebarWidgetsControl() 1546 api.control.each( function ( control ) {1548 api.control.each( function( control ) { 1547 1549 if ( control.params.type === 'sidebar_widgets' && -1 !== _.indexOf( control.setting(), widget_id ) ) { 1548 1550 found_control = control; 1549 1551 } … … 1557 1559 * @param {string} widget_id 1558 1560 * @return {object|null} 1559 1561 */ 1560 api.Widgets.getWidgetFormControlForWidget = function ( widget_id ) {1562 api.Widgets.getWidgetFormControlForWidget = function( widget_id ) { 1561 1563 var found_control = null; 1562 1564 // @todo We can just use widget_id_to_setting_id() here 1563 api.control.each( function ( control ) {1565 api.control.each( function( control ) { 1564 1566 if ( control.params.type === 'widget_form' && control.params.widget_id === widget_id ) { 1565 1567 found_control = control; 1566 1568 } … … 1569 1571 return found_control; 1570 1572 }; 1571 1573 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, 1574 api.Widgets.AvailableWidgetsPanelView = wp.Backbone.View.extend({ 1580 1575 1581 /** 1582 * Set up event listeners 1583 */ 1584 setup: function() { 1585 var panel = this; 1576 el: '#available-widgets', 1586 1577 1587 panel.container = $( '#available-widgets' ); 1588 panel.filter_input = $( '#available-widgets-filter' ).find( 'input' ); 1578 events: { 1579 'input #widgets-search': 'search', 1580 'keyup #widgets-search': 'search', 1581 'change #widgets-search': 'search', 1582 'search #widgets-search': 'search', 1583 'focus .widget-tpl' : 'focus', 1584 'click .widget-tpl' : '_submit', 1585 'keypress .widget-tpl' : '_submit', 1586 'keydown' : 'keyboardAccessible' 1587 }, 1589 1588 1590 api.Widgets.availableWidgets.on( 'change update', panel.update_available_widgets_list ); 1591 panel.update_available_widgets_list(); 1589 selected: null, 1590 currentSidebarControl: null, 1591 $search: null, 1592 1592 1593 initialize: function() { 1594 var self = this; 1595 1596 this.$search = $( '#widgets-search' ); 1597 1598 this.listenTo( this.collection, 'update', this.updateList ); 1599 1600 this.updateList(); 1601 1593 1602 // If the available widgets panel is open and the customize controls are 1594 1603 // interacted with (i.e. available widgets panel is blurred) then close the 1595 1604 // 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();1605 $( '#customize-controls' ).on( 'click keydown', function( e ) { 1606 var isAddNewBtn = $( e.target ).is( '.add-new-widget, .add-new-widget *' ); 1607 if ( $( 'body' ).hasClass( 'adding-widget' ) && ! isAddNewBtn ) { 1608 self.close(); 1600 1609 } 1601 1610 } ); 1602 1611 1603 1612 // Close the panel if the URL in the preview changes 1604 api.Widgets.Previewer.bind( 'url', function() { 1605 panel.close(); 1606 } ); 1613 api.Widgets.Previewer.bind( 'url', this.close ); 1614 }, 1607 1615 1608 // Submit a selection when clicked or keypressed1609 panel.container.find( '.widget-tpl' ).on( 'click keypress', function( event ) {1616 search: function( event ) { 1617 var firstVisible; 1610 1618 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 } 1619 this.collection.doSearch( event.target.value ); 1615 1620 1616 panel.submit( this ); 1617 } ); 1621 // Remove a widget from being selected if it is no longer visible 1622 if ( this.selected && ! this.selected.is( ':visible' ) ) { 1623 this.selected.removeClass( 'selected' ); 1624 this.selected = null; 1625 } 1618 1626 1619 panel.filter_input.on( 'input keyup change', function( event ) { 1620 var first_visible_widget; 1627 // If a widget was selected but the filter value has been cleared out, clear selection 1628 if ( this.selected && ! event.target.value ) { 1629 this.selected.removeClass( 'selected' ); 1630 this.selected = null; 1631 } 1621 1632 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; 1633 // If a filter has been entered and a widget hasn't been selected, select the first one shown 1634 if ( ! this.selected && event.target.value ) { 1635 firstVisible = this.$el.find( '> .widget-tpl:visible:first' ); 1636 if ( firstVisible.length ) { 1637 this.select( firstVisible ); 1628 1638 } 1639 } 1640 }, 1629 1641 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 } 1642 updateList: function() { 1643 // First hide all widgets... 1644 this.$el.find( '.widget-tpl' ).hide(); 1635 1645 1636 // If a filter has been entered and a widget hasn't been selected, select the first one shown1637 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 }1646 // ..and then show only available widgets which could be filtered 1647 this.collection.each( function( widget ) { 1648 var widgetTpl = $( '#widget-tpl-' + widget.id ); 1649 widgetTpl.toggle( ! widget.get( 'is_disabled' ) ); 1650 if ( widget.get( 'is_disabled' ) && widgetTpl.is( this.selected ) ) { 1651 this.selected = null; 1642 1652 } 1643 1653 } ); 1654 }, 1644 1655 1645 // Select a widget when it is focused on 1646 panel.container.find( ' > .widget-tpl' ).on( 'focus', function() { 1647 panel.select( this ); 1648 } ); 1656 select: function( widgetTpl ) { 1657 this.selected = $( widgetTpl ); 1658 this.selected.siblings( '.widget-tpl' ).removeClass( 'selected' ); 1659 this.selected.addClass( 'selected' ); 1660 }, 1649 1661 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 } ); 1662 focus: function( event ) { 1663 this.select( $( event.currentTarget ) ); 1694 1664 }, 1695 1665 1696 /**1697 * Updates widgets list.1698 */1699 update_available_widgets_list: function() {1700 var panel = api.Widgets.availableWidgetsPanel;1666 _submit: function( event ) { 1667 // Only proceed with keypress if it is Enter or Spacebar 1668 if ( event.type === 'keypress' && ( event.which !== 13 && event.which !== 32 ) ) { 1669 return; 1670 } 1701 1671 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 } ); 1672 this.submit( $( event.currentTarget ) ); 1713 1673 }, 1714 1674 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 }, 1675 submit: function( widgetTpl ) { 1676 var widgetId, widget; 1724 1677 1725 submit: function ( widget_tpl ) { 1726 var panel = this, widget_id, widget; 1727 if ( ! widget_tpl ) { 1728 widget_tpl = panel.selected_widget_tpl; 1678 if ( ! widgetTpl ) { 1679 widgetTpl = this.selected; 1729 1680 } 1730 if ( ! widget_tpl || ! panel.active_sidebar_widgets_control ) { 1681 1682 if ( ! widgetTpl || ! this.currentSidebarControl ) { 1731 1683 return; 1732 1684 } 1733 panel.select( widget_tpl );1734 1685 1735 widget_id = $( panel.selected_widget_tpl ).data( 'widget-id' ); 1736 widget = api.Widgets.availableWidgets.findWhere( {id: widget_id} ); 1686 this.select( widgetTpl ); 1687 1688 widgetId = $( this.selected ).data( 'widget-id' ); 1689 widget = this.collection.findWhere( { id: widgetId } ); 1737 1690 if ( ! widget ) { 1738 throw new Error( 'Widget unexpectedly not found.' );1691 return; 1739 1692 } 1740 panel.active_sidebar_widgets_control.addWidget( widget.get( 'id_base' ) ); 1741 panel.close(); 1693 1694 this.currentSidebarControl.addWidget( widget.get( 'id_base' ) ); 1695 1696 this.close(); 1742 1697 }, 1743 1698 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; 1699 open: function( sidebarControl ) { 1700 this.currentSidebarControl = sidebarControl; 1750 1701 1751 1702 // 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 ) {1703 _( this.currentSidebarControl.getWidgetFormControls() ).each( function( control ) { 1753 1704 if ( control.params.is_wide ) { 1754 1705 control.collapseForm(); 1755 1706 } 1756 1707 } ); 1757 1708 1758 1709 $( 'body' ).addClass( 'adding-widget' ); 1759 panel.container.find( '.widget-tpl' ).removeClass( 'selected' ); 1760 api.Widgets.availableWidgets.doSearch( '' ); 1761 panel.filter_input.focus(); 1710 1711 this.$el.find( '.selected' ).removeClass( 'selected' ); 1712 1713 // Reset search 1714 this.collection.doSearch( '' ); 1715 1716 this.$search.focus(); 1762 1717 }, 1763 1718 1764 /** 1765 * Hide the panel 1766 */ 1767 close: function ( options ) { 1768 var panel = this; 1719 close: function( options ) { 1769 1720 options = options || {}; 1770 if ( options.return_focus && panel.active_sidebar_widgets_control ) { 1771 panel.active_sidebar_widgets_control.container.find( '.add-new-widget' ).focus(); 1721 1722 if ( options.returnFocus && this.currentSidebarControl ) { 1723 this.currentSidebarControl.container.find( '.add-new-widget' ).focus(); 1772 1724 } 1773 panel.active_sidebar_widgets_control = null; 1774 panel.selected_widget_tpl = null; 1725 1726 this.currentSidebarControl = null; 1727 this.selected = null; 1728 1775 1729 $( 'body' ).removeClass( 'adding-widget' ); 1776 panel.filter_input.val( '' ); 1730 1731 this.$search.val( '' ); 1732 }, 1733 1734 keyboardAccessible: function( event ) { 1735 var isEnter = ( event.which === 13 ), 1736 isEsc = ( event.which === 27 ), 1737 isDown = ( event.which === 40 ), 1738 isUp = ( event.which === 38 ), 1739 selected = null, 1740 firstVisible = this.$el.find( '> .widget-tpl:visible:first' ), 1741 lastVisible = this.$el.find( '> .widget-tpl:visible:last' ), 1742 isSearchFocused = $( event.target ).is( this.$search ); 1743 1744 if ( isDown || isUp ) { 1745 if ( isDown ) { 1746 if ( isSearchFocused ) { 1747 selected = firstVisible; 1748 } else if ( this.selected && this.selected.nextAll( '.widget-tpl:visible' ).length !== 0 ) { 1749 selected = this.selected.nextAll( '.widget-tpl:visible:first' ); 1750 } 1751 } else if ( isUp ) { 1752 if ( isSearchFocused ) { 1753 selected = lastVisible; 1754 } else if ( this.selected && this.selected.prevAll( '.widget-tpl:visible' ).length !== 0 ) { 1755 selected = this.selected.prevAll( '.widget-tpl:visible:first' ); 1756 } 1757 } 1758 1759 this.select( selected ); 1760 1761 if ( selected ) { 1762 selected.focus(); 1763 } else { 1764 this.$search.focus(); 1765 } 1766 1767 return; 1768 } 1769 1770 // If enter pressed but nothing entered, don't do anything 1771 if ( isEnter && ! this.$search.val() ) { 1772 return; 1773 } 1774 1775 if ( isEnter ) { 1776 this.submit(); 1777 } else if ( isEsc ) { 1778 this.close( { returnFocus: true } ); 1779 } 1777 1780 } 1778 } ;1781 }); 1779 1782 1780 1783 /** 1781 1784 * @param {String} widget_id
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)