~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-admin/js/nav-menu.js

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

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