[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/js/ -> widgets.js (source)

   1  /**
   2   * @output wp-admin/js/widgets.js
   3   */
   4  
   5  /* global ajaxurl, isRtl, wpWidgets */
   6  
   7  (function($) {
   8      var $document = $( document );
   9  
  10  window.wpWidgets = {
  11      /**
  12       * A closed Sidebar that gets a Widget dragged over it.
  13       *
  14       * @var {element|null}
  15       */
  16      hoveredSidebar: null,
  17  
  18      /**
  19       * Lookup of which widgets have had change events triggered.
  20       *
  21       * @var {object}
  22       */
  23      dirtyWidgets: {},
  24  
  25      init : function() {
  26          var rem, the_id,
  27              self = this,
  28              chooser = $('.widgets-chooser'),
  29              selectSidebar = chooser.find('.widgets-chooser-sidebars'),
  30              sidebars = $('div.widgets-sortables'),
  31              isRTL = !! ( 'undefined' !== typeof isRtl && isRtl );
  32  
  33          // Handle the widgets containers in the right column.
  34          $( '#widgets-right .sidebar-name' )
  35              /*
  36               * Toggle the widgets containers when clicked and update the toggle
  37               * button `aria-expanded` attribute value.
  38               */
  39              .on( 'click', function() {
  40                  var $this = $( this ),
  41                      $wrap = $this.closest( '.widgets-holder-wrap '),
  42                      $toggle = $this.find( '.handlediv' );
  43  
  44                  if ( $wrap.hasClass( 'closed' ) ) {
  45                      $wrap.removeClass( 'closed' );
  46                      $toggle.attr( 'aria-expanded', 'true' );
  47                      // Refresh the jQuery UI sortable items.
  48                      $this.parent().sortable( 'refresh' );
  49                  } else {
  50                      $wrap.addClass( 'closed' );
  51                      $toggle.attr( 'aria-expanded', 'false' );
  52                  }
  53  
  54                  // Update the admin menu "sticky" state.
  55                  $document.triggerHandler( 'wp-pin-menu' );
  56              })
  57              /*
  58               * Set the initial `aria-expanded` attribute value on the widgets
  59               * containers toggle button. The first one is expanded by default.
  60               */
  61              .find( '.handlediv' ).each( function( index ) {
  62                  if ( 0 === index ) {
  63                      // jQuery equivalent of `continue` within an `each()` loop.
  64                      return;
  65                  }
  66  
  67                  $( this ).attr( 'aria-expanded', 'false' );
  68              });
  69  
  70          // Show AYS dialog when there are unsaved widget changes.
  71          $( window ).on( 'beforeunload.widgets', function( event ) {
  72              var dirtyWidgetIds = [], unsavedWidgetsElements;
  73              $.each( self.dirtyWidgets, function( widgetId, dirty ) {
  74                  if ( dirty ) {
  75                      dirtyWidgetIds.push( widgetId );
  76                  }
  77              });
  78              if ( 0 !== dirtyWidgetIds.length ) {
  79                  unsavedWidgetsElements = $( '#widgets-right' ).find( '.widget' ).filter( function() {
  80                      return -1 !== dirtyWidgetIds.indexOf( $( this ).prop( 'id' ).replace( /^widget-\d+_/, '' ) );
  81                  });
  82                  unsavedWidgetsElements.each( function() {
  83                      if ( ! $( this ).hasClass( 'open' ) ) {
  84                          $( this ).find( '.widget-title-action:first' ).trigger( 'click' );
  85                      }
  86                  });
  87  
  88                  // Bring the first unsaved widget into view and focus on the first tabbable field.
  89                  unsavedWidgetsElements.first().each( function() {
  90                      if ( this.scrollIntoViewIfNeeded ) {
  91                          this.scrollIntoViewIfNeeded();
  92                      } else {
  93                          this.scrollIntoView();
  94                      }
  95                      $( this ).find( '.widget-inside :tabbable:first' ).trigger( 'focus' );
  96                  } );
  97  
  98                  event.returnValue = wp.i18n.__( 'The changes you made will be lost if you navigate away from this page.' );
  99                  return event.returnValue;
 100              }
 101          });
 102  
 103          // Handle the widgets containers in the left column.
 104          $( '#widgets-left .sidebar-name' ).on( 'click', function() {
 105              var $wrap = $( this ).closest( '.widgets-holder-wrap' );
 106  
 107              $wrap
 108                  .toggleClass( 'closed' )
 109                  .find( '.handlediv' ).attr( 'aria-expanded', ! $wrap.hasClass( 'closed' ) );
 110  
 111              // Update the admin menu "sticky" state.
 112              $document.triggerHandler( 'wp-pin-menu' );
 113          });
 114  
 115          $(document.body).on('click.widgets-toggle', function(e) {
 116              var target = $(e.target), css = {},
 117                  widget, inside, targetWidth, widgetWidth, margin, saveButton, widgetId,
 118                  toggleBtn = target.closest( '.widget' ).find( '.widget-top button.widget-action' );
 119  
 120              if ( target.parents('.widget-top').length && ! target.parents('#available-widgets').length ) {
 121                  widget = target.closest('div.widget');
 122                  inside = widget.children('.widget-inside');
 123                  targetWidth = parseInt( widget.find('input.widget-width').val(), 10 );
 124                  widgetWidth = widget.parent().width();
 125                  widgetId = inside.find( '.widget-id' ).val();
 126  
 127                  // Save button is initially disabled, but is enabled when a field is changed.
 128                  if ( ! widget.data( 'dirty-state-initialized' ) ) {
 129                      saveButton = inside.find( '.widget-control-save' );
 130                      saveButton.prop( 'disabled', true ).val( wp.i18n.__( 'Saved' ) );
 131                      inside.on( 'input change', function() {
 132                          self.dirtyWidgets[ widgetId ] = true;
 133                          widget.addClass( 'widget-dirty' );
 134                          saveButton.prop( 'disabled', false ).val( wp.i18n.__( 'Save' ) );
 135                      });
 136                      widget.data( 'dirty-state-initialized', true );
 137                  }
 138  
 139                  if ( inside.is(':hidden') ) {
 140                      if ( targetWidth > 250 && ( targetWidth + 30 > widgetWidth ) && widget.closest('div.widgets-sortables').length ) {
 141                          if ( widget.closest('div.widget-liquid-right').length ) {
 142                              margin = isRTL ? 'margin-right' : 'margin-left';
 143                          } else {
 144                              margin = isRTL ? 'margin-left' : 'margin-right';
 145                          }
 146  
 147                          css[ margin ] = widgetWidth - ( targetWidth + 30 ) + 'px';
 148                          widget.css( css );
 149                      }
 150                      /*
 151                       * Don't change the order of attributes changes and animation:
 152                       * it's important for screen readers, see ticket #31476.
 153                       */
 154                      toggleBtn.attr( 'aria-expanded', 'true' );
 155                      inside.slideDown( 'fast', function() {
 156                          widget.addClass( 'open' );
 157                      });
 158                  } else {
 159                      /*
 160                       * Don't change the order of attributes changes and animation:
 161                       * it's important for screen readers, see ticket #31476.
 162                       */
 163                      toggleBtn.attr( 'aria-expanded', 'false' );
 164                      inside.slideUp( 'fast', function() {
 165                          widget.attr( 'style', '' );
 166                          widget.removeClass( 'open' );
 167                      });
 168                  }
 169              } else if ( target.hasClass('widget-control-save') ) {
 170                  wpWidgets.save( target.closest('div.widget'), 0, 1, 0 );
 171                  e.preventDefault();
 172              } else if ( target.hasClass('widget-control-remove') ) {
 173                  wpWidgets.save( target.closest('div.widget'), 1, 1, 0 );
 174              } else if ( target.hasClass('widget-control-close') ) {
 175                  widget = target.closest('div.widget');
 176                  widget.removeClass( 'open' );
 177                  toggleBtn.attr( 'aria-expanded', 'false' );
 178                  wpWidgets.close( widget );
 179              } else if ( target.attr( 'id' ) === 'inactive-widgets-control-remove' ) {
 180                  wpWidgets.removeInactiveWidgets();
 181                  e.preventDefault();
 182              }
 183          });
 184  
 185          sidebars.children('.widget').each( function() {
 186              var $this = $(this);
 187  
 188              wpWidgets.appendTitle( this );
 189  
 190              if ( $this.find( 'p.widget-error' ).length ) {
 191                  $this.find( '.widget-action' ).trigger( 'click' ).attr( 'aria-expanded', 'true' );
 192              }
 193          });
 194  
 195          $('#widget-list').children('.widget').draggable({
 196              connectToSortable: 'div.widgets-sortables',
 197              handle: '> .widget-top > .widget-title',
 198              distance: 2,
 199              helper: 'clone',
 200              zIndex: 101,
 201              containment: '#wpwrap',
 202              refreshPositions: true,
 203              start: function( event, ui ) {
 204                  var chooser = $(this).find('.widgets-chooser');
 205  
 206                  ui.helper.find('div.widget-description').hide();
 207                  the_id = this.id;
 208  
 209                  if ( chooser.length ) {
 210                      // Hide the chooser and move it out of the widget.
 211                      $( '#wpbody-content' ).append( chooser.hide() );
 212                      // Delete the cloned chooser from the drag helper.
 213                      ui.helper.find('.widgets-chooser').remove();
 214                      self.clearWidgetSelection();
 215                  }
 216              },
 217              stop: function() {
 218                  if ( rem ) {
 219                      $(rem).hide();
 220                  }
 221  
 222                  rem = '';
 223              }
 224          });
 225  
 226          /**
 227           * Opens and closes previously closed Sidebars when Widgets are dragged over/out of them.
 228           */
 229          sidebars.droppable( {
 230              tolerance: 'intersect',
 231  
 232              /**
 233               * Open Sidebar when a Widget gets dragged over it.
 234               *
 235               * @ignore
 236               *
 237               * @param {Object} event jQuery event object.
 238               */
 239              over: function( event ) {
 240                  var $wrap = $( event.target ).parent();
 241  
 242                  if ( wpWidgets.hoveredSidebar && ! $wrap.is( wpWidgets.hoveredSidebar ) ) {
 243                      // Close the previous Sidebar as the Widget has been dragged onto another Sidebar.
 244                      wpWidgets.closeSidebar( event );
 245                  }
 246  
 247                  if ( $wrap.hasClass( 'closed' ) ) {
 248                      wpWidgets.hoveredSidebar = $wrap;
 249                      $wrap
 250                          .removeClass( 'closed' )
 251                          .find( '.handlediv' ).attr( 'aria-expanded', 'true' );
 252                  }
 253  
 254                  $( this ).sortable( 'refresh' );
 255              },
 256  
 257              /**
 258               * Close Sidebar when the Widget gets dragged out of it.
 259               *
 260               * @ignore
 261               *
 262               * @param {Object} event jQuery event object.
 263               */
 264              out: function( event ) {
 265                  if ( wpWidgets.hoveredSidebar ) {
 266                      wpWidgets.closeSidebar( event );
 267                  }
 268              }
 269          } );
 270  
 271          sidebars.sortable({
 272              placeholder: 'widget-placeholder',
 273              items: '> .widget',
 274              handle: '> .widget-top > .widget-title',
 275              cursor: 'move',
 276              distance: 2,
 277              containment: '#wpwrap',
 278              tolerance: 'pointer',
 279              refreshPositions: true,
 280              start: function( event, ui ) {
 281                  var height, $this = $(this),
 282                      $wrap = $this.parent(),
 283                      inside = ui.item.children('.widget-inside');
 284  
 285                  if ( inside.css('display') === 'block' ) {
 286                      ui.item.removeClass('open');
 287                      ui.item.find( '.widget-top button.widget-action' ).attr( 'aria-expanded', 'false' );
 288                      inside.hide();
 289                      $(this).sortable('refreshPositions');
 290                  }
 291  
 292                  if ( ! $wrap.hasClass('closed') ) {
 293                      // Lock all open sidebars min-height when starting to drag.
 294                      // Prevents jumping when dragging a widget from an open sidebar to a closed sidebar below.
 295                      height = ui.item.hasClass('ui-draggable') ? $this.height() : 1 + $this.height();
 296                      $this.css( 'min-height', height + 'px' );
 297                  }
 298              },
 299  
 300              stop: function( event, ui ) {
 301                  var addNew, widgetNumber, $sidebar, $children, child, item,
 302                      $widget = ui.item,
 303                      id = the_id;
 304  
 305                  // Reset the var to hold a previously closed sidebar.
 306                  wpWidgets.hoveredSidebar = null;
 307  
 308                  if ( $widget.hasClass('deleting') ) {
 309                      wpWidgets.save( $widget, 1, 0, 1 ); // Delete widget.
 310                      $widget.remove();
 311                      return;
 312                  }
 313  
 314                  addNew = $widget.find('input.add_new').val();
 315                  widgetNumber = $widget.find('input.multi_number').val();
 316  
 317                  $widget.attr( 'style', '' ).removeClass('ui-draggable');
 318                  the_id = '';
 319  
 320                  if ( addNew ) {
 321                      if ( 'multi' === addNew ) {
 322                          $widget.html(
 323                              $widget.html().replace( /<[^<>]+>/g, function( tag ) {
 324                                  return tag.replace( /__i__|%i%/g, widgetNumber );
 325                              })
 326                          );
 327  
 328                          $widget.attr( 'id', id.replace( '__i__', widgetNumber ) );
 329                          widgetNumber++;
 330  
 331                          $( 'div#' + id ).find( 'input.multi_number' ).val( widgetNumber );
 332                      } else if ( 'single' === addNew ) {
 333                          $widget.attr( 'id', 'new-' + id );
 334                          rem = 'div#' + id;
 335                      }
 336  
 337                      wpWidgets.save( $widget, 0, 0, 1 );
 338                      $widget.find('input.add_new').val('');
 339                      $document.trigger( 'widget-added', [ $widget ] );
 340                  }
 341  
 342                  $sidebar = $widget.parent();
 343  
 344                  if ( $sidebar.parent().hasClass('closed') ) {
 345                      $sidebar.parent()
 346                          .removeClass( 'closed' )
 347                          .find( '.handlediv' ).attr( 'aria-expanded', 'true' );
 348  
 349                      $children = $sidebar.children('.widget');
 350  
 351                      // Make sure the dropped widget is at the top.
 352                      if ( $children.length > 1 ) {
 353                          child = $children.get(0);
 354                          item = $widget.get(0);
 355  
 356                          if ( child.id && item.id && child.id !== item.id ) {
 357                              $( child ).before( $widget );
 358                          }
 359                      }
 360                  }
 361  
 362                  if ( addNew ) {
 363                      $widget.find( '.widget-action' ).trigger( 'click' );
 364                  } else {
 365                      wpWidgets.saveOrder( $sidebar.attr('id') );
 366                  }
 367              },
 368  
 369              activate: function() {
 370                  $(this).parent().addClass( 'widget-hover' );
 371              },
 372  
 373              deactivate: function() {
 374                  // Remove all min-height added on "start".
 375                  $(this).css( 'min-height', '' ).parent().removeClass( 'widget-hover' );
 376              },
 377  
 378              receive: function( event, ui ) {
 379                  var $sender = $( ui.sender );
 380  
 381                  // Don't add more widgets to orphaned sidebars.
 382                  if ( this.id.indexOf('orphaned_widgets') > -1 ) {
 383                      $sender.sortable('cancel');
 384                      return;
 385                  }
 386  
 387                  // If the last widget was moved out of an orphaned sidebar, close and remove it.
 388                  if ( $sender.attr('id').indexOf('orphaned_widgets') > -1 && ! $sender.children('.widget').length ) {
 389                      $sender.parents('.orphan-sidebar').slideUp( 400, function(){ $(this).remove(); } );
 390                  }
 391              }
 392          }).sortable( 'option', 'connectWith', 'div.widgets-sortables' );
 393  
 394          $('#available-widgets').droppable({
 395              tolerance: 'pointer',
 396              accept: function(o){
 397                  return $(o).parent().attr('id') !== 'widget-list';
 398              },
 399              drop: function(e,ui) {
 400                  ui.draggable.addClass('deleting');
 401                  $('#removing-widget').hide().children('span').empty();
 402              },
 403              over: function(e,ui) {
 404                  ui.draggable.addClass('deleting');
 405                  $('div.widget-placeholder').hide();
 406  
 407                  if ( ui.draggable.hasClass('ui-sortable-helper') ) {
 408                      $('#removing-widget').show().children('span')
 409                      .html( ui.draggable.find( 'div.widget-title' ).children( 'h3' ).html() );
 410                  }
 411              },
 412              out: function(e,ui) {
 413                  ui.draggable.removeClass('deleting');
 414                  $('div.widget-placeholder').show();
 415                  $('#removing-widget').hide().children('span').empty();
 416              }
 417          });
 418  
 419          // Area Chooser.
 420          $( '#widgets-right .widgets-holder-wrap' ).each( function( index, element ) {
 421              var $element = $( element ),
 422                  name = $element.find( '.sidebar-name h2' ).text() || '',
 423                  ariaLabel = $element.find( '.sidebar-name' ).data( 'add-to' ),
 424                  id = $element.find( '.widgets-sortables' ).attr( 'id' ),
 425                  li = $( '<li>' ),
 426                  button = $( '<button>', {
 427                      type: 'button',
 428                      'aria-pressed': 'false',
 429                      'class': 'widgets-chooser-button',
 430                      'aria-label': ariaLabel
 431                  } ).text( name.toString().trim() );
 432  
 433              li.append( button );
 434  
 435              if ( index === 0 ) {
 436                  li.addClass( 'widgets-chooser-selected' );
 437                  button.attr( 'aria-pressed', 'true' );
 438              }
 439  
 440              selectSidebar.append( li );
 441              li.data( 'sidebarId', id );
 442          });
 443  
 444          $( '#available-widgets .widget .widget-top' ).on( 'click.widgets-chooser', function() {
 445              var $widget = $( this ).closest( '.widget' ),
 446                  toggleButton = $( this ).find( '.widget-action' ),
 447                  chooserButtons = selectSidebar.find( '.widgets-chooser-button' );
 448  
 449              if ( $widget.hasClass( 'widget-in-question' ) || $( '#widgets-left' ).hasClass( 'chooser' ) ) {
 450                  toggleButton.attr( 'aria-expanded', 'false' );
 451                  self.closeChooser();
 452              } else {
 453                  // Open the chooser.
 454                  self.clearWidgetSelection();
 455                  $( '#widgets-left' ).addClass( 'chooser' );
 456                  // Add CSS class and insert the chooser after the widget description.
 457                  $widget.addClass( 'widget-in-question' ).children( '.widget-description' ).after( chooser );
 458                  // Open the chooser with a slide down animation.
 459                  chooser.slideDown( 300, function() {
 460                      // Update the toggle button aria-expanded attribute after previous DOM manipulations.
 461                      toggleButton.attr( 'aria-expanded', 'true' );
 462                  });
 463  
 464                  chooserButtons.on( 'click.widgets-chooser', function() {
 465                      selectSidebar.find( '.widgets-chooser-selected' ).removeClass( 'widgets-chooser-selected' );
 466                      chooserButtons.attr( 'aria-pressed', 'false' );
 467                      $( this )
 468                          .attr( 'aria-pressed', 'true' )
 469                          .closest( 'li' ).addClass( 'widgets-chooser-selected' );
 470                  } );
 471              }
 472          });
 473  
 474          // Add event handlers.
 475          chooser.on( 'click.widgets-chooser', function( event ) {
 476              var $target = $( event.target );
 477  
 478              if ( $target.hasClass('button-primary') ) {
 479                  self.addWidget( chooser );
 480                  self.closeChooser();
 481              } else if ( $target.hasClass( 'widgets-chooser-cancel' ) ) {
 482                  self.closeChooser();
 483              }
 484          }).on( 'keyup.widgets-chooser', function( event ) {
 485              if ( event.which === $.ui.keyCode.ESCAPE ) {
 486                  self.closeChooser();
 487              }
 488          });
 489      },
 490  
 491      saveOrder : function( sidebarId ) {
 492          var data = {
 493              action: 'widgets-order',
 494              savewidgets: $('#_wpnonce_widgets').val(),
 495              sidebars: []
 496          };
 497  
 498          if ( sidebarId ) {
 499              $( '#' + sidebarId ).find( '.spinner:first' ).addClass( 'is-active' );
 500          }
 501  
 502          $('div.widgets-sortables').each( function() {
 503              if ( $(this).sortable ) {
 504                  data['sidebars[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(',');
 505              }
 506          });
 507  
 508          $.post( ajaxurl, data, function() {
 509              $( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
 510              $( '.spinner' ).removeClass( 'is-active' );
 511          });
 512      },
 513  
 514      save : function( widget, del, animate, order ) {
 515          var self = this, data, a,
 516              sidebarId = widget.closest( 'div.widgets-sortables' ).attr( 'id' ),
 517              form = widget.find( 'form' ),
 518              isAdd = widget.find( 'input.add_new' ).val();
 519  
 520          if ( ! del && ! isAdd && form.prop( 'checkValidity' ) && ! form[0].checkValidity() ) {
 521              return;
 522          }
 523  
 524          data = form.serialize();
 525  
 526          widget = $(widget);
 527          $( '.spinner', widget ).addClass( 'is-active' );
 528  
 529          a = {
 530              action: 'save-widget',
 531              savewidgets: $('#_wpnonce_widgets').val(),
 532              sidebar: sidebarId
 533          };
 534  
 535          if ( del ) {
 536              a.delete_widget = 1;
 537          }
 538  
 539          data += '&' + $.param(a);
 540  
 541          $.post( ajaxurl, data, function(r) {
 542              var id = $('input.widget-id', widget).val();
 543  
 544              if ( del ) {
 545                  if ( ! $('input.widget_number', widget).val() ) {
 546                      $('#available-widgets').find('input.widget-id').each(function(){
 547                          if ( $(this).val() === id ) {
 548                              $(this).closest('div.widget').show();
 549                          }
 550                      });
 551                  }
 552  
 553                  if ( animate ) {
 554                      order = 0;
 555                      widget.slideUp( 'fast', function() {
 556                          $( this ).remove();
 557                          wpWidgets.saveOrder();
 558                          delete self.dirtyWidgets[ id ];
 559                      });
 560                  } else {
 561                      widget.remove();
 562                      delete self.dirtyWidgets[ id ];
 563  
 564                      if ( sidebarId === 'wp_inactive_widgets' ) {
 565                          $( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
 566                      }
 567                  }
 568              } else {
 569                  $( '.spinner' ).removeClass( 'is-active' );
 570                  if ( r && r.length > 2 ) {
 571                      $( 'div.widget-content', widget ).html( r );
 572                      wpWidgets.appendTitle( widget );
 573  
 574                      // Re-disable the save button.
 575                      widget.find( '.widget-control-save' ).prop( 'disabled', true ).val( wp.i18n.__( 'Saved' ) );
 576  
 577                      widget.removeClass( 'widget-dirty' );
 578  
 579                      // Clear the dirty flag from the widget.
 580                      delete self.dirtyWidgets[ id ];
 581  
 582                      $document.trigger( 'widget-updated', [ widget ] );
 583  
 584                      if ( sidebarId === 'wp_inactive_widgets' ) {
 585                          $( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
 586                      }
 587                  }
 588              }
 589  
 590              if ( order ) {
 591                  wpWidgets.saveOrder();
 592              }
 593          });
 594      },
 595  
 596      removeInactiveWidgets : function() {
 597          var $element = $( '.remove-inactive-widgets' ), self = this, a, data;
 598  
 599          $( '.spinner', $element ).addClass( 'is-active' );
 600  
 601          a = {
 602              action : 'delete-inactive-widgets',
 603              removeinactivewidgets : $( '#_wpnonce_remove_inactive_widgets' ).val()
 604          };
 605  
 606          data = $.param( a );
 607  
 608          $.post( ajaxurl, data, function() {
 609              $( '#wp_inactive_widgets .widget' ).each(function() {
 610                  var $widget = $( this );
 611                  delete self.dirtyWidgets[ $widget.find( 'input.widget-id' ).val() ];
 612                  $widget.remove();
 613              });
 614              $( '#inactive-widgets-control-remove' ).prop( 'disabled', true );
 615              $( '.spinner', $element ).removeClass( 'is-active' );
 616          } );
 617      },
 618  
 619      appendTitle : function(widget) {
 620          var title = $('input[id*="-title"]', widget).val() || '';
 621  
 622          if ( title ) {
 623              title = ': ' + title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;');
 624          }
 625  
 626          $(widget).children('.widget-top').children('.widget-title').children()
 627                  .children('.in-widget-title').html(title);
 628  
 629      },
 630  
 631      close : function(widget) {
 632          widget.children('.widget-inside').slideUp('fast', function() {
 633              widget.attr( 'style', '' )
 634                  .find( '.widget-top button.widget-action' )
 635                      .attr( 'aria-expanded', 'false' )
 636                      .focus();
 637          });
 638      },
 639  
 640      addWidget: function( chooser ) {
 641          var widget, widgetId, add, n, viewportTop, viewportBottom, sidebarBounds,
 642              sidebarId = chooser.find( '.widgets-chooser-selected' ).data('sidebarId'),
 643              sidebar = $( '#' + sidebarId );
 644  
 645          widget = $('#available-widgets').find('.widget-in-question').clone();
 646          widgetId = widget.attr('id');
 647          add = widget.find( 'input.add_new' ).val();
 648          n = widget.find( 'input.multi_number' ).val();
 649  
 650          // Remove the cloned chooser from the widget.
 651          widget.find('.widgets-chooser').remove();
 652  
 653          if ( 'multi' === add ) {
 654              widget.html(
 655                  widget.html().replace( /<[^<>]+>/g, function(m) {
 656                      return m.replace( /__i__|%i%/g, n );
 657                  })
 658              );
 659  
 660              widget.attr( 'id', widgetId.replace( '__i__', n ) );
 661              n++;
 662              $( '#' + widgetId ).find('input.multi_number').val(n);
 663          } else if ( 'single' === add ) {
 664              widget.attr( 'id', 'new-' + widgetId );
 665              $( '#' + widgetId ).hide();
 666          }
 667  
 668          // Open the widgets container.
 669          sidebar.closest( '.widgets-holder-wrap' )
 670              .removeClass( 'closed' )
 671              .find( '.handlediv' ).attr( 'aria-expanded', 'true' );
 672  
 673          sidebar.append( widget );
 674          sidebar.sortable('refresh');
 675  
 676          wpWidgets.save( widget, 0, 0, 1 );
 677          // No longer "new" widget.
 678          widget.find( 'input.add_new' ).val('');
 679  
 680          $document.trigger( 'widget-added', [ widget ] );
 681  
 682          /*
 683           * Check if any part of the sidebar is visible in the viewport. If it is, don't scroll.
 684           * Otherwise, scroll up to so the sidebar is in view.
 685           *
 686           * We do this by comparing the top and bottom, of the sidebar so see if they are within
 687           * the bounds of the viewport.
 688           */
 689          viewportTop = $(window).scrollTop();
 690          viewportBottom = viewportTop + $(window).height();
 691          sidebarBounds = sidebar.offset();
 692  
 693          sidebarBounds.bottom = sidebarBounds.top + sidebar.outerHeight();
 694  
 695          if ( viewportTop > sidebarBounds.bottom || viewportBottom < sidebarBounds.top ) {
 696              $( 'html, body' ).animate({
 697                  scrollTop: sidebarBounds.top - 130
 698              }, 200 );
 699          }
 700  
 701          window.setTimeout( function() {
 702              // Cannot use a callback in the animation above as it fires twice,
 703              // have to queue this "by hand".
 704              widget.find( '.widget-title' ).trigger('click');
 705              // At the end of the animation, announce the widget has been added.
 706              window.wp.a11y.speak( wp.i18n.__( 'Widget has been added to the selected sidebar' ), 'assertive' );
 707          }, 250 );
 708      },
 709  
 710      closeChooser: function() {
 711          var self = this,
 712              widgetInQuestion = $( '#available-widgets .widget-in-question' );
 713  
 714          $( '.widgets-chooser' ).slideUp( 200, function() {
 715              $( '#wpbody-content' ).append( this );
 716              self.clearWidgetSelection();
 717              // Move focus back to the toggle button.
 718              widgetInQuestion.find( '.widget-action' ).attr( 'aria-expanded', 'false' ).focus();
 719          });
 720      },
 721  
 722      clearWidgetSelection: function() {
 723          $( '#widgets-left' ).removeClass( 'chooser' );
 724          $( '.widget-in-question' ).removeClass( 'widget-in-question' );
 725      },
 726  
 727      /**
 728       * Closes a Sidebar that was previously closed, but opened by dragging a Widget over it.
 729       *
 730       * Used when a Widget gets dragged in/out of the Sidebar and never dropped.
 731       *
 732       * @param {Object} event jQuery event object.
 733       */
 734      closeSidebar: function( event ) {
 735          this.hoveredSidebar
 736              .addClass( 'closed' )
 737              .find( '.handlediv' ).attr( 'aria-expanded', 'false' );
 738  
 739          $( event.target ).css( 'min-height', '' );
 740          this.hoveredSidebar = null;
 741      }
 742  };
 743  
 744  $( function(){ wpWidgets.init(); } );
 745  
 746  })(jQuery);
 747  
 748  /**
 749   * Removed in 5.5.0, needed for back-compatibility.
 750   *
 751   * @since 4.9.0
 752   * @deprecated 5.5.0
 753   *
 754   * @type {object}
 755  */
 756  wpWidgets.l10n = wpWidgets.l10n || {
 757      save: '',
 758      saved: '',
 759      saveAlert: '',
 760      widgetAdded: ''
 761  };
 762  
 763  wpWidgets.l10n = window.wp.deprecateL10nObject( 'wpWidgets.l10n', wpWidgets.l10n, '5.5.0' );


Generated : Mon Mar 18 08:20:01 2024 Cross-referenced by PHPXref