]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-admin/js/nav-menu.js
WordPress 4.5
[autoinstalls/wordpress.git] / wp-admin / js / nav-menu.js
1 /**
2  * WordPress Administration Navigation Menu
3  * Interface JS functions
4  *
5  * @version 2.0.0
6  *
7  * @package WordPress
8  * @subpackage Administration
9  */
10
11 /* global menus, postboxes, columns, isRtl, navMenuL10n, ajaxurl */
12
13 var wpNavMenu;
14
15 (function($) {
16
17         var api;
18
19         api = wpNavMenu = {
20
21                 options : {
22                         menuItemDepthPerLevel : 30, // Do not use directly. Use depthToPx and pxToDepth instead.
23                         globalMaxDepth:  11,
24                         sortableItems:   '> *',
25                         targetTolerance: 0
26                 },
27
28                 menuList : undefined,   // Set in init.
29                 targetList : undefined, // Set in init.
30                 menusChanged : false,
31                 isRTL: !! ( 'undefined' != typeof isRtl && isRtl ),
32                 negateIfRTL: ( 'undefined' != typeof isRtl && isRtl ) ? -1 : 1,
33                 lastSearch: '',
34
35                 // Functions that run on init.
36                 init : function() {
37                         api.menuList = $('#menu-to-edit');
38                         api.targetList = api.menuList;
39
40                         this.jQueryExtensions();
41
42                         this.attachMenuEditListeners();
43
44                         this.attachQuickSearchListeners();
45                         this.attachThemeLocationsListeners();
46                         this.attachMenuSaveSubmitListeners();
47
48                         this.attachTabsPanelListeners();
49
50                         this.attachUnsavedChangesListener();
51
52                         if ( api.menuList.length )
53                                 this.initSortables();
54
55                         if ( menus.oneThemeLocationNoMenus )
56                                 $( '#posttype-page' ).addSelectedToMenu( api.addMenuItemToBottom );
57
58                         this.initManageLocations();
59
60                         this.initAccessibility();
61
62                         this.initToggles();
63
64                         this.initPreviewing();
65                 },
66
67                 jQueryExtensions : function() {
68                         // jQuery extensions
69                         $.fn.extend({
70                                 menuItemDepth : function() {
71                                         var margin = api.isRTL ? this.eq(0).css('margin-right') : this.eq(0).css('margin-left');
72                                         return api.pxToDepth( margin && -1 != margin.indexOf('px') ? margin.slice(0, -2) : 0 );
73                                 },
74                                 updateDepthClass : function(current, prev) {
75                                         return this.each(function(){
76                                                 var t = $(this);
77                                                 prev = prev || t.menuItemDepth();
78                                                 $(this).removeClass('menu-item-depth-'+ prev )
79                                                         .addClass('menu-item-depth-'+ current );
80                                         });
81                                 },
82                                 shiftDepthClass : function(change) {
83                                         return this.each(function(){
84                                                 var t = $(this),
85                                                         depth = t.menuItemDepth();
86                                                 $(this).removeClass('menu-item-depth-'+ depth )
87                                                         .addClass('menu-item-depth-'+ (depth + change) );
88                                         });
89                                 },
90                                 childMenuItems : function() {
91                                         var result = $();
92                                         this.each(function(){
93                                                 var t = $(this), depth = t.menuItemDepth(), next = t.next( '.menu-item' );
94                                                 while( next.length && next.menuItemDepth() > depth ) {
95                                                         result = result.add( next );
96                                                         next = next.next( '.menu-item' );
97                                                 }
98                                         });
99                                         return result;
100                                 },
101                                 shiftHorizontally : function( dir ) {
102                                         return this.each(function(){
103                                                 var t = $(this),
104                                                         depth = t.menuItemDepth(),
105                                                         newDepth = depth + dir;
106
107                                                 // Change .menu-item-depth-n class
108                                                 t.moveHorizontally( newDepth, depth );
109                                         });
110                                 },
111                                 moveHorizontally : function( newDepth, depth ) {
112                                         return this.each(function(){
113                                                 var t = $(this),
114                                                         children = t.childMenuItems(),
115                                                         diff = newDepth - depth,
116                                                         subItemText = t.find('.is-submenu');
117
118                                                 // Change .menu-item-depth-n class
119                                                 t.updateDepthClass( newDepth, depth ).updateParentMenuItemDBId();
120
121                                                 // If it has children, move those too
122                                                 if ( children ) {
123                                                         children.each(function() {
124                                                                 var t = $(this),
125                                                                         thisDepth = t.menuItemDepth(),
126                                                                         newDepth = thisDepth + diff;
127                                                                 t.updateDepthClass(newDepth, thisDepth).updateParentMenuItemDBId();
128                                                         });
129                                                 }
130
131                                                 // Show "Sub item" helper text
132                                                 if (0 === newDepth)
133                                                         subItemText.hide();
134                                                 else
135                                                         subItemText.show();
136                                         });
137                                 },
138                                 updateParentMenuItemDBId : function() {
139                                         return this.each(function(){
140                                                 var item = $(this),
141                                                         input = item.find( '.menu-item-data-parent-id' ),
142                                                         depth = parseInt( item.menuItemDepth(), 10 ),
143                                                         parentDepth = depth - 1,
144                                                         parent = item.prevAll( '.menu-item-depth-' + parentDepth ).first();
145
146                                                 if ( 0 === depth ) { // Item is on the top level, has no parent
147                                                         input.val(0);
148                                                 } else { // Find the parent item, and retrieve its object id.
149                                                         input.val( parent.find( '.menu-item-data-db-id' ).val() );
150                                                 }
151                                         });
152                                 },
153                                 hideAdvancedMenuItemFields : function() {
154                                         return this.each(function(){
155                                                 var that = $(this);
156                                                 $('.hide-column-tog').not(':checked').each(function(){
157                                                         that.find('.field-' + $(this).val() ).addClass('hidden-field');
158                                                 });
159                                         });
160                                 },
161                                 /**
162                                  * Adds selected menu items to the menu.
163                                  *
164                                  * @param jQuery metabox The metabox jQuery object.
165                                  */
166                                 addSelectedToMenu : function(processMethod) {
167                                         if ( 0 === $('#menu-to-edit').length ) {
168                                                 return false;
169                                         }
170
171                                         return this.each(function() {
172                                                 var t = $(this), menuItems = {},
173                                                         checkboxes = ( menus.oneThemeLocationNoMenus && 0 === t.find( '.tabs-panel-active .categorychecklist li input:checked' ).length ) ? t.find( '#page-all li input[type="checkbox"]' ) : t.find( '.tabs-panel-active .categorychecklist li input:checked' ),
174                                                         re = /menu-item\[([^\]]*)/;
175
176                                                 processMethod = processMethod || api.addMenuItemToBottom;
177
178                                                 // If no items are checked, bail.
179                                                 if ( !checkboxes.length )
180                                                         return false;
181
182                                                 // Show the ajax spinner
183                                                 t.find( '.button-controls .spinner' ).addClass( 'is-active' );
184
185                                                 // Retrieve menu item data
186                                                 $(checkboxes).each(function(){
187                                                         var t = $(this),
188                                                                 listItemDBIDMatch = re.exec( t.attr('name') ),
189                                                                 listItemDBID = 'undefined' == typeof listItemDBIDMatch[1] ? 0 : parseInt(listItemDBIDMatch[1], 10);
190
191                                                         if ( this.className && -1 != this.className.indexOf('add-to-top') )
192                                                                 processMethod = api.addMenuItemToTop;
193                                                         menuItems[listItemDBID] = t.closest('li').getItemData( 'add-menu-item', listItemDBID );
194                                                 });
195
196                                                 // Add the items
197                                                 api.addItemToMenu(menuItems, processMethod, function(){
198                                                         // Deselect the items and hide the ajax spinner
199                                                         checkboxes.removeAttr('checked');
200                                                         t.find( '.button-controls .spinner' ).removeClass( 'is-active' );
201                                                 });
202                                         });
203                                 },
204                                 getItemData : function( itemType, id ) {
205                                         itemType = itemType || 'menu-item';
206
207                                         var itemData = {}, i,
208                                         fields = [
209                                                 'menu-item-db-id',
210                                                 'menu-item-object-id',
211                                                 'menu-item-object',
212                                                 'menu-item-parent-id',
213                                                 'menu-item-position',
214                                                 'menu-item-type',
215                                                 'menu-item-title',
216                                                 'menu-item-url',
217                                                 'menu-item-description',
218                                                 'menu-item-attr-title',
219                                                 'menu-item-target',
220                                                 'menu-item-classes',
221                                                 'menu-item-xfn'
222                                         ];
223
224                                         if( !id && itemType == 'menu-item' ) {
225                                                 id = this.find('.menu-item-data-db-id').val();
226                                         }
227
228                                         if( !id ) return itemData;
229
230                                         this.find('input').each(function() {
231                                                 var field;
232                                                 i = fields.length;
233                                                 while ( i-- ) {
234                                                         if( itemType == 'menu-item' )
235                                                                 field = fields[i] + '[' + id + ']';
236                                                         else if( itemType == 'add-menu-item' )
237                                                                 field = 'menu-item[' + id + '][' + fields[i] + ']';
238
239                                                         if (
240                                                                 this.name &&
241                                                                 field == this.name
242                                                         ) {
243                                                                 itemData[fields[i]] = this.value;
244                                                         }
245                                                 }
246                                         });
247
248                                         return itemData;
249                                 },
250                                 setItemData : function( itemData, itemType, id ) { // Can take a type, such as 'menu-item', or an id.
251                                         itemType = itemType || 'menu-item';
252
253                                         if( !id && itemType == 'menu-item' ) {
254                                                 id = $('.menu-item-data-db-id', this).val();
255                                         }
256
257                                         if( !id ) return this;
258
259                                         this.find('input').each(function() {
260                                                 var t = $(this), field;
261                                                 $.each( itemData, function( attr, val ) {
262                                                         if( itemType == 'menu-item' )
263                                                                 field = attr + '[' + id + ']';
264                                                         else if( itemType == 'add-menu-item' )
265                                                                 field = 'menu-item[' + id + '][' + attr + ']';
266
267                                                         if ( field == t.attr('name') ) {
268                                                                 t.val( val );
269                                                         }
270                                                 });
271                                         });
272                                         return this;
273                                 }
274                         });
275                 },
276
277                 countMenuItems : function( depth ) {
278                         return $( '.menu-item-depth-' + depth ).length;
279                 },
280
281                 moveMenuItem : function( $this, dir ) {
282
283                         var items, newItemPosition, newDepth,
284                                 menuItems = $( '#menu-to-edit li' ),
285                                 menuItemsCount = menuItems.length,
286                                 thisItem = $this.parents( 'li.menu-item' ),
287                                 thisItemChildren = thisItem.childMenuItems(),
288                                 thisItemData = thisItem.getItemData(),
289                                 thisItemDepth = parseInt( thisItem.menuItemDepth(), 10 ),
290                                 thisItemPosition = parseInt( thisItem.index(), 10 ),
291                                 nextItem = thisItem.next(),
292                                 nextItemChildren = nextItem.childMenuItems(),
293                                 nextItemDepth = parseInt( nextItem.menuItemDepth(), 10 ) + 1,
294                                 prevItem = thisItem.prev(),
295                                 prevItemDepth = parseInt( prevItem.menuItemDepth(), 10 ),
296                                 prevItemId = prevItem.getItemData()['menu-item-db-id'];
297
298                         switch ( dir ) {
299                         case 'up':
300                                 newItemPosition = thisItemPosition - 1;
301
302                                 // Already at top
303                                 if ( 0 === thisItemPosition )
304                                         break;
305
306                                 // If a sub item is moved to top, shift it to 0 depth
307                                 if ( 0 === newItemPosition && 0 !== thisItemDepth )
308                                         thisItem.moveHorizontally( 0, thisItemDepth );
309
310                                 // If prev item is sub item, shift to match depth
311                                 if ( 0 !== prevItemDepth )
312                                         thisItem.moveHorizontally( prevItemDepth, thisItemDepth );
313
314                                 // Does this item have sub items?
315                                 if ( thisItemChildren ) {
316                                         items = thisItem.add( thisItemChildren );
317                                         // Move the entire block
318                                         items.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
319                                 } else {
320                                         thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
321                                 }
322                                 break;
323                         case 'down':
324                                 // Does this item have sub items?
325                                 if ( thisItemChildren ) {
326                                         items = thisItem.add( thisItemChildren ),
327                                                 nextItem = menuItems.eq( items.length + thisItemPosition ),
328                                                 nextItemChildren = 0 !== nextItem.childMenuItems().length;
329
330                                         if ( nextItemChildren ) {
331                                                 newDepth = parseInt( nextItem.menuItemDepth(), 10 ) + 1;
332                                                 thisItem.moveHorizontally( newDepth, thisItemDepth );
333                                         }
334
335                                         // Have we reached the bottom?
336                                         if ( menuItemsCount === thisItemPosition + items.length )
337                                                 break;
338
339                                         items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) ).updateParentMenuItemDBId();
340                                 } else {
341                                         // If next item has sub items, shift depth
342                                         if ( 0 !== nextItemChildren.length )
343                                                 thisItem.moveHorizontally( nextItemDepth, thisItemDepth );
344
345                                         // Have we reached the bottom
346                                         if ( menuItemsCount === thisItemPosition + 1 )
347                                                 break;
348                                         thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) ).updateParentMenuItemDBId();
349                                 }
350                                 break;
351                         case 'top':
352                                 // Already at top
353                                 if ( 0 === thisItemPosition )
354                                         break;
355                                 // Does this item have sub items?
356                                 if ( thisItemChildren ) {
357                                         items = thisItem.add( thisItemChildren );
358                                         // Move the entire block
359                                         items.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
360                                 } else {
361                                         thisItem.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
362                                 }
363                                 break;
364                         case 'left':
365                                 // As far left as possible
366                                 if ( 0 === thisItemDepth )
367                                         break;
368                                 thisItem.shiftHorizontally( -1 );
369                                 break;
370                         case 'right':
371                                 // Can't be sub item at top
372                                 if ( 0 === thisItemPosition )
373                                         break;
374                                 // Already sub item of prevItem
375                                 if ( thisItemData['menu-item-parent-id'] === prevItemId )
376                                         break;
377                                 thisItem.shiftHorizontally( 1 );
378                                 break;
379                         }
380                         $this.focus();
381                         api.registerChange();
382                         api.refreshKeyboardAccessibility();
383                         api.refreshAdvancedAccessibility();
384                 },
385
386                 initAccessibility : function() {
387                         var menu = $( '#menu-to-edit' );
388
389                         api.refreshKeyboardAccessibility();
390                         api.refreshAdvancedAccessibility();
391
392                         // Refresh the accessibility when the user comes close to the item in any way
393                         menu.on( 'mouseenter.refreshAccessibility focus.refreshAccessibility touchstart.refreshAccessibility' , '.menu-item' , function(){
394                                 api.refreshAdvancedAccessibilityOfItem( $( this ).find( 'a.item-edit' ) );
395                         } );
396
397                         // We have to update on click as well because we might hover first, change the item, and then click.
398                         menu.on( 'click', 'a.item-edit', function() {
399                                 api.refreshAdvancedAccessibilityOfItem( $( this ) );
400                         } );
401
402                         // Links for moving items
403                         menu.on( 'click', '.menus-move', function ( e ) {
404                                 var $this = $( this ),
405                                         dir = $this.data( 'dir' );
406
407                                 if ( 'undefined' !== typeof dir ) {
408                                         api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), dir );
409                                 }
410                                 e.preventDefault();
411                         });
412                 },
413
414                 /**
415                  * refreshAdvancedAccessibilityOfItem( [itemToRefresh] )
416                  *
417                  * Refreshes advanced accessibility buttons for one menu item.
418                  * Shows or hides buttons based on the location of the menu item.
419                  *
420                  * @param  {object} itemToRefresh The menu item that might need its advanced accessibility buttons refreshed
421                  */
422                 refreshAdvancedAccessibilityOfItem : function( itemToRefresh ) {
423
424                         // Only refresh accessibility when necessary
425                         if ( true !== $( itemToRefresh ).data( 'needs_accessibility_refresh' ) ) {
426                                 return;
427                         }
428
429                         var thisLink, thisLinkText, primaryItems, itemPosition, title,
430                                 parentItem, parentItemId, parentItemName, subItems,
431                                 $this = $( itemToRefresh ),
432                                 menuItem = $this.closest( 'li.menu-item' ).first(),
433                                 depth = menuItem.menuItemDepth(),
434                                 isPrimaryMenuItem = ( 0 === depth ),
435                                 itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
436                                 position = parseInt( menuItem.index(), 10 ),
437                                 prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1, 10 ),
438                                 prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(),
439                                 prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(),
440                                 totalMenuItems = $('#menu-to-edit li').length,
441                                 hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length;
442
443                                 menuItem.find( '.field-move' ).toggle( totalMenuItems > 1 );
444
445                         // Where can they move this menu item?
446                         if ( 0 !== position ) {
447                                 thisLink = menuItem.find( '.menus-move-up' );
448                                 thisLink.attr( 'aria-label', menus.moveUp ).css( 'display', 'inline' );
449                         }
450
451                         if ( 0 !== position && isPrimaryMenuItem ) {
452                                 thisLink = menuItem.find( '.menus-move-top' );
453                                 thisLink.attr( 'aria-label', menus.moveToTop ).css( 'display', 'inline' );
454                         }
455
456                         if ( position + 1 !== totalMenuItems && 0 !== position ) {
457                                 thisLink = menuItem.find( '.menus-move-down' );
458                                 thisLink.attr( 'aria-label', menus.moveDown ).css( 'display', 'inline' );
459                         }
460
461                         if ( 0 === position && 0 !== hasSameDepthSibling ) {
462                                 thisLink = menuItem.find( '.menus-move-down' );
463                                 thisLink.attr( 'aria-label', menus.moveDown ).css( 'display', 'inline' );
464                         }
465
466                         if ( ! isPrimaryMenuItem ) {
467                                 thisLink = menuItem.find( '.menus-move-left' ),
468                                 thisLinkText = menus.outFrom.replace( '%s', prevItemNameLeft );
469                                 thisLink.attr( 'aria-label', menus.moveOutFrom.replace( '%s', prevItemNameLeft ) ).text( thisLinkText ).css( 'display', 'inline' );
470                         }
471
472                         if ( 0 !== position ) {
473                                 if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) {
474                                         thisLink = menuItem.find( '.menus-move-right' ),
475                                         thisLinkText = menus.under.replace( '%s', prevItemNameRight );
476                                         thisLink.attr( 'aria-label', menus.moveUnder.replace( '%s', prevItemNameRight ) ).text( thisLinkText ).css( 'display', 'inline' );
477                                 }
478                         }
479
480                         if ( isPrimaryMenuItem ) {
481                                 primaryItems = $( '.menu-item-depth-0' ),
482                                 itemPosition = primaryItems.index( menuItem ) + 1,
483                                 totalMenuItems = primaryItems.length,
484
485                                 // String together help text for primary menu items
486                                 title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$d', totalMenuItems );
487                         } else {
488                                 parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(),
489                                 parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
490                                 parentItemName = parentItem.find( '.menu-item-title' ).text(),
491                                 subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
492                                 itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1;
493
494                                 // String together help text for sub menu items
495                                 title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$s', parentItemName );
496                         }
497
498                         // @todo Consider to update just the `aria-label` attribute.
499                         $this.attr( 'aria-label', title ).text( title );
500
501                         // Mark this item's accessibility as refreshed
502                         $this.data( 'needs_accessibility_refresh', false );
503                 },
504
505                 /**
506                  * refreshAdvancedAccessibility
507                  *
508                  * Hides all advanced accessibility buttons and marks them for refreshing.
509                  */
510                 refreshAdvancedAccessibility : function() {
511
512                         // Hide all links by default
513                         $( '.menu-item-settings .field-move a' ).hide();
514
515                         // Mark all menu items as unprocessed
516                         $( 'a.item-edit' ).data( 'needs_accessibility_refresh', true );
517
518                         // All open items have to be refreshed or they will show no links
519                         $( '.menu-item-edit-active a.item-edit' ).each( function() {
520                                 api.refreshAdvancedAccessibilityOfItem( this );
521                         } );
522                 },
523
524                 refreshKeyboardAccessibility : function() {
525                         $( 'a.item-edit' ).off( 'focus' ).on( 'focus', function(){
526                                 $(this).off( 'keydown' ).on( 'keydown', function(e){
527
528                                         var arrows,
529                                                 $this = $( this ),
530                                                 thisItem = $this.parents( 'li.menu-item' ),
531                                                 thisItemData = thisItem.getItemData();
532
533                                         // Bail if it's not an arrow key
534                                         if ( 37 != e.which && 38 != e.which && 39 != e.which && 40 != e.which )
535                                                 return;
536
537                                         // Avoid multiple keydown events
538                                         $this.off('keydown');
539
540                                         // Bail if there is only one menu item
541                                         if ( 1 === $('#menu-to-edit li').length )
542                                                 return;
543
544                                         // If RTL, swap left/right arrows
545                                         arrows = { '38': 'up', '40': 'down', '37': 'left', '39': 'right' };
546                                         if ( $('body').hasClass('rtl') )
547                                                 arrows = { '38' : 'up', '40' : 'down', '39' : 'left', '37' : 'right' };
548
549                                         switch ( arrows[e.which] ) {
550                                         case 'up':
551                                                 api.moveMenuItem( $this, 'up' );
552                                                 break;
553                                         case 'down':
554                                                 api.moveMenuItem( $this, 'down' );
555                                                 break;
556                                         case 'left':
557                                                 api.moveMenuItem( $this, 'left' );
558                                                 break;
559                                         case 'right':
560                                                 api.moveMenuItem( $this, 'right' );
561                                                 break;
562                                         }
563                                         // Put focus back on same menu item
564                                         $( '#edit-' + thisItemData['menu-item-db-id'] ).focus();
565                                         return false;
566                                 });
567                         });
568                 },
569
570                 initPreviewing : function() {
571                         // Update the item handle title when the navigation label is changed.
572                         $( '#menu-to-edit' ).on( 'change input', '.edit-menu-item-title', function(e) {
573                                 var input = $( e.currentTarget ), title, titleEl;
574                                 title = input.val();
575                                 titleEl = input.closest( '.menu-item' ).find( '.menu-item-title' );
576                                 // Don't update to empty title.
577                                 if ( title ) {
578                                         titleEl.text( title ).removeClass( 'no-title' );
579                                 } else {
580                                         titleEl.text( navMenuL10n.untitled ).addClass( 'no-title' );
581                                 }
582                         } );
583                 },
584
585                 initToggles : function() {
586                         // init postboxes
587                         postboxes.add_postbox_toggles('nav-menus');
588
589                         // adjust columns functions for menus UI
590                         columns.useCheckboxesForHidden();
591                         columns.checked = function(field) {
592                                 $('.field-' + field).removeClass('hidden-field');
593                         };
594                         columns.unchecked = function(field) {
595                                 $('.field-' + field).addClass('hidden-field');
596                         };
597                         // hide fields
598                         api.menuList.hideAdvancedMenuItemFields();
599
600                         $('.hide-postbox-tog').click(function () {
601                                 var hidden = $( '.accordion-container li.accordion-section' ).filter(':hidden').map(function() { return this.id; }).get().join(',');
602                                 $.post(ajaxurl, {
603                                         action: 'closed-postboxes',
604                                         hidden: hidden,
605                                         closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
606                                         page: 'nav-menus'
607                                 });
608                         });
609                 },
610
611                 initSortables : function() {
612                         var currentDepth = 0, originalDepth, minDepth, maxDepth,
613                                 prev, next, prevBottom, nextThreshold, helperHeight, transport,
614                                 menuEdge = api.menuList.offset().left,
615                                 body = $('body'), maxChildDepth,
616                                 menuMaxDepth = initialMenuMaxDepth();
617
618                         if( 0 !== $( '#menu-to-edit li' ).length )
619                                 $( '.drag-instructions' ).show();
620
621                         // Use the right edge if RTL.
622                         menuEdge += api.isRTL ? api.menuList.width() : 0;
623
624                         api.menuList.sortable({
625                                 handle: '.menu-item-handle',
626                                 placeholder: 'sortable-placeholder',
627                                 items: api.options.sortableItems,
628                                 start: function(e, ui) {
629                                         var height, width, parent, children, tempHolder;
630
631                                         // handle placement for rtl orientation
632                                         if ( api.isRTL )
633                                                 ui.item[0].style.right = 'auto';
634
635                                         transport = ui.item.children('.menu-item-transport');
636
637                                         // Set depths. currentDepth must be set before children are located.
638                                         originalDepth = ui.item.menuItemDepth();
639                                         updateCurrentDepth(ui, originalDepth);
640
641                                         // Attach child elements to parent
642                                         // Skip the placeholder
643                                         parent = ( ui.item.next()[0] == ui.placeholder[0] ) ? ui.item.next() : ui.item;
644                                         children = parent.childMenuItems();
645                                         transport.append( children );
646
647                                         // Update the height of the placeholder to match the moving item.
648                                         height = transport.outerHeight();
649                                         // If there are children, account for distance between top of children and parent
650                                         height += ( height > 0 ) ? (ui.placeholder.css('margin-top').slice(0, -2) * 1) : 0;
651                                         height += ui.helper.outerHeight();
652                                         helperHeight = height;
653                                         height -= 2; // Subtract 2 for borders
654                                         ui.placeholder.height(height);
655
656                                         // Update the width of the placeholder to match the moving item.
657                                         maxChildDepth = originalDepth;
658                                         children.each(function(){
659                                                 var depth = $(this).menuItemDepth();
660                                                 maxChildDepth = (depth > maxChildDepth) ? depth : maxChildDepth;
661                                         });
662                                         width = ui.helper.find('.menu-item-handle').outerWidth(); // Get original width
663                                         width += api.depthToPx(maxChildDepth - originalDepth); // Account for children
664                                         width -= 2; // Subtract 2 for borders
665                                         ui.placeholder.width(width);
666
667                                         // Update the list of menu items.
668                                         tempHolder = ui.placeholder.next( '.menu-item' );
669                                         tempHolder.css( 'margin-top', helperHeight + 'px' ); // Set the margin to absorb the placeholder
670                                         ui.placeholder.detach(); // detach or jQuery UI will think the placeholder is a menu item
671                                         $(this).sortable( 'refresh' ); // The children aren't sortable. We should let jQ UI know.
672                                         ui.item.after( ui.placeholder ); // reattach the placeholder.
673                                         tempHolder.css('margin-top', 0); // reset the margin
674
675                                         // Now that the element is complete, we can update...
676                                         updateSharedVars(ui);
677                                 },
678                                 stop: function(e, ui) {
679                                         var children, subMenuTitle,
680                                                 depthChange = currentDepth - originalDepth;
681
682                                         // Return child elements to the list
683                                         children = transport.children().insertAfter(ui.item);
684
685                                         // Add "sub menu" description
686                                         subMenuTitle = ui.item.find( '.item-title .is-submenu' );
687                                         if ( 0 < currentDepth )
688                                                 subMenuTitle.show();
689                                         else
690                                                 subMenuTitle.hide();
691
692                                         // Update depth classes
693                                         if ( 0 !== depthChange ) {
694                                                 ui.item.updateDepthClass( currentDepth );
695                                                 children.shiftDepthClass( depthChange );
696                                                 updateMenuMaxDepth( depthChange );
697                                         }
698                                         // Register a change
699                                         api.registerChange();
700                                         // Update the item data.
701                                         ui.item.updateParentMenuItemDBId();
702
703                                         // address sortable's incorrectly-calculated top in opera
704                                         ui.item[0].style.top = 0;
705
706                                         // handle drop placement for rtl orientation
707                                         if ( api.isRTL ) {
708                                                 ui.item[0].style.left = 'auto';
709                                                 ui.item[0].style.right = 0;
710                                         }
711
712                                         api.refreshKeyboardAccessibility();
713                                         api.refreshAdvancedAccessibility();
714                                 },
715                                 change: function(e, ui) {
716                                         // Make sure the placeholder is inside the menu.
717                                         // Otherwise fix it, or we're in trouble.
718                                         if( ! ui.placeholder.parent().hasClass('menu') )
719                                                 (prev.length) ? prev.after( ui.placeholder ) : api.menuList.prepend( ui.placeholder );
720
721                                         updateSharedVars(ui);
722                                 },
723                                 sort: function(e, ui) {
724                                         var offset = ui.helper.offset(),
725                                                 edge = api.isRTL ? offset.left + ui.helper.width() : offset.left,
726                                                 depth = api.negateIfRTL * api.pxToDepth( edge - menuEdge );
727
728                                         // Check and correct if depth is not within range.
729                                         // Also, if the dragged element is dragged upwards over
730                                         // an item, shift the placeholder to a child position.
731                                         if ( depth > maxDepth || offset.top < ( prevBottom - api.options.targetTolerance ) ) {
732                                                 depth = maxDepth;
733                                         } else if ( depth < minDepth ) {
734                                                 depth = minDepth;
735                                         }
736
737                                         if( depth != currentDepth )
738                                                 updateCurrentDepth(ui, depth);
739
740                                         // If we overlap the next element, manually shift downwards
741                                         if( nextThreshold && offset.top + helperHeight > nextThreshold ) {
742                                                 next.after( ui.placeholder );
743                                                 updateSharedVars( ui );
744                                                 $( this ).sortable( 'refreshPositions' );
745                                         }
746                                 }
747                         });
748
749                         function updateSharedVars(ui) {
750                                 var depth;
751
752                                 prev = ui.placeholder.prev( '.menu-item' );
753                                 next = ui.placeholder.next( '.menu-item' );
754
755                                 // Make sure we don't select the moving item.
756                                 if( prev[0] == ui.item[0] ) prev = prev.prev( '.menu-item' );
757                                 if( next[0] == ui.item[0] ) next = next.next( '.menu-item' );
758
759                                 prevBottom = (prev.length) ? prev.offset().top + prev.height() : 0;
760                                 nextThreshold = (next.length) ? next.offset().top + next.height() / 3 : 0;
761                                 minDepth = (next.length) ? next.menuItemDepth() : 0;
762
763                                 if( prev.length )
764                                         maxDepth = ( (depth = prev.menuItemDepth() + 1) > api.options.globalMaxDepth ) ? api.options.globalMaxDepth : depth;
765                                 else
766                                         maxDepth = 0;
767                         }
768
769                         function updateCurrentDepth(ui, depth) {
770                                 ui.placeholder.updateDepthClass( depth, currentDepth );
771                                 currentDepth = depth;
772                         }
773
774                         function initialMenuMaxDepth() {
775                                 if( ! body[0].className ) return 0;
776                                 var match = body[0].className.match(/menu-max-depth-(\d+)/);
777                                 return match && match[1] ? parseInt( match[1], 10 ) : 0;
778                         }
779
780                         function updateMenuMaxDepth( depthChange ) {
781                                 var depth, newDepth = menuMaxDepth;
782                                 if ( depthChange === 0 ) {
783                                         return;
784                                 } else if ( depthChange > 0 ) {
785                                         depth = maxChildDepth + depthChange;
786                                         if( depth > menuMaxDepth )
787                                                 newDepth = depth;
788                                 } else if ( depthChange < 0 && maxChildDepth == menuMaxDepth ) {
789                                         while( ! $('.menu-item-depth-' + newDepth, api.menuList).length && newDepth > 0 )
790                                                 newDepth--;
791                                 }
792                                 // Update the depth class.
793                                 body.removeClass( 'menu-max-depth-' + menuMaxDepth ).addClass( 'menu-max-depth-' + newDepth );
794                                 menuMaxDepth = newDepth;
795                         }
796                 },
797
798                 initManageLocations : function () {
799                         $('#menu-locations-wrap form').submit(function(){
800                                 window.onbeforeunload = null;
801                         });
802                         $('.menu-location-menus select').on('change', function () {
803                                 var editLink = $(this).closest('tr').find('.locations-edit-menu-link');
804                                 if ($(this).find('option:selected').data('orig'))
805                                         editLink.show();
806                                 else
807                                         editLink.hide();
808                         });
809                 },
810
811                 attachMenuEditListeners : function() {
812                         var that = this;
813                         $('#update-nav-menu').bind('click', function(e) {
814                                 if ( e.target && e.target.className ) {
815                                         if ( -1 != e.target.className.indexOf('item-edit') ) {
816                                                 return that.eventOnClickEditLink(e.target);
817                                         } else if ( -1 != e.target.className.indexOf('menu-save') ) {
818                                                 return that.eventOnClickMenuSave(e.target);
819                                         } else if ( -1 != e.target.className.indexOf('menu-delete') ) {
820                                                 return that.eventOnClickMenuDelete(e.target);
821                                         } else if ( -1 != e.target.className.indexOf('item-delete') ) {
822                                                 return that.eventOnClickMenuItemDelete(e.target);
823                                         } else if ( -1 != e.target.className.indexOf('item-cancel') ) {
824                                                 return that.eventOnClickCancelLink(e.target);
825                                         }
826                                 }
827                         });
828                         $('#add-custom-links input[type="text"]').keypress(function(e){
829                                 $('#customlinkdiv').removeClass('form-invalid');
830
831                                 if ( e.keyCode === 13 ) {
832                                         e.preventDefault();
833                                         $( '#submit-customlinkdiv' ).click();
834                                 }
835                         });
836                 },
837
838                 attachMenuSaveSubmitListeners : function() {
839                         /*
840                          * When a navigation menu is saved, store a JSON representation of all form data
841                          * in a single input to avoid PHP `max_input_vars` limitations. See #14134.
842                          */
843                         $( '#update-nav-menu' ).submit( function() {
844                                 var navMenuData = $( '#update-nav-menu' ).serializeArray();
845                                 $( '[name="nav-menu-data"]' ).val( JSON.stringify( navMenuData ) );
846                         });
847                 },
848
849                 attachThemeLocationsListeners : function() {
850                         var loc = $('#nav-menu-theme-locations'), params = {};
851                         params.action = 'menu-locations-save';
852                         params['menu-settings-column-nonce'] = $('#menu-settings-column-nonce').val();
853                         loc.find('input[type="submit"]').click(function() {
854                                 loc.find('select').each(function() {
855                                         params[this.name] = $(this).val();
856                                 });
857                                 loc.find( '.spinner' ).addClass( 'is-active' );
858                                 $.post( ajaxurl, params, function() {
859                                         loc.find( '.spinner' ).removeClass( 'is-active' );
860                                 });
861                                 return false;
862                         });
863                 },
864
865                 attachQuickSearchListeners : function() {
866                         var searchTimer,
867                                 inputEvent;
868
869                         // Prevent form submission.
870                         $( '#nav-menu-meta' ).on( 'submit', function( event ) {
871                                 event.preventDefault();
872                         });
873
874                         /*
875                          * Use feature detection to determine whether inputs should use
876                          * the `keyup` or `input` event. Input is preferred but lacks support
877                          * in legacy browsers. See changeset 34078, see also ticket #26600#comment:59
878                          */
879                         if ( 'oninput' in document.createElement( 'input' ) ) {
880                                 inputEvent = 'input';
881                         } else {
882                                 inputEvent = 'keyup';
883                         }
884
885                         $( '.quick-search' ).on( inputEvent, function() {
886                                 var t = $(this);
887
888                                 if( searchTimer ) clearTimeout(searchTimer);
889
890                                 searchTimer = setTimeout(function(){
891                                         api.updateQuickSearchResults( t );
892                                 }, 500 );
893                         }).on( 'blur', function() {
894                                 api.lastSearch = '';
895                         }).attr('autocomplete','off');
896                 },
897
898                 updateQuickSearchResults : function(input) {
899                         var panel, params,
900                                 minSearchLength = 2,
901                                 q = input.val();
902
903                         /*
904                          * Minimum characters for a search. Also avoid a new AJAX search when
905                          * the pressed key (e.g. arrows) doesn't change the searched term.
906                          */
907                         if ( q.length < minSearchLength || api.lastSearch == q ) {
908                                 return;
909                         }
910
911                         api.lastSearch = q;
912
913                         panel = input.parents('.tabs-panel');
914                         params = {
915                                 'action': 'menu-quick-search',
916                                 'response-format': 'markup',
917                                 'menu': $('#menu').val(),
918                                 'menu-settings-column-nonce': $('#menu-settings-column-nonce').val(),
919                                 'q': q,
920                                 'type': input.attr('name')
921                         };
922
923                         $( '.spinner', panel ).addClass( 'is-active' );
924
925                         $.post( ajaxurl, params, function(menuMarkup) {
926                                 api.processQuickSearchQueryResponse(menuMarkup, params, panel);
927                         });
928                 },
929
930                 addCustomLink : function( processMethod ) {
931                         var url = $('#custom-menu-item-url').val(),
932                                 label = $('#custom-menu-item-name').val();
933
934                         processMethod = processMethod || api.addMenuItemToBottom;
935
936                         if ( '' === url || 'http://' == url ) {
937                                 $('#customlinkdiv').addClass('form-invalid');
938                                 return false;
939                         }
940
941                         // Show the ajax spinner
942                         $( '.customlinkdiv .spinner' ).addClass( 'is-active' );
943                         this.addLinkToMenu( url, label, processMethod, function() {
944                                 // Remove the ajax spinner
945                                 $( '.customlinkdiv .spinner' ).removeClass( 'is-active' );
946                                 // Set custom link form back to defaults
947                                 $('#custom-menu-item-name').val('').blur();
948                                 $('#custom-menu-item-url').val('http://');
949                         });
950                 },
951
952                 addLinkToMenu : function(url, label, processMethod, callback) {
953                         processMethod = processMethod || api.addMenuItemToBottom;
954                         callback = callback || function(){};
955
956                         api.addItemToMenu({
957                                 '-1': {
958                                         'menu-item-type': 'custom',
959                                         'menu-item-url': url,
960                                         'menu-item-title': label
961                                 }
962                         }, processMethod, callback);
963                 },
964
965                 addItemToMenu : function(menuItem, processMethod, callback) {
966                         var menu = $('#menu').val(),
967                                 nonce = $('#menu-settings-column-nonce').val(),
968                                 params;
969
970                         processMethod = processMethod || function(){};
971                         callback = callback || function(){};
972
973                         params = {
974                                 'action': 'add-menu-item',
975                                 'menu': menu,
976                                 'menu-settings-column-nonce': nonce,
977                                 'menu-item': menuItem
978                         };
979
980                         $.post( ajaxurl, params, function(menuMarkup) {
981                                 var ins = $('#menu-instructions');
982
983                                 menuMarkup = $.trim( menuMarkup ); // Trim leading whitespaces
984                                 processMethod(menuMarkup, params);
985
986                                 // Make it stand out a bit more visually, by adding a fadeIn
987                                 $( 'li.pending' ).hide().fadeIn('slow');
988                                 $( '.drag-instructions' ).show();
989                                 if( ! ins.hasClass( 'menu-instructions-inactive' ) && ins.siblings().length )
990                                         ins.addClass( 'menu-instructions-inactive' );
991
992                                 callback();
993                         });
994                 },
995
996                 /**
997                  * Process the add menu item request response into menu list item.
998                  *
999                  * @param string menuMarkup The text server response of menu item markup.
1000                  * @param object req The request arguments.
1001                  */
1002                 addMenuItemToBottom : function( menuMarkup ) {
1003                         $(menuMarkup).hideAdvancedMenuItemFields().appendTo( api.targetList );
1004                         api.refreshKeyboardAccessibility();
1005                         api.refreshAdvancedAccessibility();
1006                 },
1007
1008                 addMenuItemToTop : function( menuMarkup ) {
1009                         $(menuMarkup).hideAdvancedMenuItemFields().prependTo( api.targetList );
1010                         api.refreshKeyboardAccessibility();
1011                         api.refreshAdvancedAccessibility();
1012                 },
1013
1014                 attachUnsavedChangesListener : function() {
1015                         $('#menu-management input, #menu-management select, #menu-management, #menu-management textarea, .menu-location-menus select').change(function(){
1016                                 api.registerChange();
1017                         });
1018
1019                         if ( 0 !== $('#menu-to-edit').length || 0 !== $('.menu-location-menus select').length ) {
1020                                 window.onbeforeunload = function(){
1021                                         if ( api.menusChanged )
1022                                                 return navMenuL10n.saveAlert;
1023                                 };
1024                         } else {
1025                                 // Make the post boxes read-only, as they can't be used yet
1026                                 $( '#menu-settings-column' ).find( 'input,select' ).end().find( 'a' ).attr( 'href', '#' ).unbind( 'click' );
1027                         }
1028                 },
1029
1030                 registerChange : function() {
1031                         api.menusChanged = true;
1032                 },
1033
1034                 attachTabsPanelListeners : function() {
1035                         $('#menu-settings-column').bind('click', function(e) {
1036                                 var selectAreaMatch, panelId, wrapper, items,
1037                                         target = $(e.target);
1038
1039                                 if ( target.hasClass('nav-tab-link') ) {
1040
1041                                         panelId = target.data( 'type' );
1042
1043                                         wrapper = target.parents('.accordion-section-content').first();
1044
1045                                         // upon changing tabs, we want to uncheck all checkboxes
1046                                         $('input', wrapper).removeAttr('checked');
1047
1048                                         $('.tabs-panel-active', wrapper).removeClass('tabs-panel-active').addClass('tabs-panel-inactive');
1049                                         $('#' + panelId, wrapper).removeClass('tabs-panel-inactive').addClass('tabs-panel-active');
1050
1051                                         $('.tabs', wrapper).removeClass('tabs');
1052                                         target.parent().addClass('tabs');
1053
1054                                         // select the search bar
1055                                         $('.quick-search', wrapper).focus();
1056
1057                                         e.preventDefault();
1058                                 } else if ( target.hasClass('select-all') ) {
1059                                         selectAreaMatch = /#(.*)$/.exec(e.target.href);
1060                                         if ( selectAreaMatch && selectAreaMatch[1] ) {
1061                                                 items = $('#' + selectAreaMatch[1] + ' .tabs-panel-active .menu-item-title input');
1062                                                 if( items.length === items.filter(':checked').length )
1063                                                         items.removeAttr('checked');
1064                                                 else
1065                                                         items.prop('checked', true);
1066                                                 return false;
1067                                         }
1068                                 } else if ( target.hasClass('submit-add-to-menu') ) {
1069                                         api.registerChange();
1070
1071                                         if ( e.target.id && 'submit-customlinkdiv' == e.target.id )
1072                                                 api.addCustomLink( api.addMenuItemToBottom );
1073                                         else if ( e.target.id && -1 != e.target.id.indexOf('submit-') )
1074                                                 $('#' + e.target.id.replace(/submit-/, '')).addSelectedToMenu( api.addMenuItemToBottom );
1075                                         return false;
1076                                 } else if ( target.hasClass('page-numbers') ) {
1077                                         $.post( ajaxurl, e.target.href.replace(/.*\?/, '').replace(/action=([^&]*)/, '') + '&action=menu-get-metabox',
1078                                                 function( resp ) {
1079                                                         if ( -1 == resp.indexOf('replace-id') )
1080                                                                 return;
1081
1082                                                         var metaBoxData = $.parseJSON(resp),
1083                                                         toReplace = document.getElementById(metaBoxData['replace-id']),
1084                                                         placeholder = document.createElement('div'),
1085                                                         wrap = document.createElement('div');
1086
1087                                                         if ( ! metaBoxData.markup || ! toReplace )
1088                                                                 return;
1089
1090                                                         wrap.innerHTML = metaBoxData.markup ? metaBoxData.markup : '';
1091
1092                                                         toReplace.parentNode.insertBefore( placeholder, toReplace );
1093                                                         placeholder.parentNode.removeChild( toReplace );
1094
1095                                                         placeholder.parentNode.insertBefore( wrap, placeholder );
1096
1097                                                         placeholder.parentNode.removeChild( placeholder );
1098
1099                                                 }
1100                                         );
1101
1102                                         return false;
1103                                 }
1104                         });
1105                 },
1106
1107                 eventOnClickEditLink : function(clickedEl) {
1108                         var settings, item,
1109                         matchedSection = /#(.*)$/.exec(clickedEl.href);
1110                         if ( matchedSection && matchedSection[1] ) {
1111                                 settings = $('#'+matchedSection[1]);
1112                                 item = settings.parent();
1113                                 if( 0 !== item.length ) {
1114                                         if( item.hasClass('menu-item-edit-inactive') ) {
1115                                                 if( ! settings.data('menu-item-data') ) {
1116                                                         settings.data( 'menu-item-data', settings.getItemData() );
1117                                                 }
1118                                                 settings.slideDown('fast');
1119                                                 item.removeClass('menu-item-edit-inactive')
1120                                                         .addClass('menu-item-edit-active');
1121                                         } else {
1122                                                 settings.slideUp('fast');
1123                                                 item.removeClass('menu-item-edit-active')
1124                                                         .addClass('menu-item-edit-inactive');
1125                                         }
1126                                         return false;
1127                                 }
1128                         }
1129                 },
1130
1131                 eventOnClickCancelLink : function(clickedEl) {
1132                         var settings = $( clickedEl ).closest( '.menu-item-settings' ),
1133                                 thisMenuItem = $( clickedEl ).closest( '.menu-item' );
1134                         thisMenuItem.removeClass('menu-item-edit-active').addClass('menu-item-edit-inactive');
1135                         settings.setItemData( settings.data('menu-item-data') ).hide();
1136                         return false;
1137                 },
1138
1139                 eventOnClickMenuSave : function() {
1140                         var locs = '',
1141                         menuName = $('#menu-name'),
1142                         menuNameVal = menuName.val();
1143                         // Cancel and warn if invalid menu name
1144                         if( !menuNameVal || menuNameVal == menuName.attr('title') || !menuNameVal.replace(/\s+/, '') ) {
1145                                 menuName.parent().addClass('form-invalid');
1146                                 return false;
1147                         }
1148                         // Copy menu theme locations
1149                         $('#nav-menu-theme-locations select').each(function() {
1150                                 locs += '<input type="hidden" name="' + this.name + '" value="' + $(this).val() + '" />';
1151                         });
1152                         $('#update-nav-menu').append( locs );
1153                         // Update menu item position data
1154                         api.menuList.find('.menu-item-data-position').val( function(index) { return index + 1; } );
1155                         window.onbeforeunload = null;
1156
1157                         return true;
1158                 },
1159
1160                 eventOnClickMenuDelete : function() {
1161                         // Delete warning AYS
1162                         if ( window.confirm( navMenuL10n.warnDeleteMenu ) ) {
1163                                 window.onbeforeunload = null;
1164                                 return true;
1165                         }
1166                         return false;
1167                 },
1168
1169                 eventOnClickMenuItemDelete : function(clickedEl) {
1170                         var itemID = parseInt(clickedEl.id.replace('delete-', ''), 10);
1171                         api.removeMenuItem( $('#menu-item-' + itemID) );
1172                         api.registerChange();
1173                         return false;
1174                 },
1175
1176                 /**
1177                  * Process the quick search response into a search result
1178                  *
1179                  * @param string resp The server response to the query.
1180                  * @param object req The request arguments.
1181                  * @param jQuery panel The tabs panel we're searching in.
1182                  */
1183                 processQuickSearchQueryResponse : function(resp, req, panel) {
1184                         var matched, newID,
1185                         takenIDs = {},
1186                         form = document.getElementById('nav-menu-meta'),
1187                         pattern = /menu-item[(\[^]\]*/,
1188                         $items = $('<div>').html(resp).find('li'),
1189                         $item;
1190
1191                         if( ! $items.length ) {
1192                                 $('.categorychecklist', panel).html( '<li><p>' + navMenuL10n.noResultsFound + '</p></li>' );
1193                                 $( '.spinner', panel ).removeClass( 'is-active' );
1194                                 return;
1195                         }
1196
1197                         $items.each(function(){
1198                                 $item = $(this);
1199
1200                                 // make a unique DB ID number
1201                                 matched = pattern.exec($item.html());
1202
1203                                 if ( matched && matched[1] ) {
1204                                         newID = matched[1];
1205                                         while( form.elements['menu-item[' + newID + '][menu-item-type]'] || takenIDs[ newID ] ) {
1206                                                 newID--;
1207                                         }
1208
1209                                         takenIDs[newID] = true;
1210                                         if ( newID != matched[1] ) {
1211                                                 $item.html( $item.html().replace(new RegExp(
1212                                                         'menu-item\\[' + matched[1] + '\\]', 'g'),
1213                                                         'menu-item[' + newID + ']'
1214                                                 ) );
1215                                         }
1216                                 }
1217                         });
1218
1219                         $('.categorychecklist', panel).html( $items );
1220                         $( '.spinner', panel ).removeClass( 'is-active' );
1221                 },
1222
1223                 removeMenuItem : function(el) {
1224                         var children = el.childMenuItems();
1225
1226                         el.addClass('deleting').animate({
1227                                         opacity : 0,
1228                                         height: 0
1229                                 }, 350, function() {
1230                                         var ins = $('#menu-instructions');
1231                                         el.remove();
1232                                         children.shiftDepthClass( -1 ).updateParentMenuItemDBId();
1233                                         if ( 0 === $( '#menu-to-edit li' ).length ) {
1234                                                 $( '.drag-instructions' ).hide();
1235                                                 ins.removeClass( 'menu-instructions-inactive' );
1236                                         }
1237                                         api.refreshAdvancedAccessibility();
1238                                 });
1239                 },
1240
1241                 depthToPx : function(depth) {
1242                         return depth * api.options.menuItemDepthPerLevel;
1243                 },
1244
1245                 pxToDepth : function(px) {
1246                         return Math.floor(px / api.options.menuItemDepthPerLevel);
1247                 }
1248
1249         };
1250
1251         $(document).ready(function(){ wpNavMenu.init(); });
1252
1253 })(jQuery);