214 api.addItemToMenu(menuItems, processMethod, function(){ |
214 api.addItemToMenu(menuItems, processMethod, function(){ |
215 // Deselect the items and hide the Ajax spinner. |
215 // Deselect the items and hide the Ajax spinner. |
216 checkboxes.prop( 'checked', false ); |
216 checkboxes.prop( 'checked', false ); |
217 t.find( '.button-controls .select-all' ).prop( 'checked', false ); |
217 t.find( '.button-controls .select-all' ).prop( 'checked', false ); |
218 t.find( '.button-controls .spinner' ).removeClass( 'is-active' ); |
218 t.find( '.button-controls .spinner' ).removeClass( 'is-active' ); |
|
219 t.updateParentDropdown(); |
|
220 t.updateOrderDropdown(); |
219 }); |
221 }); |
220 }); |
222 }); |
221 }, |
223 }, |
222 getItemData : function( itemType, id ) { |
224 getItemData : function( itemType, id ) { |
223 itemType = itemType || 'menu-item'; |
225 itemType = itemType || 'menu-item'; |
286 t.val( val ); |
288 t.val( val ); |
287 } |
289 } |
288 }); |
290 }); |
289 }); |
291 }); |
290 return this; |
292 return this; |
|
293 }, |
|
294 updateParentDropdown : function() { |
|
295 return this.each(function(){ |
|
296 var menuItems = $( '#menu-to-edit li' ), |
|
297 parentDropdowns = $( '.edit-menu-item-parent' ); |
|
298 |
|
299 $.each( parentDropdowns, function() { |
|
300 var parentDropdown = $( this ), |
|
301 $html = '', |
|
302 $selected = '', |
|
303 currentItemID = parentDropdown.closest( 'li.menu-item' ).find( '.menu-item-data-db-id' ).val(), |
|
304 currentparentID = parentDropdown.closest( 'li.menu-item' ).find( '.menu-item-data-parent-id' ).val(), |
|
305 currentItem = parentDropdown.closest( 'li.menu-item' ), |
|
306 currentMenuItemChild = currentItem.childMenuItems(), |
|
307 excludeMenuItem = [ currentItemID ]; |
|
308 |
|
309 if ( currentMenuItemChild.length > 0 ) { |
|
310 $.each( currentMenuItemChild, function(){ |
|
311 var childItem = $(this), |
|
312 childID = childItem.find( '.menu-item-data-db-id' ).val(); |
|
313 |
|
314 excludeMenuItem.push( childID ); |
|
315 }); |
|
316 } |
|
317 |
|
318 if ( currentparentID == 0 ) { |
|
319 $selected = 'selected'; |
|
320 } |
|
321 |
|
322 $html += '<option ' + $selected + ' value="0">' + wp.i18n._x( 'No Parent', 'menu item without a parent in navigation menu' ) + '</option>'; |
|
323 |
|
324 $.each( menuItems, function() { |
|
325 var menuItem = $(this), |
|
326 $selected = '', |
|
327 menuID = menuItem.find( '.menu-item-data-db-id' ).val(), |
|
328 menuTitle = menuItem.find( '.edit-menu-item-title' ).val(); |
|
329 |
|
330 if ( ! excludeMenuItem.includes( menuID ) ) { |
|
331 if ( currentparentID == menuID ) { |
|
332 $selected = 'selected'; |
|
333 } |
|
334 $html += '<option ' + $selected + ' value="' + menuID + '">' + menuTitle + '</option>'; |
|
335 } |
|
336 }); |
|
337 |
|
338 parentDropdown.html( $html ); |
|
339 }); |
|
340 |
|
341 }); |
|
342 }, |
|
343 updateOrderDropdown : function() { |
|
344 return this.each( function() { |
|
345 var itemPosition, |
|
346 orderDropdowns = $( '.edit-menu-item-order' ); |
|
347 |
|
348 $.each( orderDropdowns, function() { |
|
349 var orderDropdown = $( this ), |
|
350 menuItem = orderDropdown.closest( 'li.menu-item' ).first(), |
|
351 depth = menuItem.menuItemDepth(), |
|
352 isPrimaryMenuItem = ( 0 === depth ), |
|
353 $html = '', |
|
354 $selected = ''; |
|
355 |
|
356 if ( isPrimaryMenuItem ) { |
|
357 var primaryItems = $( '.menu-item-depth-0' ), |
|
358 totalMenuItems = primaryItems.length; |
|
359 |
|
360 itemPosition = primaryItems.index( menuItem ) + 1; |
|
361 |
|
362 for ( let i = 1; i < totalMenuItems + 1; i++ ) { |
|
363 $selected = ''; |
|
364 if ( i == itemPosition ) { |
|
365 $selected = 'selected'; |
|
366 } |
|
367 var itemString = wp.i18n.sprintf( |
|
368 /* translators: 1: The current menu item number, 2: The total number of menu items. */ |
|
369 wp.i18n._x( '%1$s of %2$s', 'part of a total number of menu items' ), |
|
370 i, |
|
371 totalMenuItems |
|
372 ); |
|
373 $html += '<option ' + $selected + ' value="' + i + '">' + itemString + '</option>'; |
|
374 } |
|
375 |
|
376 } else { |
|
377 var parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(), |
|
378 parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(), |
|
379 subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ), |
|
380 totalSubMenuItems = subItems.length; |
|
381 |
|
382 itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1; |
|
383 |
|
384 for ( let i = 1; i < totalSubMenuItems + 1; i++ ) { |
|
385 $selected = ''; |
|
386 if ( i == itemPosition ) { |
|
387 $selected = 'selected'; |
|
388 } |
|
389 var submenuString = wp.i18n.sprintf( |
|
390 /* translators: 1: The current submenu item number, 2: The total number of submenu items. */ |
|
391 wp.i18n._x( '%1$s of %2$s', 'part of a total number of menu items' ), |
|
392 i, |
|
393 totalSubMenuItems |
|
394 ); |
|
395 $html += '<option ' + $selected + ' value="' + i + '">' + submenuString + '</option>'; |
|
396 } |
|
397 |
|
398 } |
|
399 |
|
400 orderDropdown.html( $html ); |
|
401 }); |
|
402 |
|
403 }); |
291 } |
404 } |
292 }); |
405 }); |
293 }, |
406 }, |
294 |
407 |
295 countMenuItems : function( depth ) { |
408 countMenuItems : function( depth ) { |
296 return $( '.menu-item-depth-' + depth ).length; |
409 return $( '.menu-item-depth-' + depth ).length; |
297 }, |
410 }, |
298 |
411 |
299 moveMenuItem : function( $this, dir ) { |
412 moveMenuItem : function( $this, dir ) { |
300 |
|
301 var items, newItemPosition, newDepth, |
413 var items, newItemPosition, newDepth, |
302 menuItems = $( '#menu-to-edit li' ), |
414 menuItems = $( '#menu-to-edit li' ), |
303 menuItemsCount = menuItems.length, |
415 menuItemsCount = menuItems.length, |
304 thisItem = $this.parents( 'li.menu-item' ), |
416 thisItem = $this.parents( 'li.menu-item' ), |
305 thisItemChildren = thisItem.childMenuItems(), |
417 thisItemChildren = thisItem.childMenuItems(), |
429 |
543 |
430 if ( 'undefined' !== typeof dir ) { |
544 if ( 'undefined' !== typeof dir ) { |
431 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), dir ); |
545 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), dir ); |
432 } |
546 } |
433 }); |
547 }); |
|
548 |
|
549 // Set menu parents data for all menu items. |
|
550 menu.updateParentDropdown(); |
|
551 |
|
552 // Set menu order data for all menu items. |
|
553 menu.updateOrderDropdown(); |
|
554 |
|
555 // Update menu item parent when value is changed. |
|
556 menu.on( 'change', '.edit-menu-item-parent', function() { |
|
557 api.changeMenuParent( $( this ) ); |
|
558 }); |
|
559 |
|
560 // Update menu item order when value is changed. |
|
561 menu.on( 'change', '.edit-menu-item-order', function() { |
|
562 api.changeMenuOrder( $( this ) ); |
|
563 }); |
|
564 }, |
|
565 |
|
566 /** |
|
567 * changeMenuParent( [parentDropdown] ) |
|
568 * |
|
569 * @since 6.7.0 |
|
570 * |
|
571 * @param {object} parentDropdown select field |
|
572 */ |
|
573 changeMenuParent : function( parentDropdown ) { |
|
574 var menuItemNewPosition, |
|
575 menuItems = $( '#menu-to-edit li' ), |
|
576 $this = $( parentDropdown ), |
|
577 newParentID = $this.val(), |
|
578 menuItem = $this.closest( 'li.menu-item' ).first(), |
|
579 menuItemOldDepth = menuItem.menuItemDepth(), |
|
580 menuItemChildren = menuItem.childMenuItems(), |
|
581 menuItemNoChildren = parseInt( menuItem.childMenuItems().length, 10 ), |
|
582 parentItem = $( '#menu-item-' + newParentID ), |
|
583 parentItemDepth = parentItem.menuItemDepth(), |
|
584 menuItemNewDepth = parseInt( parentItemDepth ) + 1; |
|
585 |
|
586 if ( newParentID == 0 ) { |
|
587 menuItemNewDepth = 0; |
|
588 } |
|
589 |
|
590 menuItem.find( '.menu-item-data-parent-id' ).val( newParentID ); |
|
591 menuItem.moveHorizontally( menuItemNewDepth, menuItemOldDepth ); |
|
592 |
|
593 if ( menuItemNoChildren > 0 ) { |
|
594 menuItem = menuItem.add( menuItemChildren ); |
|
595 } |
|
596 menuItem.detach(); |
|
597 |
|
598 menuItems = $( '#menu-to-edit li' ); |
|
599 |
|
600 var parentItemPosition = parseInt( parentItem.index(), 10 ), |
|
601 parentItemNoChild = parseInt( parentItem.childMenuItems().length, 10 ); |
|
602 |
|
603 if ( parentItemNoChild > 0 ){ |
|
604 menuItemNewPosition = parentItemPosition + parentItemNoChild; |
|
605 } else { |
|
606 menuItemNewPosition = parentItemPosition; |
|
607 } |
|
608 |
|
609 if ( newParentID == 0 ) { |
|
610 menuItemNewPosition = menuItems.length - 1; |
|
611 } |
|
612 |
|
613 menuItem.insertAfter( menuItems.eq( menuItemNewPosition ) ).updateParentMenuItemDBId().updateParentDropdown().updateOrderDropdown(); |
|
614 |
|
615 api.registerChange(); |
|
616 api.refreshKeyboardAccessibility(); |
|
617 api.refreshAdvancedAccessibility(); |
|
618 $this.trigger( 'focus' ); |
|
619 wp.a11y.speak( menus.parentUpdated, 'polite' ); |
|
620 }, |
|
621 |
|
622 /** |
|
623 * changeMenuOrder( [OrderDropdown] ) |
|
624 * |
|
625 * @since 6.7.0 |
|
626 * |
|
627 * @param {object} orderDropdown select field |
|
628 */ |
|
629 changeMenuOrder : function( orderDropdown ) { |
|
630 var menuItems = $( '#menu-to-edit li' ), |
|
631 $this = $( orderDropdown ), |
|
632 newOrderID = parseInt( $this.val(), 10), |
|
633 menuItem = $this.closest( 'li.menu-item' ).first(), |
|
634 menuItemChildren = menuItem.childMenuItems(), |
|
635 menuItemNoChildren = menuItemChildren.length, |
|
636 menuItemCurrentPosition = parseInt( menuItem.index(), 10 ), |
|
637 parentItemID = menuItem.find( '.menu-item-data-parent-id' ).val(), |
|
638 subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemID + '"]' ), |
|
639 currentItemAtPosition = $(subItems[newOrderID - 1]).closest( 'li.menu-item' ); |
|
640 |
|
641 if ( menuItemNoChildren > 0 ) { |
|
642 menuItem = menuItem.add( menuItemChildren ); |
|
643 } |
|
644 |
|
645 var currentItemNoChildren = currentItemAtPosition.childMenuItems().length, |
|
646 currentItemPosition = parseInt( currentItemAtPosition.index(), 10 ); |
|
647 |
|
648 menuItems = $( '#menu-to-edit li' ); |
|
649 |
|
650 var menuItemNewPosition = currentItemPosition; |
|
651 |
|
652 if(menuItemCurrentPosition > menuItemNewPosition){ |
|
653 menuItemNewPosition = currentItemPosition; |
|
654 menuItem.detach().insertBefore( menuItems.eq( menuItemNewPosition ) ).updateOrderDropdown(); |
|
655 } else { |
|
656 menuItemNewPosition = menuItemNewPosition + currentItemNoChildren; |
|
657 menuItem.detach().insertAfter( menuItems.eq( menuItemNewPosition ) ).updateOrderDropdown(); |
|
658 } |
|
659 |
|
660 api.registerChange(); |
|
661 api.refreshKeyboardAccessibility(); |
|
662 api.refreshAdvancedAccessibility(); |
|
663 $this.trigger( 'focus' ); |
|
664 wp.a11y.speak( menus.orderUpdated, 'polite' ); |
434 }, |
665 }, |
435 |
666 |
436 /** |
667 /** |
437 * refreshAdvancedAccessibilityOfItem( [itemToRefresh] ) |
668 * refreshAdvancedAccessibilityOfItem( [itemToRefresh] ) |
438 * |
669 * |
867 menuName.parent().removeClass( 'form-invalid' ); |
1100 menuName.parent().removeClass( 'form-invalid' ); |
868 } |
1101 } |
869 }, 500 ) ); |
1102 }, 500 ) ); |
870 |
1103 |
871 $('#add-custom-links input[type="text"]').on( 'keypress', function(e){ |
1104 $('#add-custom-links input[type="text"]').on( 'keypress', function(e){ |
872 $('#customlinkdiv').removeClass('form-invalid'); |
1105 $( '#customlinkdiv' ).removeClass( 'form-invalid' ); |
|
1106 $( '#custom-menu-item-url' ).removeAttr( 'aria-invalid' ).removeAttr( 'aria-describedby' ); |
|
1107 $( '#custom-url-error' ).hide(); |
873 |
1108 |
874 if ( e.keyCode === 13 ) { |
1109 if ( e.keyCode === 13 ) { |
875 e.preventDefault(); |
1110 e.preventDefault(); |
876 $( '#submit-customlinkdiv' ).trigger( 'click' ); |
1111 $( '#submit-customlinkdiv' ).trigger( 'click' ); |
|
1112 } |
|
1113 }); |
|
1114 |
|
1115 $( '#submit-customlinkdiv' ).on( 'click', function (e) { |
|
1116 var urlInput = $( '#custom-menu-item-url' ), |
|
1117 url = urlInput.val().trim(), |
|
1118 errorMessage = $( '#custom-url-error' ), |
|
1119 urlWrap = $( '#menu-item-url-wrap' ), |
|
1120 urlRegex; |
|
1121 |
|
1122 // Hide the error message initially |
|
1123 errorMessage.hide(); |
|
1124 urlWrap.removeClass( 'has-error' ); |
|
1125 |
|
1126 /* |
|
1127 * Allow URLs including: |
|
1128 * - http://example.com/ |
|
1129 * - //example.com |
|
1130 * - /directory/ |
|
1131 * - ?query-param |
|
1132 * - #target |
|
1133 * - mailto:foo@example.com |
|
1134 * |
|
1135 * Any further validation will be handled on the server when the setting is attempted to be saved, |
|
1136 * so this pattern does not need to be complete. |
|
1137 */ |
|
1138 urlRegex = /^((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#)/; |
|
1139 if ( ! urlRegex.test( url ) ) { |
|
1140 e.preventDefault(); |
|
1141 urlInput.addClass( 'form-invalid' ) |
|
1142 .attr( 'aria-invalid', 'true' ) |
|
1143 .attr( 'aria-describedby', 'custom-url-error' ); |
|
1144 |
|
1145 errorMessage.show(); |
|
1146 var errorText = errorMessage.text(); |
|
1147 urlWrap.addClass( 'has-error' ); |
|
1148 // Announce error message via screen reader |
|
1149 wp.a11y.speak( errorText, 'assertive' ); |
877 } |
1150 } |
878 }); |
1151 }); |
879 }, |
1152 }, |
880 |
1153 |
881 /** |
1154 /** |
1152 }); |
1427 }); |
1153 }, |
1428 }, |
1154 |
1429 |
1155 addCustomLink : function( processMethod ) { |
1430 addCustomLink : function( processMethod ) { |
1156 var url = $('#custom-menu-item-url').val().toString(), |
1431 var url = $('#custom-menu-item-url').val().toString(), |
1157 label = $('#custom-menu-item-name').val(); |
1432 label = $('#custom-menu-item-name').val(), |
|
1433 urlRegex; |
1158 |
1434 |
1159 if ( '' !== url ) { |
1435 if ( '' !== url ) { |
1160 url = url.trim(); |
1436 url = url.trim(); |
1161 } |
1437 } |
1162 |
1438 |
1163 processMethod = processMethod || api.addMenuItemToBottom; |
1439 processMethod = processMethod || api.addMenuItemToBottom; |
1164 |
1440 |
1165 if ( '' === url || 'https://' == url || 'http://' == url ) { |
1441 /* |
|
1442 * Allow URLs including: |
|
1443 * - http://example.com/ |
|
1444 * - //example.com |
|
1445 * - /directory/ |
|
1446 * - ?query-param |
|
1447 * - #target |
|
1448 * - mailto:foo@example.com |
|
1449 * |
|
1450 * Any further validation will be handled on the server when the setting is attempted to be saved, |
|
1451 * so this pattern does not need to be complete. |
|
1452 */ |
|
1453 urlRegex = /^((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#)/; |
|
1454 if ( ! urlRegex.test( url ) ) { |
1166 $('#customlinkdiv').addClass('form-invalid'); |
1455 $('#customlinkdiv').addClass('form-invalid'); |
1167 return false; |
1456 return false; |
1168 } |
1457 } |
1169 |
1458 |
1170 // Show the Ajax spinner. |
1459 // Show the Ajax spinner. |