]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-admin/js/widgets.js
Wordpress 4.6
[autoinstalls/wordpress.git] / wp-admin / js / widgets.js
1 /*global ajaxurl, isRtl */
2 var wpWidgets;
3 (function($) {
4         var $document = $( document );
5
6 wpWidgets = {
7         /**
8          * A closed Sidebar that gets a Widget dragged over it.
9          *
10          * @var element|null
11          */
12         hoveredSidebar: null,
13
14         init : function() {
15                 var rem, the_id,
16                         self = this,
17                         chooser = $('.widgets-chooser'),
18                         selectSidebar = chooser.find('.widgets-chooser-sidebars'),
19                         sidebars = $('div.widgets-sortables'),
20                         isRTL = !! ( 'undefined' !== typeof isRtl && isRtl );
21
22                 $('#widgets-right .sidebar-name').click( function() {
23                         var $this = $(this),
24                                 $wrap = $this.closest('.widgets-holder-wrap');
25
26                         if ( $wrap.hasClass('closed') ) {
27                                 $wrap.removeClass('closed');
28                                 $this.parent().sortable('refresh');
29                         } else {
30                                 $wrap.addClass('closed');
31                         }
32
33                         $document.triggerHandler( 'wp-pin-menu' );
34                 });
35
36                 $('#widgets-left .sidebar-name').click( function() {
37                         $(this).closest('.widgets-holder-wrap').toggleClass('closed');
38                         $document.triggerHandler( 'wp-pin-menu' );
39                 });
40
41                 $(document.body).bind('click.widgets-toggle', function(e) {
42                         var target = $(e.target),
43                                 css = { 'z-index': 100 },
44                                 widget, inside, targetWidth, widgetWidth, margin;
45
46                         if ( target.parents('.widget-top').length && ! target.parents('#available-widgets').length ) {
47                                 widget = target.closest('div.widget');
48                                 inside = widget.children('.widget-inside');
49                                 targetWidth = parseInt( widget.find('input.widget-width').val(), 10 ),
50                                 widgetWidth = widget.parent().width();
51
52                                 if ( inside.is(':hidden') ) {
53                                         if ( targetWidth > 250 && ( targetWidth + 30 > widgetWidth ) && widget.closest('div.widgets-sortables').length ) {
54                                                 if ( widget.closest('div.widget-liquid-right').length ) {
55                                                         margin = isRTL ? 'margin-right' : 'margin-left';
56                                                 } else {
57                                                         margin = isRTL ? 'margin-left' : 'margin-right';
58                                                 }
59
60                                                 css[ margin ] = widgetWidth - ( targetWidth + 30 ) + 'px';
61                                                 widget.css( css );
62                                         }
63                                         widget.addClass( 'open' );
64                                         inside.slideDown('fast');
65                                 } else {
66                                         inside.slideUp('fast', function() {
67                                                 widget.attr( 'style', '' );
68                                                 widget.removeClass( 'open' );
69                                         });
70                                 }
71                                 e.preventDefault();
72                         } else if ( target.hasClass('widget-control-save') ) {
73                                 wpWidgets.save( target.closest('div.widget'), 0, 1, 0 );
74                                 e.preventDefault();
75                         } else if ( target.hasClass('widget-control-remove') ) {
76                                 wpWidgets.save( target.closest('div.widget'), 1, 1, 0 );
77                                 e.preventDefault();
78                         } else if ( target.hasClass('widget-control-close') ) {
79                                 widget = target.closest('div.widget');
80                                 widget.removeClass( 'open' );
81                                 wpWidgets.close( widget );
82                                 e.preventDefault();
83                         } else if ( target.attr( 'id' ) === 'inactive-widgets-control-remove' ) {
84                                 wpWidgets.removeInactiveWidgets();
85                                 e.preventDefault();
86                         }
87                 });
88
89                 sidebars.children('.widget').each( function() {
90                         var $this = $(this);
91
92                         wpWidgets.appendTitle( this );
93
94                         if ( $this.find( 'p.widget-error' ).length ) {
95                                 $this.find( 'a.widget-action' ).trigger('click');
96                         }
97                 });
98
99                 $('#widget-list').children('.widget').draggable({
100                         connectToSortable: 'div.widgets-sortables',
101                         handle: '> .widget-top > .widget-title',
102                         distance: 2,
103                         helper: 'clone',
104                         zIndex: 100,
105                         containment: '#wpwrap',
106                         refreshPositions: true,
107                         start: function( event, ui ) {
108                                 var chooser = $(this).find('.widgets-chooser');
109
110                                 ui.helper.find('div.widget-description').hide();
111                                 the_id = this.id;
112
113                                 if ( chooser.length ) {
114                                         // Hide the chooser and move it out of the widget
115                                         $( '#wpbody-content' ).append( chooser.hide() );
116                                         // Delete the cloned chooser from the drag helper
117                                         ui.helper.find('.widgets-chooser').remove();
118                                         self.clearWidgetSelection();
119                                 }
120                         },
121                         stop: function() {
122                                 if ( rem ) {
123                                         $(rem).hide();
124                                 }
125
126                                 rem = '';
127                         }
128                 });
129
130                 /**
131                  * Opens and closes previously closed Sidebars when Widgets are dragged over/out of them.
132                  */
133                 sidebars.droppable( {
134                         tolerance: 'intersect',
135
136                         /**
137                          * Open Sidebar when a Widget gets dragged over it.
138                          *
139                          * @param event
140                          */
141                         over: function( event ) {
142                                 var $wrap = $( event.target ).parent();
143
144                                 if ( wpWidgets.hoveredSidebar && ! $wrap.is( wpWidgets.hoveredSidebar ) ) {
145                                         // Close the previous Sidebar as the Widget has been dragged onto another Sidebar.
146                                         wpWidgets.closeSidebar( event );
147                                 }
148
149                                 if ( $wrap.hasClass( 'closed' ) ) {
150                                         wpWidgets.hoveredSidebar = $wrap;
151                                         $wrap.removeClass( 'closed' );
152                                 }
153
154                                 $( this ).sortable( 'refresh' );
155                         },
156
157                         /**
158                          * Close Sidebar when the Widget gets dragged out of it.
159                          *
160                          * @param event
161                          */
162                         out: function( event ) {
163                                 if ( wpWidgets.hoveredSidebar ) {
164                                         wpWidgets.closeSidebar( event );
165                                 }
166                         }
167                 } );
168
169                 sidebars.sortable({
170                         placeholder: 'widget-placeholder',
171                         items: '> .widget',
172                         handle: '> .widget-top > .widget-title',
173                         cursor: 'move',
174                         distance: 2,
175                         containment: '#wpwrap',
176                         tolerance: 'pointer',
177                         refreshPositions: true,
178                         start: function( event, ui ) {
179                                 var height, $this = $(this),
180                                         $wrap = $this.parent(),
181                                         inside = ui.item.children('.widget-inside');
182
183                                 if ( inside.css('display') === 'block' ) {
184                                         ui.item.removeClass('open');
185                                         inside.hide();
186                                         $(this).sortable('refreshPositions');
187                                 }
188
189                                 if ( ! $wrap.hasClass('closed') ) {
190                                         // Lock all open sidebars min-height when starting to drag.
191                                         // Prevents jumping when dragging a widget from an open sidebar to a closed sidebar below.
192                                         height = ui.item.hasClass('ui-draggable') ? $this.height() : 1 + $this.height();
193                                         $this.css( 'min-height', height + 'px' );
194                                 }
195                         },
196
197                         stop: function( event, ui ) {
198                                 var addNew, widgetNumber, $sidebar, $children, child, item,
199                                         $widget = ui.item,
200                                         id = the_id;
201
202                                 // Reset the var to hold a previously closed sidebar.
203                                 wpWidgets.hoveredSidebar = null;
204
205                                 if ( $widget.hasClass('deleting') ) {
206                                         wpWidgets.save( $widget, 1, 0, 1 ); // delete widget
207                                         $widget.remove();
208                                         return;
209                                 }
210
211                                 addNew = $widget.find('input.add_new').val();
212                                 widgetNumber = $widget.find('input.multi_number').val();
213
214                                 $widget.attr( 'style', '' ).removeClass('ui-draggable');
215                                 the_id = '';
216
217                                 if ( addNew ) {
218                                         if ( 'multi' === addNew ) {
219                                                 $widget.html(
220                                                         $widget.html().replace( /<[^<>]+>/g, function( tag ) {
221                                                                 return tag.replace( /__i__|%i%/g, widgetNumber );
222                                                         })
223                                                 );
224
225                                                 $widget.attr( 'id', id.replace( '__i__', widgetNumber ) );
226                                                 widgetNumber++;
227
228                                                 $( 'div#' + id ).find( 'input.multi_number' ).val( widgetNumber );
229                                         } else if ( 'single' === addNew ) {
230                                                 $widget.attr( 'id', 'new-' + id );
231                                                 rem = 'div#' + id;
232                                         }
233
234                                         wpWidgets.save( $widget, 0, 0, 1 );
235                                         $widget.find('input.add_new').val('');
236                                         $document.trigger( 'widget-added', [ $widget ] );
237                                 }
238
239                                 $sidebar = $widget.parent();
240
241                                 if ( $sidebar.parent().hasClass('closed') ) {
242                                         $sidebar.parent().removeClass('closed');
243                                         $children = $sidebar.children('.widget');
244
245                                         // Make sure the dropped widget is at the top
246                                         if ( $children.length > 1 ) {
247                                                 child = $children.get(0);
248                                                 item = $widget.get(0);
249
250                                                 if ( child.id && item.id && child.id !== item.id ) {
251                                                         $( child ).before( $widget );
252                                                 }
253                                         }
254                                 }
255
256                                 if ( addNew ) {
257                                         $widget.find( 'a.widget-action' ).trigger('click');
258                                 } else {
259                                         wpWidgets.saveOrder( $sidebar.attr('id') );
260                                 }
261                         },
262
263                         activate: function() {
264                                 $(this).parent().addClass( 'widget-hover' );
265                         },
266
267                         deactivate: function() {
268                                 // Remove all min-height added on "start"
269                                 $(this).css( 'min-height', '' ).parent().removeClass( 'widget-hover' );
270                         },
271
272                         receive: function( event, ui ) {
273                                 var $sender = $( ui.sender );
274
275                                 // Don't add more widgets to orphaned sidebars
276                                 if ( this.id.indexOf('orphaned_widgets') > -1 ) {
277                                         $sender.sortable('cancel');
278                                         return;
279                                 }
280
281                                 // If the last widget was moved out of an orphaned sidebar, close and remove it.
282                                 if ( $sender.attr('id').indexOf('orphaned_widgets') > -1 && ! $sender.children('.widget').length ) {
283                                         $sender.parents('.orphan-sidebar').slideUp( 400, function(){ $(this).remove(); } );
284                                 }
285                         }
286                 }).sortable( 'option', 'connectWith', 'div.widgets-sortables' );
287
288                 $('#available-widgets').droppable({
289                         tolerance: 'pointer',
290                         accept: function(o){
291                                 return $(o).parent().attr('id') !== 'widget-list';
292                         },
293                         drop: function(e,ui) {
294                                 ui.draggable.addClass('deleting');
295                                 $('#removing-widget').hide().children('span').empty();
296                         },
297                         over: function(e,ui) {
298                                 ui.draggable.addClass('deleting');
299                                 $('div.widget-placeholder').hide();
300
301                                 if ( ui.draggable.hasClass('ui-sortable-helper') ) {
302                                         $('#removing-widget').show().children('span')
303                                         .html( ui.draggable.find( 'div.widget-title' ).children( 'h3' ).html() );
304                                 }
305                         },
306                         out: function(e,ui) {
307                                 ui.draggable.removeClass('deleting');
308                                 $('div.widget-placeholder').show();
309                                 $('#removing-widget').hide().children('span').empty();
310                         }
311                 });
312
313                 // Area Chooser
314                 $( '#widgets-right .widgets-holder-wrap' ).each( function( index, element ) {
315                         var $element = $( element ),
316                                 name = $element.find( '.sidebar-name h2' ).text(),
317                                 id = $element.find( '.widgets-sortables' ).attr( 'id' ),
318                                 li = $('<li tabindex="0">').text( $.trim( name ) );
319
320                         if ( index === 0 ) {
321                                 li.addClass( 'widgets-chooser-selected' );
322                         }
323
324                         selectSidebar.append( li );
325                         li.data( 'sidebarId', id );
326                 });
327
328                 $( '#available-widgets .widget .widget-title' ).on( 'click.widgets-chooser', function() {
329                         var $widget = $(this).closest( '.widget' );
330
331                         if ( $widget.hasClass( 'widget-in-question' ) || $( '#widgets-left' ).hasClass( 'chooser' ) ) {
332                                 self.closeChooser();
333                         } else {
334                                 // Open the chooser
335                                 self.clearWidgetSelection();
336                                 $( '#widgets-left' ).addClass( 'chooser' );
337                                 $widget.addClass( 'widget-in-question' ).children( '.widget-description' ).after( chooser );
338
339                                 chooser.slideDown( 300, function() {
340                                         selectSidebar.find('.widgets-chooser-selected').focus();
341                                 });
342
343                                 selectSidebar.find( 'li' ).on( 'focusin.widgets-chooser', function() {
344                                         selectSidebar.find('.widgets-chooser-selected').removeClass( 'widgets-chooser-selected' );
345                                         $(this).addClass( 'widgets-chooser-selected' );
346                                 } );
347                         }
348                 });
349
350                 // Add event handlers
351                 chooser.on( 'click.widgets-chooser', function( event ) {
352                         var $target = $( event.target );
353
354                         if ( $target.hasClass('button-primary') ) {
355                                 self.addWidget( chooser );
356                                 self.closeChooser();
357                         } else if ( $target.hasClass('button-secondary') ) {
358                                 self.closeChooser();
359                         }
360                 }).on( 'keyup.widgets-chooser', function( event ) {
361                         if ( event.which === $.ui.keyCode.ENTER ) {
362                                 if ( $( event.target ).hasClass('button-secondary') ) {
363                                         // Close instead of adding when pressing Enter on the Cancel button
364                                         self.closeChooser();
365                                 } else {
366                                         self.addWidget( chooser );
367                                         self.closeChooser();
368                                 }
369                         } else if ( event.which === $.ui.keyCode.ESCAPE ) {
370                                 self.closeChooser();
371                         }
372                 });
373         },
374
375         saveOrder : function( sidebarId ) {
376                 var data = {
377                         action: 'widgets-order',
378                         savewidgets: $('#_wpnonce_widgets').val(),
379                         sidebars: []
380                 };
381
382                 if ( sidebarId ) {
383                         $( '#' + sidebarId ).find( '.spinner:first' ).addClass( 'is-active' );
384                 }
385
386                 $('div.widgets-sortables').each( function() {
387                         if ( $(this).sortable ) {
388                                 data['sidebars[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(',');
389                         }
390                 });
391
392                 $.post( ajaxurl, data, function() {
393                         $( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
394                         $( '.spinner' ).removeClass( 'is-active' );
395                 });
396         },
397
398         save : function( widget, del, animate, order ) {
399                 var sidebarId = widget.closest('div.widgets-sortables').attr('id'),
400                         data = widget.find('form').serialize(), a;
401
402                 widget = $(widget);
403                 $( '.spinner', widget ).addClass( 'is-active' );
404
405                 a = {
406                         action: 'save-widget',
407                         savewidgets: $('#_wpnonce_widgets').val(),
408                         sidebar: sidebarId
409                 };
410
411                 if ( del ) {
412                         a.delete_widget = 1;
413                 }
414
415                 data += '&' + $.param(a);
416
417                 $.post( ajaxurl, data, function(r) {
418                         var id;
419
420                         if ( del ) {
421                                 if ( ! $('input.widget_number', widget).val() ) {
422                                         id = $('input.widget-id', widget).val();
423                                         $('#available-widgets').find('input.widget-id').each(function(){
424                                                 if ( $(this).val() === id ) {
425                                                         $(this).closest('div.widget').show();
426                                                 }
427                                         });
428                                 }
429
430                                 if ( animate ) {
431                                         order = 0;
432                                         widget.slideUp('fast', function(){
433                                                 $(this).remove();
434                                                 wpWidgets.saveOrder();
435                                         });
436                                 } else {
437                                         widget.remove();
438
439                                         if ( sidebarId === 'wp_inactive_widgets' ) {
440                                                 $( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
441                                         }
442                                 }
443                         } else {
444                                 $( '.spinner' ).removeClass( 'is-active' );
445                                 if ( r && r.length > 2 ) {
446                                         $( 'div.widget-content', widget ).html( r );
447                                         wpWidgets.appendTitle( widget );
448                                         $document.trigger( 'widget-updated', [ widget ] );
449
450                                         if ( sidebarId === 'wp_inactive_widgets' ) {
451                                                 $( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
452                                         }
453                                 }
454                         }
455
456                         if ( order ) {
457                                 wpWidgets.saveOrder();
458                         }
459                 });
460         },
461
462         removeInactiveWidgets : function() {
463                 var $element = $( '.remove-inactive-widgets' ), a, data;
464
465                 $( '.spinner', $element ).addClass( 'is-active' );
466
467                 a = {
468                         action : 'delete-inactive-widgets',
469                         removeinactivewidgets : $( '#_wpnonce_remove_inactive_widgets' ).val()
470                 };
471
472                 data = $.param( a );
473
474                 $.post( ajaxurl, data, function() {
475                         $( '#wp_inactive_widgets .widget' ).remove();
476                         $( '#inactive-widgets-control-remove' ).prop( 'disabled' , true );
477                         $( '.spinner', $element ).removeClass( 'is-active' );
478                 } );
479         },
480
481         appendTitle : function(widget) {
482                 var title = $('input[id*="-title"]', widget).val() || '';
483
484                 if ( title ) {
485                         title = ': ' + title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;');
486                 }
487
488                 $(widget).children('.widget-top').children('.widget-title').children()
489                                 .children('.in-widget-title').html(title);
490
491         },
492
493         close : function(widget) {
494                 widget.children('.widget-inside').slideUp('fast', function() {
495                         widget.attr( 'style', '' );
496                 });
497         },
498
499         addWidget: function( chooser ) {
500                 var widget, widgetId, add, n, viewportTop, viewportBottom, sidebarBounds,
501                         sidebarId = chooser.find( '.widgets-chooser-selected' ).data('sidebarId'),
502                         sidebar = $( '#' + sidebarId );
503
504                 widget = $('#available-widgets').find('.widget-in-question').clone();
505                 widgetId = widget.attr('id');
506                 add = widget.find( 'input.add_new' ).val();
507                 n = widget.find( 'input.multi_number' ).val();
508
509                 // Remove the cloned chooser from the widget
510                 widget.find('.widgets-chooser').remove();
511
512                 if ( 'multi' === add ) {
513                         widget.html(
514                                 widget.html().replace( /<[^<>]+>/g, function(m) {
515                                         return m.replace( /__i__|%i%/g, n );
516                                 })
517                         );
518
519                         widget.attr( 'id', widgetId.replace( '__i__', n ) );
520                         n++;
521                         $( '#' + widgetId ).find('input.multi_number').val(n);
522                 } else if ( 'single' === add ) {
523                         widget.attr( 'id', 'new-' + widgetId );
524                         $( '#' + widgetId ).hide();
525                 }
526
527                 // Open the widgets container
528                 sidebar.closest( '.widgets-holder-wrap' ).removeClass('closed');
529
530                 sidebar.append( widget );
531                 sidebar.sortable('refresh');
532
533                 wpWidgets.save( widget, 0, 0, 1 );
534                 // No longer "new" widget
535                 widget.find( 'input.add_new' ).val('');
536
537                 $document.trigger( 'widget-added', [ widget ] );
538
539                 /*
540                  * Check if any part of the sidebar is visible in the viewport. If it is, don't scroll.
541                  * Otherwise, scroll up to so the sidebar is in view.
542                  *
543                  * We do this by comparing the top and bottom, of the sidebar so see if they are within
544                  * the bounds of the viewport.
545                  */
546                 viewportTop = $(window).scrollTop();
547                 viewportBottom = viewportTop + $(window).height();
548                 sidebarBounds = sidebar.offset();
549
550                 sidebarBounds.bottom = sidebarBounds.top + sidebar.outerHeight();
551
552                 if ( viewportTop > sidebarBounds.bottom || viewportBottom < sidebarBounds.top ) {
553                         $( 'html, body' ).animate({
554                                 scrollTop: sidebarBounds.top - 130
555                         }, 200 );
556                 }
557
558                 window.setTimeout( function() {
559                         // Cannot use a callback in the animation above as it fires twice,
560                         // have to queue this "by hand".
561                         widget.find( '.widget-title' ).trigger('click');
562                 }, 250 );
563         },
564
565         closeChooser: function() {
566                 var self = this;
567
568                 $( '.widgets-chooser' ).slideUp( 200, function() {
569                         $( '#wpbody-content' ).append( this );
570                         self.clearWidgetSelection();
571                 });
572         },
573
574         clearWidgetSelection: function() {
575                 $( '#widgets-left' ).removeClass( 'chooser' );
576                 $( '.widget-in-question' ).removeClass( 'widget-in-question' );
577         },
578
579         /**
580          * Closes a Sidebar that was previously closed, but opened by dragging a Widget over it.
581          *
582          * Used when a Widget gets dragged in/out of the Sidebar and never dropped.
583          *
584          * @param sidebar
585          */
586         closeSidebar: function( sidebar ) {
587                 this.hoveredSidebar.addClass( 'closed' );
588                 $( sidebar.target ).css( 'min-height', '' );
589                 this.hoveredSidebar = null;
590         }
591 };
592
593 $document.ready( function(){ wpWidgets.init(); } );
594
595 })(jQuery);