| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @output wp-admin/js/customize-nav-menus.js | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | /* global _wpCustomizeNavMenusSettings, wpNavMenu, console */ | 
					
						
							|  |  |  | ( function( api, wp, $ ) { | 
					
						
							|  |  |  | 	'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Set up wpNavMenu for drag and drop. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	wpNavMenu.originalInit = wpNavMenu.init; | 
					
						
							|  |  |  | 	wpNavMenu.options.menuItemDepthPerLevel = 20; | 
					
						
							|  |  |  | 	wpNavMenu.options.sortableItems         = '> .customize-control-nav_menu_item'; | 
					
						
							|  |  |  | 	wpNavMenu.options.targetTolerance       = 10; | 
					
						
							|  |  |  | 	wpNavMenu.init = function() { | 
					
						
							|  |  |  | 		this.jQueryExtensions(); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @namespace wp.customize.Menus | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	api.Menus = api.Menus || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Link settings.
 | 
					
						
							|  |  |  | 	api.Menus.data = { | 
					
						
							|  |  |  | 		itemTypes: [], | 
					
						
							|  |  |  | 		l10n: {}, | 
					
						
							|  |  |  | 		settingTransport: 'refresh', | 
					
						
							|  |  |  | 		phpIntMax: 0, | 
					
						
							|  |  |  | 		defaultSettingValues: { | 
					
						
							|  |  |  | 			nav_menu: {}, | 
					
						
							|  |  |  | 			nav_menu_item: {} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		locationSlugMappedToName: {} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	if ( 'undefined' !== typeof _wpCustomizeNavMenusSettings ) { | 
					
						
							|  |  |  | 		$.extend( api.Menus.data, _wpCustomizeNavMenusSettings ); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Newly-created Nav Menus and Nav Menu Items have negative integer IDs which | 
					
						
							|  |  |  | 	 * serve as placeholders until Save & Publish happens. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus.generatePlaceholderAutoIncrementId | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @return {number} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.generatePlaceholderAutoIncrementId = function() { | 
					
						
							|  |  |  | 		return -Math.ceil( api.Menus.data.phpIntMax * Math.random() ); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.AvailableItemModel | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * A single available menu item model. See PHP's WP_Customize_Nav_Menu_Item_Setting class. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.AvailableItemModel | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments Backbone.Model | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.AvailableItemModel = Backbone.Model.extend( $.extend( | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			id: null // This is only used by Backbone.
 | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		api.Menus.data.defaultSettingValues.nav_menu_item | 
					
						
							|  |  |  | 	) ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.AvailableItemCollection | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Collection for available menu item models. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.AvailableItemCollection | 
					
						
							|  |  |  | 	 * @augments Backbone.Collection | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.AvailableItemCollection = Backbone.Collection.extend(/** @lends wp.customize.Menus.AvailableItemCollection.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		model: api.Menus.AvailableItemModel, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sort_key: 'order', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		comparator: function( item ) { | 
					
						
							|  |  |  | 			return -item.get( this.sort_key ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sortByField: function( fieldName ) { | 
					
						
							|  |  |  | 			this.sort_key = fieldName; | 
					
						
							|  |  |  | 			this.sort(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	api.Menus.availableMenuItems = new api.Menus.AvailableItemCollection( api.Menus.data.availableMenuItems ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Insert a new `auto-draft` post. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @since 4.7.0 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus.insertAutoDraftPost | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * | 
					
						
							|  |  |  | 	 * @param {object} params - Parameters for the draft post to create. | 
					
						
							|  |  |  | 	 * @param {string} params.post_type - Post type to add. | 
					
						
							|  |  |  | 	 * @param {string} params.post_title - Post title to use. | 
					
						
							|  |  |  | 	 * @return {jQuery.promise} Promise resolved with the added post. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.insertAutoDraftPost = function insertAutoDraftPost( params ) { | 
					
						
							|  |  |  | 		var request, deferred = $.Deferred(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		request = wp.ajax.post( 'customize-nav-menus-insert-auto-draft', { | 
					
						
							|  |  |  | 			'customize-menus-nonce': api.settings.nonce['customize-menus'], | 
					
						
							|  |  |  | 			'wp_customize': 'on', | 
					
						
							|  |  |  | 			'customize_changeset_uuid': api.settings.changeset.uuid, | 
					
						
							|  |  |  | 			'params': params | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		request.done( function( response ) { | 
					
						
							|  |  |  | 			if ( response.post_id ) { | 
					
						
							|  |  |  | 				api( 'nav_menus_created_posts' ).set( | 
					
						
							|  |  |  | 					api( 'nav_menus_created_posts' ).get().concat( [ response.post_id ] ) | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( 'page' === params.post_type ) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Activate static front page controls as this could be the first page created.
 | 
					
						
							|  |  |  | 					if ( api.section.has( 'static_front_page' ) ) { | 
					
						
							|  |  |  | 						api.section( 'static_front_page' ).activate(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Add new page to dropdown-pages controls.
 | 
					
						
							|  |  |  | 					api.control.each( function( control ) { | 
					
						
							|  |  |  | 						var select; | 
					
						
							|  |  |  | 						if ( 'dropdown-pages' === control.params.type ) { | 
					
						
							|  |  |  | 							select = control.container.find( 'select[name^="_customize-dropdown-pages-"]' ); | 
					
						
							|  |  |  | 							select.append( new Option( params.post_title, response.post_id ) ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				deferred.resolve( response ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		request.fail( function( response ) { | 
					
						
							|  |  |  | 			var error = response || ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( 'undefined' !== typeof response.message ) { | 
					
						
							|  |  |  | 				error = response.message; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			console.error( error ); | 
					
						
							|  |  |  | 			deferred.rejectWith( error ); | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return deferred.promise(); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.AvailableMenuItemsPanelView = wp.Backbone.View.extend(/** @lends wp.customize.Menus.AvailableMenuItemsPanelView.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		el: '#available-menu-items', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		events: { | 
					
						
							|  |  |  | 			'input #menu-items-search': 'debounceSearch', | 
					
						
							|  |  |  | 			'focus .menu-item-tpl': 'focus', | 
					
						
							|  |  |  | 			'click .menu-item-tpl': '_submit', | 
					
						
							|  |  |  | 			'click #custom-menu-item-submit': '_submitLink', | 
					
						
							|  |  |  | 			'keypress #custom-menu-item-name': '_submitLink', | 
					
						
							|  |  |  | 			'click .new-content-item .add-content': '_submitNew', | 
					
						
							|  |  |  | 			'keypress .create-item-input': '_submitNew', | 
					
						
							|  |  |  | 			'keydown': 'keyboardAccessible' | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Cache current selected menu item.
 | 
					
						
							|  |  |  | 		selected: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Cache menu control that opened the panel.
 | 
					
						
							|  |  |  | 		currentMenuControl: null, | 
					
						
							|  |  |  | 		debounceSearch: null, | 
					
						
							|  |  |  | 		$search: null, | 
					
						
							|  |  |  | 		$clearResults: null, | 
					
						
							|  |  |  | 		searchTerm: '', | 
					
						
							|  |  |  | 		rendered: false, | 
					
						
							|  |  |  | 		pages: {}, | 
					
						
							|  |  |  | 		sectionContent: '', | 
					
						
							|  |  |  | 		loading: false, | 
					
						
							|  |  |  | 		addingNew: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * wp.customize.Menus.AvailableMenuItemsPanelView | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * View class for the available menu items panel. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @constructs wp.customize.Menus.AvailableMenuItemsPanelView | 
					
						
							|  |  |  | 		 * @augments   wp.Backbone.View | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		initialize: function() { | 
					
						
							|  |  |  | 			var self = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! api.panel.has( 'nav_menus' ) ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.$search = $( '#menu-items-search' ); | 
					
						
							|  |  |  | 			this.$clearResults = this.$el.find( '.clear-results' ); | 
					
						
							|  |  |  | 			this.sectionContent = this.$el.find( '.available-menu-items-list' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.debounceSearch = _.debounce( self.search, 500 ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			_.bindAll( this, 'close' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// If the available menu items panel is open and the customize controls are
 | 
					
						
							|  |  |  | 			// interacted with (other than an item being deleted), then close the
 | 
					
						
							|  |  |  | 			// available menu items panel. Also close on back button click.
 | 
					
						
							|  |  |  | 			$( '#customize-controls, .customize-section-back' ).on( 'click keydown', function( e ) { | 
					
						
							|  |  |  | 				var isDeleteBtn = $( e.target ).is( '.item-delete, .item-delete *' ), | 
					
						
							|  |  |  | 					isAddNewBtn = $( e.target ).is( '.add-new-menu-item, .add-new-menu-item *' ); | 
					
						
							|  |  |  | 				if ( $( 'body' ).hasClass( 'adding-menu-items' ) && ! isDeleteBtn && ! isAddNewBtn ) { | 
					
						
							|  |  |  | 					self.close(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Clear the search results and trigger a `keyup` event to fire a new search.
 | 
					
						
							|  |  |  | 			this.$clearResults.on( 'click', function() { | 
					
						
							|  |  |  | 				self.$search.val( '' ).focus().trigger( 'keyup' ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.$el.on( 'input', '#custom-menu-item-name.invalid, #custom-menu-item-url.invalid', function() { | 
					
						
							|  |  |  | 				$( this ).removeClass( 'invalid' ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Load available items if it looks like we'll need them.
 | 
					
						
							|  |  |  | 			api.panel( 'nav_menus' ).container.bind( 'expanded', function() { | 
					
						
							|  |  |  | 				if ( ! self.rendered ) { | 
					
						
							|  |  |  | 					self.initList(); | 
					
						
							|  |  |  | 					self.rendered = true; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Load more items.
 | 
					
						
							|  |  |  | 			this.sectionContent.scroll( function() { | 
					
						
							|  |  |  | 				var totalHeight = self.$el.find( '.accordion-section.open .available-menu-items-list' ).prop( 'scrollHeight' ), | 
					
						
							|  |  |  | 					visibleHeight = self.$el.find( '.accordion-section.open' ).height(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( ! self.loading && $( this ).scrollTop() > 3 / 4 * totalHeight - visibleHeight ) { | 
					
						
							|  |  |  | 					var type = $( this ).data( 'type' ), | 
					
						
							|  |  |  | 						object = $( this ).data( 'object' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if ( 'search' === type ) { | 
					
						
							|  |  |  | 						if ( self.searchTerm ) { | 
					
						
							|  |  |  | 							self.doSearch( self.pages.search ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						self.loadItems( [ | 
					
						
							|  |  |  | 							{ type: type, object: object } | 
					
						
							|  |  |  | 						] ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Close the panel if the URL in the preview changes
 | 
					
						
							|  |  |  | 			api.previewer.bind( 'url', this.close ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			self.delegateEvents(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Search input change handler.
 | 
					
						
							|  |  |  | 		search: function( event ) { | 
					
						
							|  |  |  | 			var $searchSection = $( '#available-menu-items-search' ), | 
					
						
							|  |  |  | 				$otherSections = $( '#available-menu-items .accordion-section' ).not( $searchSection ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! event ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( this.searchTerm === event.target.value ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( '' !== event.target.value && ! $searchSection.hasClass( 'open' ) ) { | 
					
						
							|  |  |  | 				$otherSections.fadeOut( 100 ); | 
					
						
							|  |  |  | 				$searchSection.find( '.accordion-section-content' ).slideDown( 'fast' ); | 
					
						
							|  |  |  | 				$searchSection.addClass( 'open' ); | 
					
						
							|  |  |  | 				this.$clearResults.addClass( 'is-visible' ); | 
					
						
							|  |  |  | 			} else if ( '' === event.target.value ) { | 
					
						
							|  |  |  | 				$searchSection.removeClass( 'open' ); | 
					
						
							|  |  |  | 				$otherSections.show(); | 
					
						
							|  |  |  | 				this.$clearResults.removeClass( 'is-visible' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.searchTerm = event.target.value; | 
					
						
							|  |  |  | 			this.pages.search = 1; | 
					
						
							|  |  |  | 			this.doSearch( 1 ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Get search results.
 | 
					
						
							|  |  |  | 		doSearch: function( page ) { | 
					
						
							|  |  |  | 			var self = this, params, | 
					
						
							|  |  |  | 				$section = $( '#available-menu-items-search' ), | 
					
						
							|  |  |  | 				$content = $section.find( '.accordion-section-content' ), | 
					
						
							|  |  |  | 				itemTemplate = wp.template( 'available-menu-item' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( self.currentRequest ) { | 
					
						
							|  |  |  | 				self.currentRequest.abort(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( page < 0 ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} else if ( page > 1 ) { | 
					
						
							|  |  |  | 				$section.addClass( 'loading-more' ); | 
					
						
							|  |  |  | 				$content.attr( 'aria-busy', 'true' ); | 
					
						
							|  |  |  | 				wp.a11y.speak( api.Menus.data.l10n.itemsLoadingMore ); | 
					
						
							|  |  |  | 			} else if ( '' === self.searchTerm ) { | 
					
						
							|  |  |  | 				$content.html( '' ); | 
					
						
							|  |  |  | 				wp.a11y.speak( '' ); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$section.addClass( 'loading' ); | 
					
						
							|  |  |  | 			self.loading = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			params = api.previewer.query( { excludeCustomizedSaved: true } ); | 
					
						
							|  |  |  | 			_.extend( params, { | 
					
						
							|  |  |  | 				'customize-menus-nonce': api.settings.nonce['customize-menus'], | 
					
						
							|  |  |  | 				'wp_customize': 'on', | 
					
						
							|  |  |  | 				'search': self.searchTerm, | 
					
						
							|  |  |  | 				'page': page | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			self.currentRequest = wp.ajax.post( 'search-available-menu-items-customizer', params ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			self.currentRequest.done(function( data ) { | 
					
						
							|  |  |  | 				var items; | 
					
						
							|  |  |  | 				if ( 1 === page ) { | 
					
						
							|  |  |  | 					// Clear previous results as it's a new search.
 | 
					
						
							|  |  |  | 					$content.empty(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				$section.removeClass( 'loading loading-more' ); | 
					
						
							|  |  |  | 				$content.attr( 'aria-busy', 'false' ); | 
					
						
							|  |  |  | 				$section.addClass( 'open' ); | 
					
						
							|  |  |  | 				self.loading = false; | 
					
						
							|  |  |  | 				items = new api.Menus.AvailableItemCollection( data.items ); | 
					
						
							|  |  |  | 				self.collection.add( items.models ); | 
					
						
							|  |  |  | 				items.each( function( menuItem ) { | 
					
						
							|  |  |  | 					$content.append( itemTemplate( menuItem.attributes ) ); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				if ( 20 > items.length ) { | 
					
						
							|  |  |  | 					self.pages.search = -1; // Up to 20 posts and 20 terms in results, if <20, no more results for either.
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					self.pages.search = self.pages.search + 1; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if ( items && page > 1 ) { | 
					
						
							|  |  |  | 					wp.a11y.speak( api.Menus.data.l10n.itemsFoundMore.replace( '%d', items.length ) ); | 
					
						
							|  |  |  | 				} else if ( items && page === 1 ) { | 
					
						
							|  |  |  | 					wp.a11y.speak( api.Menus.data.l10n.itemsFound.replace( '%d', items.length ) ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			self.currentRequest.fail(function( data ) { | 
					
						
							|  |  |  | 				// data.message may be undefined, for example when typing slow and the request is aborted.
 | 
					
						
							|  |  |  | 				if ( data.message ) { | 
					
						
							|  |  |  | 					$content.empty().append( $( '<li class="nothing-found"></li>' ).text( data.message ) ); | 
					
						
							|  |  |  | 					wp.a11y.speak( data.message ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				self.pages.search = -1; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			self.currentRequest.always(function() { | 
					
						
							|  |  |  | 				$section.removeClass( 'loading loading-more' ); | 
					
						
							|  |  |  | 				$content.attr( 'aria-busy', 'false' ); | 
					
						
							|  |  |  | 				self.loading = false; | 
					
						
							|  |  |  | 				self.currentRequest = null; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Render the individual items.
 | 
					
						
							|  |  |  | 		initList: function() { | 
					
						
							|  |  |  | 			var self = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Render the template for each item by type.
 | 
					
						
							|  |  |  | 			_.each( api.Menus.data.itemTypes, function( itemType ) { | 
					
						
							|  |  |  | 				self.pages[ itemType.type + ':' + itemType.object ] = 0; | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 			self.loadItems( api.Menus.data.itemTypes ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Load available nav menu items. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 * @since 4.7.0 Changed function signature to take list of item types instead of single type/object. | 
					
						
							|  |  |  | 		 * @access private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Array.<object>} itemTypes List of objects containing type and key. | 
					
						
							|  |  |  | 		 * @param {string} deprecated Formerly the object parameter. | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		loadItems: function( itemTypes, deprecated ) { | 
					
						
							|  |  |  | 			var self = this, _itemTypes, requestItemTypes = [], params, request, itemTemplate, availableMenuItemContainers = {}; | 
					
						
							|  |  |  | 			itemTemplate = wp.template( 'available-menu-item' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( _.isString( itemTypes ) && _.isString( deprecated ) ) { | 
					
						
							|  |  |  | 				_itemTypes = [ { type: itemTypes, object: deprecated } ]; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				_itemTypes = itemTypes; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			_.each( _itemTypes, function( itemType ) { | 
					
						
							|  |  |  | 				var container, name = itemType.type + ':' + itemType.object; | 
					
						
							|  |  |  | 				if ( -1 === self.pages[ name ] ) { | 
					
						
							|  |  |  | 					return; // Skip types for which there are no more results.
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				container = $( '#available-menu-items-' + itemType.type + '-' + itemType.object ); | 
					
						
							|  |  |  | 				container.find( '.accordion-section-title' ).addClass( 'loading' ); | 
					
						
							|  |  |  | 				availableMenuItemContainers[ name ] = container; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				requestItemTypes.push( { | 
					
						
							|  |  |  | 					object: itemType.object, | 
					
						
							|  |  |  | 					type: itemType.type, | 
					
						
							|  |  |  | 					page: self.pages[ name ] | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( 0 === requestItemTypes.length ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			self.loading = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			params = api.previewer.query( { excludeCustomizedSaved: true } ); | 
					
						
							|  |  |  | 			_.extend( params, { | 
					
						
							|  |  |  | 				'customize-menus-nonce': api.settings.nonce['customize-menus'], | 
					
						
							|  |  |  | 				'wp_customize': 'on', | 
					
						
							|  |  |  | 				'item_types': requestItemTypes | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			request = wp.ajax.post( 'load-available-menu-items-customizer', params ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			request.done(function( data ) { | 
					
						
							|  |  |  | 				var typeInner; | 
					
						
							|  |  |  | 				_.each( data.items, function( typeItems, name ) { | 
					
						
							|  |  |  | 					if ( 0 === typeItems.length ) { | 
					
						
							|  |  |  | 						if ( 0 === self.pages[ name ] ) { | 
					
						
							|  |  |  | 							availableMenuItemContainers[ name ].find( '.accordion-section-title' ) | 
					
						
							|  |  |  | 								.addClass( 'cannot-expand' ) | 
					
						
							|  |  |  | 								.removeClass( 'loading' ) | 
					
						
							|  |  |  | 								.find( '.accordion-section-title > button' ) | 
					
						
							|  |  |  | 								.prop( 'tabIndex', -1 ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						self.pages[ name ] = -1; | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} else if ( ( 'post_type:page' === name ) && ( ! availableMenuItemContainers[ name ].hasClass( 'open' ) ) ) { | 
					
						
							|  |  |  | 						availableMenuItemContainers[ name ].find( '.accordion-section-title > button' ).click(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					typeItems = new api.Menus.AvailableItemCollection( typeItems ); // @todo Why is this collection created and then thrown away?
 | 
					
						
							|  |  |  | 					self.collection.add( typeItems.models ); | 
					
						
							|  |  |  | 					typeInner = availableMenuItemContainers[ name ].find( '.available-menu-items-list' ); | 
					
						
							|  |  |  | 					typeItems.each( function( menuItem ) { | 
					
						
							|  |  |  | 						typeInner.append( itemTemplate( menuItem.attributes ) ); | 
					
						
							|  |  |  | 					} ); | 
					
						
							|  |  |  | 					self.pages[ name ] += 1; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			request.fail(function( data ) { | 
					
						
							|  |  |  | 				if ( typeof console !== 'undefined' && console.error ) { | 
					
						
							|  |  |  | 					console.error( data ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			request.always(function() { | 
					
						
							|  |  |  | 				_.each( availableMenuItemContainers, function( container ) { | 
					
						
							|  |  |  | 					container.find( '.accordion-section-title' ).removeClass( 'loading' ); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				self.loading = false; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Adjust the height of each section of items to fit the screen.
 | 
					
						
							|  |  |  | 		itemSectionHeight: function() { | 
					
						
							|  |  |  | 			var sections, lists, totalHeight, accordionHeight, diff; | 
					
						
							|  |  |  | 			totalHeight = window.innerHeight; | 
					
						
							|  |  |  | 			sections = this.$el.find( '.accordion-section:not( #available-menu-items-search ) .accordion-section-content' ); | 
					
						
							|  |  |  | 			lists = this.$el.find( '.accordion-section:not( #available-menu-items-search ) .available-menu-items-list:not(":only-child")' ); | 
					
						
							|  |  |  | 			accordionHeight =  46 * ( 1 + sections.length ) + 14; // Magic numbers.
 | 
					
						
							|  |  |  | 			diff = totalHeight - accordionHeight; | 
					
						
							|  |  |  | 			if ( 120 < diff && 290 > diff ) { | 
					
						
							|  |  |  | 				sections.css( 'max-height', diff ); | 
					
						
							|  |  |  | 				lists.css( 'max-height', ( diff - 60 ) ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Highlights a menu item.
 | 
					
						
							|  |  |  | 		select: function( menuitemTpl ) { | 
					
						
							|  |  |  | 			this.selected = $( menuitemTpl ); | 
					
						
							|  |  |  | 			this.selected.siblings( '.menu-item-tpl' ).removeClass( 'selected' ); | 
					
						
							|  |  |  | 			this.selected.addClass( 'selected' ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Highlights a menu item on focus.
 | 
					
						
							|  |  |  | 		focus: function( event ) { | 
					
						
							|  |  |  | 			this.select( $( event.currentTarget ) ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Submit handler for keypress and click on menu item.
 | 
					
						
							|  |  |  | 		_submit: function( event ) { | 
					
						
							|  |  |  | 			// Only proceed with keypress if it is Enter or Spacebar
 | 
					
						
							|  |  |  | 			if ( 'keypress' === event.type && ( 13 !== event.which && 32 !== event.which ) ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.submit( $( event.currentTarget ) ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Adds a selected menu item to the menu.
 | 
					
						
							|  |  |  | 		submit: function( menuitemTpl ) { | 
					
						
							|  |  |  | 			var menuitemId, menu_item; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! menuitemTpl ) { | 
					
						
							|  |  |  | 				menuitemTpl = this.selected; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! menuitemTpl || ! this.currentMenuControl ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.select( menuitemTpl ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuitemId = $( this.selected ).data( 'menu-item-id' ); | 
					
						
							|  |  |  | 			menu_item = this.collection.findWhere( { id: menuitemId } ); | 
					
						
							|  |  |  | 			if ( ! menu_item ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.currentMenuControl.addItemToMenu( menu_item.attributes ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$( menuitemTpl ).find( '.menu-item-handle' ).addClass( 'item-added' ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Submit handler for keypress and click on custom menu item.
 | 
					
						
							|  |  |  | 		_submitLink: function( event ) { | 
					
						
							|  |  |  | 			// Only proceed with keypress if it is Enter.
 | 
					
						
							|  |  |  | 			if ( 'keypress' === event.type && 13 !== event.which ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.submitLink(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Adds the custom menu item to the menu.
 | 
					
						
							|  |  |  | 		submitLink: function() { | 
					
						
							|  |  |  | 			var menuItem, | 
					
						
							|  |  |  | 				itemName = $( '#custom-menu-item-name' ), | 
					
						
							|  |  |  | 				itemUrl = $( '#custom-menu-item-url' ), | 
					
						
							|  |  |  | 				urlRegex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! this.currentMenuControl ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			 * Allow URLs including: | 
					
						
							|  |  |  | 			 * - http://example.com/
 | 
					
						
							|  |  |  | 			 * - //example.com
 | 
					
						
							|  |  |  | 			 * - /directory/ | 
					
						
							|  |  |  | 			 * - ?query-param | 
					
						
							|  |  |  | 			 * - #target | 
					
						
							|  |  |  | 			 * - mailto:foo@example.com | 
					
						
							|  |  |  | 			 * | 
					
						
							|  |  |  | 			 * Any further validation will be handled on the server when the setting is attempted to be saved, | 
					
						
							|  |  |  | 			 * so this pattern does not need to be complete. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			urlRegex = /^((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#)/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( '' === itemName.val() ) { | 
					
						
							|  |  |  | 				itemName.addClass( 'invalid' ); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} else if ( ! urlRegex.test( itemUrl.val() ) ) { | 
					
						
							|  |  |  | 				itemUrl.addClass( 'invalid' ); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuItem = { | 
					
						
							|  |  |  | 				'title': itemName.val(), | 
					
						
							|  |  |  | 				'url': itemUrl.val(), | 
					
						
							|  |  |  | 				'type': 'custom', | 
					
						
							|  |  |  | 				'type_label': api.Menus.data.l10n.custom_label, | 
					
						
							|  |  |  | 				'object': 'custom' | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.currentMenuControl.addItemToMenu( menuItem ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Reset the custom link form.
 | 
					
						
							|  |  |  | 			itemUrl.val( 'http://' ); | 
					
						
							|  |  |  | 			itemName.val( '' ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Submit handler for keypress (enter) on field and click on button. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.7.0 | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {jQuery.Event} event Event. | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_submitNew: function( event ) { | 
					
						
							|  |  |  | 			var container; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Only proceed with keypress if it is Enter.
 | 
					
						
							|  |  |  | 			if ( 'keypress' === event.type && 13 !== event.which ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( this.addingNew ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			container = $( event.target ).closest( '.accordion-section' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.submitNew( container ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Creates a new object and adds an associated menu item to the menu. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.7.0 | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {jQuery} container | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		submitNew: function( container ) { | 
					
						
							|  |  |  | 			var panel = this, | 
					
						
							|  |  |  | 				itemName = container.find( '.create-item-input' ), | 
					
						
							|  |  |  | 				title = itemName.val(), | 
					
						
							|  |  |  | 				dataContainer = container.find( '.available-menu-items-list' ), | 
					
						
							|  |  |  | 				itemType = dataContainer.data( 'type' ), | 
					
						
							|  |  |  | 				itemObject = dataContainer.data( 'object' ), | 
					
						
							|  |  |  | 				itemTypeLabel = dataContainer.data( 'type_label' ), | 
					
						
							|  |  |  | 				promise; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! this.currentMenuControl ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Only posts are supported currently.
 | 
					
						
							|  |  |  | 			if ( 'post_type' !== itemType ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( '' === $.trim( itemName.val() ) ) { | 
					
						
							|  |  |  | 				itemName.addClass( 'invalid' ); | 
					
						
							|  |  |  | 				itemName.focus(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				itemName.removeClass( 'invalid' ); | 
					
						
							|  |  |  | 				container.find( '.accordion-section-title' ).addClass( 'loading' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			panel.addingNew = true; | 
					
						
							|  |  |  | 			itemName.attr( 'disabled', 'disabled' ); | 
					
						
							|  |  |  | 			promise = api.Menus.insertAutoDraftPost( { | 
					
						
							|  |  |  | 				post_title: title, | 
					
						
							|  |  |  | 				post_type: itemObject | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 			promise.done( function( data ) { | 
					
						
							|  |  |  | 				var availableItem, $content, itemElement; | 
					
						
							|  |  |  | 				availableItem = new api.Menus.AvailableItemModel( { | 
					
						
							|  |  |  | 					'id': 'post-' + data.post_id, // Used for available menu item Backbone models.
 | 
					
						
							|  |  |  | 					'title': itemName.val(), | 
					
						
							|  |  |  | 					'type': itemType, | 
					
						
							|  |  |  | 					'type_label': itemTypeLabel, | 
					
						
							|  |  |  | 					'object': itemObject, | 
					
						
							|  |  |  | 					'object_id': data.post_id, | 
					
						
							|  |  |  | 					'url': data.url | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add new item to menu.
 | 
					
						
							|  |  |  | 				panel.currentMenuControl.addItemToMenu( availableItem.attributes ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add the new item to the list of available items.
 | 
					
						
							|  |  |  | 				api.Menus.availableMenuItemsPanel.collection.add( availableItem ); | 
					
						
							|  |  |  | 				$content = container.find( '.available-menu-items-list' ); | 
					
						
							|  |  |  | 				itemElement = $( wp.template( 'available-menu-item' )( availableItem.attributes ) ); | 
					
						
							|  |  |  | 				itemElement.find( '.menu-item-handle:first' ).addClass( 'item-added' ); | 
					
						
							|  |  |  | 				$content.prepend( itemElement ); | 
					
						
							|  |  |  | 				$content.scrollTop(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Reset the create content form.
 | 
					
						
							|  |  |  | 				itemName.val( '' ).removeAttr( 'disabled' ); | 
					
						
							|  |  |  | 				panel.addingNew = false; | 
					
						
							|  |  |  | 				container.find( '.accordion-section-title' ).removeClass( 'loading' ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Opens the panel.
 | 
					
						
							|  |  |  | 		open: function( menuControl ) { | 
					
						
							|  |  |  | 			var panel = this, close; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.currentMenuControl = menuControl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.itemSectionHeight(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( api.section.has( 'publish_settings' ) ) { | 
					
						
							|  |  |  | 				api.section( 'publish_settings' ).collapse(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$( 'body' ).addClass( 'adding-menu-items' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			close = function() { | 
					
						
							|  |  |  | 				panel.close(); | 
					
						
							|  |  |  | 				$( this ).off( 'click', close ); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			$( '#customize-preview' ).on( 'click', close ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Collapse all controls.
 | 
					
						
							|  |  |  | 			_( this.currentMenuControl.getMenuItemControls() ).each( function( control ) { | 
					
						
							|  |  |  | 				control.collapseForm(); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.$el.find( '.selected' ).removeClass( 'selected' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.$search.focus(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Closes the panel
 | 
					
						
							|  |  |  | 		close: function( options ) { | 
					
						
							|  |  |  | 			options = options || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( options.returnFocus && this.currentMenuControl ) { | 
					
						
							|  |  |  | 				this.currentMenuControl.container.find( '.add-new-menu-item' ).focus(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.currentMenuControl = null; | 
					
						
							|  |  |  | 			this.selected = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$( 'body' ).removeClass( 'adding-menu-items' ); | 
					
						
							|  |  |  | 			$( '#available-menu-items .menu-item-handle.item-added' ).removeClass( 'item-added' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.$search.val( '' ).trigger( 'keyup' ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Add a few keyboard enhancements to the panel.
 | 
					
						
							|  |  |  | 		keyboardAccessible: function( event ) { | 
					
						
							|  |  |  | 			var isEnter = ( 13 === event.which ), | 
					
						
							|  |  |  | 				isEsc = ( 27 === event.which ), | 
					
						
							|  |  |  | 				isBackTab = ( 9 === event.which && event.shiftKey ), | 
					
						
							|  |  |  | 				isSearchFocused = $( event.target ).is( this.$search ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// If enter pressed but nothing entered, don't do anything
 | 
					
						
							|  |  |  | 			if ( isEnter && ! this.$search.val() ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( isSearchFocused && isBackTab ) { | 
					
						
							|  |  |  | 				this.currentMenuControl.container.find( '.add-new-menu-item' ).focus(); | 
					
						
							|  |  |  | 				event.preventDefault(); // Avoid additional back-tab.
 | 
					
						
							|  |  |  | 			} else if ( isEsc ) { | 
					
						
							|  |  |  | 				this.close( { returnFocus: true } ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenusPanel | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer panel for menus. This is used only for screen options management. | 
					
						
							|  |  |  | 	 * Note that 'menus' must match the WP_Customize_Menu_Panel::$type. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenusPanel | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Panel | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenusPanel = api.Panel.extend(/** @lends wp.customize.Menus.MenusPanel.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		attachEvents: function() { | 
					
						
							|  |  |  | 			api.Panel.prototype.attachEvents.call( this ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var panel = this, | 
					
						
							|  |  |  | 				panelMeta = panel.container.find( '.panel-meta' ), | 
					
						
							|  |  |  | 				help = panelMeta.find( '.customize-help-toggle' ), | 
					
						
							|  |  |  | 				content = panelMeta.find( '.customize-panel-description' ), | 
					
						
							|  |  |  | 				options = $( '#screen-options-wrap' ), | 
					
						
							|  |  |  | 				button = panelMeta.find( '.customize-screen-options-toggle' ); | 
					
						
							|  |  |  | 			button.on( 'click keydown', function( event ) { | 
					
						
							|  |  |  | 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				event.preventDefault(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Hide description
 | 
					
						
							|  |  |  | 				if ( content.not( ':hidden' ) ) { | 
					
						
							|  |  |  | 					content.slideUp( 'fast' ); | 
					
						
							|  |  |  | 					help.attr( 'aria-expanded', 'false' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( 'true' === button.attr( 'aria-expanded' ) ) { | 
					
						
							|  |  |  | 					button.attr( 'aria-expanded', 'false' ); | 
					
						
							|  |  |  | 					panelMeta.removeClass( 'open' ); | 
					
						
							|  |  |  | 					panelMeta.removeClass( 'active-menu-screen-options' ); | 
					
						
							|  |  |  | 					options.slideUp( 'fast' ); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					button.attr( 'aria-expanded', 'true' ); | 
					
						
							|  |  |  | 					panelMeta.addClass( 'open' ); | 
					
						
							|  |  |  | 					panelMeta.addClass( 'active-menu-screen-options' ); | 
					
						
							|  |  |  | 					options.slideDown( 'fast' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Help toggle
 | 
					
						
							|  |  |  | 			help.on( 'click keydown', function( event ) { | 
					
						
							|  |  |  | 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				event.preventDefault(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( 'true' === button.attr( 'aria-expanded' ) ) { | 
					
						
							|  |  |  | 					button.attr( 'aria-expanded', 'false' ); | 
					
						
							|  |  |  | 					help.attr( 'aria-expanded', 'true' ); | 
					
						
							|  |  |  | 					panelMeta.addClass( 'open' ); | 
					
						
							|  |  |  | 					panelMeta.removeClass( 'active-menu-screen-options' ); | 
					
						
							|  |  |  | 					options.slideUp( 'fast' ); | 
					
						
							|  |  |  | 					content.slideDown( 'fast' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Update field visibility when clicking on the field toggles. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			var panel = this; | 
					
						
							|  |  |  | 			panel.container.find( '.hide-column-tog' ).click( function() { | 
					
						
							|  |  |  | 				panel.saveManageColumnsState(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Inject additional heading into the menu locations section's head container.
 | 
					
						
							|  |  |  | 			api.section( 'menu_locations', function( section ) { | 
					
						
							|  |  |  | 				section.headContainer.prepend( | 
					
						
							|  |  |  | 					wp.template( 'nav-menu-locations-header' )( api.Menus.data ) | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Save hidden column states. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		saveManageColumnsState: _.debounce( function() { | 
					
						
							|  |  |  | 			var panel = this; | 
					
						
							|  |  |  | 			if ( panel._updateHiddenColumnsRequest ) { | 
					
						
							|  |  |  | 				panel._updateHiddenColumnsRequest.abort(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			panel._updateHiddenColumnsRequest = wp.ajax.post( 'hidden-columns', { | 
					
						
							|  |  |  | 				hidden: panel.hidden(), | 
					
						
							|  |  |  | 				screenoptionnonce: $( '#screenoptionnonce' ).val(), | 
					
						
							|  |  |  | 				page: 'nav-menus' | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 			panel._updateHiddenColumnsRequest.always( function() { | 
					
						
							|  |  |  | 				panel._updateHiddenColumnsRequest = null; | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, 2000 ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @deprecated Since 4.7.0 now that the nav_menu sections are responsible for toggling the classes on their own containers. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		checked: function() {}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @deprecated Since 4.7.0 now that the nav_menu sections are responsible for toggling the classes on their own containers. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		unchecked: function() {}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Get hidden fields. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @returns {Array} Fields (columns) that are hidden. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		hidden: function() { | 
					
						
							|  |  |  | 			return $( '.hide-column-tog' ).not( ':checked' ).map( function() { | 
					
						
							|  |  |  | 				var id = this.id; | 
					
						
							|  |  |  | 				return id.substring( 0, id.length - 5 ); | 
					
						
							|  |  |  | 			}).get().join( ',' ); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenuSection | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer section for menus. This is used only for lazy-loading child controls. | 
					
						
							|  |  |  | 	 * Note that 'nav_menu' must match the WP_Customize_Menu_Section::$type. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenuSection | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Section | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuSection = api.Section.extend(/** @lends wp.customize.Menus.MenuSection.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Initialize. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {String} id | 
					
						
							|  |  |  | 		 * @param {Object} options | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		initialize: function( id, options ) { | 
					
						
							|  |  |  | 			var section = this; | 
					
						
							|  |  |  | 			api.Section.prototype.initialize.call( section, id, options ); | 
					
						
							|  |  |  | 			section.deferred.initSortables = $.Deferred(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Ready. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			var section = this, fieldActiveToggles, handleFieldActiveToggle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( 'undefined' === typeof section.params.menu_id ) { | 
					
						
							|  |  |  | 				throw new Error( 'params.menu_id was not defined' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			 * Since newly created sections won't be registered in PHP, we need to prevent the | 
					
						
							|  |  |  | 			 * preview's sending of the activeSections to result in this control | 
					
						
							|  |  |  | 			 * being deactivated when the preview refreshes. So we can hook onto | 
					
						
							|  |  |  | 			 * the setting that has the same ID and its presence can dictate | 
					
						
							|  |  |  | 			 * whether the section is active. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			section.active.validate = function() { | 
					
						
							|  |  |  | 				if ( ! api.has( section.id ) ) { | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return !! api( section.id ).get(); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			section.populateControls(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			section.navMenuLocationSettings = {}; | 
					
						
							|  |  |  | 			section.assignedLocations = new api.Value( [] ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.each(function( setting, id ) { | 
					
						
							|  |  |  | 				var matches = id.match( /^nav_menu_locations\[(.+?)]/ ); | 
					
						
							|  |  |  | 				if ( matches ) { | 
					
						
							|  |  |  | 					section.navMenuLocationSettings[ matches[1] ] = setting; | 
					
						
							|  |  |  | 					setting.bind( function() { | 
					
						
							|  |  |  | 						section.refreshAssignedLocations(); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			section.assignedLocations.bind(function( to ) { | 
					
						
							|  |  |  | 				section.updateAssignedLocationsInSectionTitle( to ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			section.refreshAssignedLocations(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.bind( 'pane-contents-reflowed', function() { | 
					
						
							|  |  |  | 				// Skip menus that have been removed.
 | 
					
						
							|  |  |  | 				if ( ! section.contentContainer.parent().length ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				section.container.find( '.menu-item .menu-item-reorder-nav button' ).attr({ 'tabindex': '0', 'aria-hidden': 'false' }); | 
					
						
							|  |  |  | 				section.container.find( '.menu-item.move-up-disabled .menus-move-up' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' }); | 
					
						
							|  |  |  | 				section.container.find( '.menu-item.move-down-disabled .menus-move-down' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' }); | 
					
						
							|  |  |  | 				section.container.find( '.menu-item.move-left-disabled .menus-move-left' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' }); | 
					
						
							|  |  |  | 				section.container.find( '.menu-item.move-right-disabled .menus-move-right' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' }); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * Update the active field class for the content container for a given checkbox toggle. | 
					
						
							|  |  |  | 			 * | 
					
						
							|  |  |  | 			 * @this {jQuery} | 
					
						
							|  |  |  | 			 * @returns {void} | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			handleFieldActiveToggle = function() { | 
					
						
							|  |  |  | 				var className = 'field-' + $( this ).val() + '-active'; | 
					
						
							|  |  |  | 				section.contentContainer.toggleClass( className, $( this ).prop( 'checked' ) ); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			fieldActiveToggles = api.panel( 'nav_menus' ).contentContainer.find( '.metabox-prefs:first' ).find( '.hide-column-tog' ); | 
					
						
							|  |  |  | 			fieldActiveToggles.each( handleFieldActiveToggle ); | 
					
						
							|  |  |  | 			fieldActiveToggles.on( 'click', handleFieldActiveToggle ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		populateControls: function() { | 
					
						
							|  |  |  | 			var section = this, | 
					
						
							|  |  |  | 				menuNameControlId, | 
					
						
							|  |  |  | 				menuLocationsControlId, | 
					
						
							|  |  |  | 				menuAutoAddControlId, | 
					
						
							|  |  |  | 				menuDeleteControlId, | 
					
						
							|  |  |  | 				menuControl, | 
					
						
							|  |  |  | 				menuNameControl, | 
					
						
							|  |  |  | 				menuLocationsControl, | 
					
						
							|  |  |  | 				menuAutoAddControl, | 
					
						
							|  |  |  | 				menuDeleteControl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the control for managing the menu name.
 | 
					
						
							|  |  |  | 			menuNameControlId = section.id + '[name]'; | 
					
						
							|  |  |  | 			menuNameControl = api.control( menuNameControlId ); | 
					
						
							|  |  |  | 			if ( ! menuNameControl ) { | 
					
						
							|  |  |  | 				menuNameControl = new api.controlConstructor.nav_menu_name( menuNameControlId, { | 
					
						
							|  |  |  | 					type: 'nav_menu_name', | 
					
						
							|  |  |  | 					label: api.Menus.data.l10n.menuNameLabel, | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 0, | 
					
						
							|  |  |  | 					settings: { | 
					
						
							|  |  |  | 						'default': section.id | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuNameControl ); | 
					
						
							|  |  |  | 				menuNameControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the menu control.
 | 
					
						
							|  |  |  | 			menuControl = api.control( section.id ); | 
					
						
							|  |  |  | 			if ( ! menuControl ) { | 
					
						
							|  |  |  | 				menuControl = new api.controlConstructor.nav_menu( section.id, { | 
					
						
							|  |  |  | 					type: 'nav_menu', | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 998, | 
					
						
							|  |  |  | 					settings: { | 
					
						
							|  |  |  | 						'default': section.id | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					menu_id: section.params.menu_id | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuControl ); | 
					
						
							|  |  |  | 				menuControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the menu locations control.
 | 
					
						
							|  |  |  | 			menuLocationsControlId = section.id + '[locations]'; | 
					
						
							|  |  |  | 			menuLocationsControl = api.control( menuLocationsControlId ); | 
					
						
							|  |  |  | 			if ( ! menuLocationsControl ) { | 
					
						
							|  |  |  | 				menuLocationsControl = new api.controlConstructor.nav_menu_locations( menuLocationsControlId, { | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 999, | 
					
						
							|  |  |  | 					settings: { | 
					
						
							|  |  |  | 						'default': section.id | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					menu_id: section.params.menu_id | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuLocationsControl.id, menuLocationsControl ); | 
					
						
							|  |  |  | 				menuControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the control for managing the menu auto_add.
 | 
					
						
							|  |  |  | 			menuAutoAddControlId = section.id + '[auto_add]'; | 
					
						
							|  |  |  | 			menuAutoAddControl = api.control( menuAutoAddControlId ); | 
					
						
							|  |  |  | 			if ( ! menuAutoAddControl ) { | 
					
						
							|  |  |  | 				menuAutoAddControl = new api.controlConstructor.nav_menu_auto_add( menuAutoAddControlId, { | 
					
						
							|  |  |  | 					type: 'nav_menu_auto_add', | 
					
						
							|  |  |  | 					label: '', | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 1000, | 
					
						
							|  |  |  | 					settings: { | 
					
						
							|  |  |  | 						'default': section.id | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuAutoAddControl ); | 
					
						
							|  |  |  | 				menuAutoAddControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the control for deleting the menu
 | 
					
						
							|  |  |  | 			menuDeleteControlId = section.id + '[delete]'; | 
					
						
							|  |  |  | 			menuDeleteControl = api.control( menuDeleteControlId ); | 
					
						
							|  |  |  | 			if ( ! menuDeleteControl ) { | 
					
						
							|  |  |  | 				menuDeleteControl = new api.Control( menuDeleteControlId, { | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 1001, | 
					
						
							|  |  |  | 					templateId: 'nav-menu-delete-button' | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuDeleteControl.id, menuDeleteControl ); | 
					
						
							|  |  |  | 				menuDeleteControl.active.set( true ); | 
					
						
							|  |  |  | 				menuDeleteControl.deferred.embedded.done( function () { | 
					
						
							|  |  |  | 					menuDeleteControl.container.find( 'button' ).on( 'click', function() { | 
					
						
							|  |  |  | 						var menuId = section.params.menu_id; | 
					
						
							|  |  |  | 						var menuControl = api.Menus.getMenuControl( menuId ); | 
					
						
							|  |  |  | 						menuControl.setting.set( false ); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		refreshAssignedLocations: function() { | 
					
						
							|  |  |  | 			var section = this, | 
					
						
							|  |  |  | 				menuTermId = section.params.menu_id, | 
					
						
							|  |  |  | 				currentAssignedLocations = []; | 
					
						
							|  |  |  | 			_.each( section.navMenuLocationSettings, function( setting, themeLocation ) { | 
					
						
							|  |  |  | 				if ( setting() === menuTermId ) { | 
					
						
							|  |  |  | 					currentAssignedLocations.push( themeLocation ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			section.assignedLocations.set( currentAssignedLocations ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @param {Array} themeLocationSlugs Theme location slugs. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		updateAssignedLocationsInSectionTitle: function( themeLocationSlugs ) { | 
					
						
							|  |  |  | 			var section = this, | 
					
						
							|  |  |  | 				$title; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$title = section.container.find( '.accordion-section-title:first' ); | 
					
						
							|  |  |  | 			$title.find( '.menu-in-location' ).remove(); | 
					
						
							|  |  |  | 			_.each( themeLocationSlugs, function( themeLocationSlug ) { | 
					
						
							|  |  |  | 				var $label, locationName; | 
					
						
							|  |  |  | 				$label = $( '<span class="menu-in-location"></span>' ); | 
					
						
							|  |  |  | 				locationName = api.Menus.data.locationSlugMappedToName[ themeLocationSlug ]; | 
					
						
							|  |  |  | 				$label.text( api.Menus.data.l10n.menuLocation.replace( '%s', locationName ) ); | 
					
						
							|  |  |  | 				$title.append( $label ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			section.container.toggleClass( 'assigned-to-menu-location', 0 !== themeLocationSlugs.length ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		onChangeExpanded: function( expanded, args ) { | 
					
						
							|  |  |  | 			var section = this, completeCallback; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( expanded ) { | 
					
						
							|  |  |  | 				wpNavMenu.menuList = section.contentContainer; | 
					
						
							|  |  |  | 				wpNavMenu.targetList = wpNavMenu.menuList; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add attributes needed by wpNavMenu
 | 
					
						
							|  |  |  | 				$( '#menu-to-edit' ).removeAttr( 'id' ); | 
					
						
							|  |  |  | 				wpNavMenu.menuList.attr( 'id', 'menu-to-edit' ).addClass( 'menu' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				_.each( api.section( section.id ).controls(), function( control ) { | 
					
						
							|  |  |  | 					if ( 'nav_menu_item' === control.params.type ) { | 
					
						
							|  |  |  | 						control.actuallyEmbed(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Make sure Sortables is initialized after the section has been expanded to prevent `offset` issues.
 | 
					
						
							|  |  |  | 				if ( args.completeCallback ) { | 
					
						
							|  |  |  | 					completeCallback = args.completeCallback; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				args.completeCallback = function() { | 
					
						
							|  |  |  | 					if ( 'resolved' !== section.deferred.initSortables.state() ) { | 
					
						
							|  |  |  | 						wpNavMenu.initSortables(); // Depends on menu-to-edit ID being set above.
 | 
					
						
							|  |  |  | 						section.deferred.initSortables.resolve( wpNavMenu.menuList ); // Now MenuControl can extend the sortable.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// @todo Note that wp.customize.reflowPaneContents() is debounced, so this immediate change will show a slight flicker while priorities get updated.
 | 
					
						
							|  |  |  | 						api.control( 'nav_menu[' + String( section.params.menu_id ) + ']' ).reflowMenuItems(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if ( _.isFunction( completeCallback ) ) { | 
					
						
							|  |  |  | 						completeCallback(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			api.Section.prototype.onChangeExpanded.call( section, expanded, args ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Highlight how a user may create new menu items. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * This method reminds the user to create new menu items and how. | 
					
						
							|  |  |  | 		 * It's exposed this way because this class knows best which UI needs | 
					
						
							|  |  |  | 		 * highlighted but those expanding this section know more about why and | 
					
						
							|  |  |  | 		 * when the affordance should be highlighted. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		highlightNewItemButton: function() { | 
					
						
							|  |  |  | 			api.utils.highlightButton( this.contentContainer.find( '.add-new-menu-item' ), { delay: 2000 } ); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Create a nav menu setting and section. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @since 4.9.0 | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @param {string} [name=''] Nav menu name. | 
					
						
							|  |  |  | 	 * @returns {wp.customize.Menus.MenuSection} Added nav menu. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.createNavMenu = function createNavMenu( name ) { | 
					
						
							|  |  |  | 		var customizeId, placeholderId, setting; | 
					
						
							|  |  |  | 		placeholderId = api.Menus.generatePlaceholderAutoIncrementId(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		customizeId = 'nav_menu[' + String( placeholderId ) + ']'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Register the menu control setting.
 | 
					
						
							|  |  |  | 		setting = api.create( customizeId, customizeId, {}, { | 
					
						
							|  |  |  | 			type: 'nav_menu', | 
					
						
							|  |  |  | 			transport: api.Menus.data.settingTransport, | 
					
						
							|  |  |  | 			previewer: api.previewer | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 		setting.set( $.extend( | 
					
						
							|  |  |  | 			{}, | 
					
						
							|  |  |  | 			api.Menus.data.defaultSettingValues.nav_menu, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: name || '' | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		) ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* | 
					
						
							|  |  |  | 		 * Add the menu section (and its controls). | 
					
						
							|  |  |  | 		 * Note that this will automatically create the required controls | 
					
						
							|  |  |  | 		 * inside via the Section's ready method. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		return api.section.add( new api.Menus.MenuSection( customizeId, { | 
					
						
							|  |  |  | 			panel: 'nav_menus', | 
					
						
							|  |  |  | 			title: displayNavMenuName( name ), | 
					
						
							|  |  |  | 			customizeAction: api.Menus.data.l10n.customizingMenus, | 
					
						
							|  |  |  | 			priority: 10, | 
					
						
							|  |  |  | 			menu_id: placeholderId | 
					
						
							|  |  |  | 		} ) ); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.NewMenuSection | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer section for new menus. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.NewMenuSection | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Section | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.NewMenuSection = api.Section.extend(/** @lends wp.customize.Menus.NewMenuSection.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Add behaviors for the accordion section. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		attachEvents: function() { | 
					
						
							|  |  |  | 			var section = this, | 
					
						
							|  |  |  | 				container = section.container, | 
					
						
							|  |  |  | 				contentContainer = section.contentContainer, | 
					
						
							|  |  |  | 				navMenuSettingPattern = /^nav_menu\[/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			section.headContainer.find( '.accordion-section-title' ).replaceWith( | 
					
						
							|  |  |  | 				wp.template( 'nav-menu-create-menu-section-title' ) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			 * We have to manually handle section expanded because we do not | 
					
						
							|  |  |  | 			 * apply the `accordion-section-title` class to this button-driven section. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			container.on( 'click', '.customize-add-menu-button', function() { | 
					
						
							|  |  |  | 				section.expand(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			contentContainer.on( 'keydown', '.menu-name-field', function( event ) { | 
					
						
							|  |  |  | 				if ( 13 === event.which ) { // Enter.
 | 
					
						
							|  |  |  | 					section.submit(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 			contentContainer.on( 'click', '#customize-new-menu-submit', function( event ) { | 
					
						
							|  |  |  | 				section.submit(); | 
					
						
							|  |  |  | 				event.stopPropagation(); | 
					
						
							|  |  |  | 				event.preventDefault(); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * Get number of non-deleted nav menus. | 
					
						
							|  |  |  | 			 * | 
					
						
							|  |  |  | 			 * @since 4.9.0 | 
					
						
							|  |  |  | 			 * @returns {number} Count. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			function getNavMenuCount() { | 
					
						
							|  |  |  | 				var count = 0; | 
					
						
							|  |  |  | 				api.each( function( setting ) { | 
					
						
							|  |  |  | 					if ( navMenuSettingPattern.test( setting.id ) && false !== setting.get() ) { | 
					
						
							|  |  |  | 						count += 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				return count; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * Update visibility of notice to prompt users to create menus. | 
					
						
							|  |  |  | 			 * | 
					
						
							|  |  |  | 			 * @since 4.9.0 | 
					
						
							|  |  |  | 			 * @returns {void} | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			function updateNoticeVisibility() { | 
					
						
							|  |  |  | 				container.find( '.add-new-menu-notice' ).prop( 'hidden', getNavMenuCount() > 0 ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * Handle setting addition. | 
					
						
							|  |  |  | 			 * | 
					
						
							|  |  |  | 			 * @since 4.9.0 | 
					
						
							|  |  |  | 			 * @param {wp.customize.Setting} setting - Added setting. | 
					
						
							|  |  |  | 			 * @returns {void} | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			function addChangeEventListener( setting ) { | 
					
						
							|  |  |  | 				if ( navMenuSettingPattern.test( setting.id ) ) { | 
					
						
							|  |  |  | 					setting.bind( updateNoticeVisibility ); | 
					
						
							|  |  |  | 					updateNoticeVisibility(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * Handle setting removal. | 
					
						
							|  |  |  | 			 * | 
					
						
							|  |  |  | 			 * @since 4.9.0 | 
					
						
							|  |  |  | 			 * @param {wp.customize.Setting} setting - Removed setting. | 
					
						
							|  |  |  | 			 * @returns {void} | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			function removeChangeEventListener( setting ) { | 
					
						
							|  |  |  | 				if ( navMenuSettingPattern.test( setting.id ) ) { | 
					
						
							|  |  |  | 					setting.unbind( updateNoticeVisibility ); | 
					
						
							|  |  |  | 					updateNoticeVisibility(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.each( addChangeEventListener ); | 
					
						
							|  |  |  | 			api.bind( 'add', addChangeEventListener ); | 
					
						
							|  |  |  | 			api.bind( 'removed', removeChangeEventListener ); | 
					
						
							|  |  |  | 			updateNoticeVisibility(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.Section.prototype.attachEvents.apply( section, arguments ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up the control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			this.populateControls(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Create the controls for this section. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		populateControls: function() { | 
					
						
							|  |  |  | 			var section = this, | 
					
						
							|  |  |  | 				menuNameControlId, | 
					
						
							|  |  |  | 				menuLocationsControlId, | 
					
						
							|  |  |  | 				newMenuSubmitControlId, | 
					
						
							|  |  |  | 				menuNameControl, | 
					
						
							|  |  |  | 				menuLocationsControl, | 
					
						
							|  |  |  | 				newMenuSubmitControl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuNameControlId = section.id + '[name]'; | 
					
						
							|  |  |  | 			menuNameControl = api.control( menuNameControlId ); | 
					
						
							|  |  |  | 			if ( ! menuNameControl ) { | 
					
						
							|  |  |  | 				menuNameControl = new api.controlConstructor.nav_menu_name( menuNameControlId, { | 
					
						
							|  |  |  | 					label: api.Menus.data.l10n.menuNameLabel, | 
					
						
							|  |  |  | 					description: api.Menus.data.l10n.newMenuNameDescription, | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 0 | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuNameControl.id, menuNameControl ); | 
					
						
							|  |  |  | 				menuNameControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuLocationsControlId = section.id + '[locations]'; | 
					
						
							|  |  |  | 			menuLocationsControl = api.control( menuLocationsControlId ); | 
					
						
							|  |  |  | 			if ( ! menuLocationsControl ) { | 
					
						
							|  |  |  | 				menuLocationsControl = new api.controlConstructor.nav_menu_locations( menuLocationsControlId, { | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 1, | 
					
						
							|  |  |  | 					menu_id: '', | 
					
						
							|  |  |  | 					isCreating: true | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( menuLocationsControlId, menuLocationsControl ); | 
					
						
							|  |  |  | 				menuLocationsControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			newMenuSubmitControlId = section.id + '[submit]'; | 
					
						
							|  |  |  | 			newMenuSubmitControl = api.control( newMenuSubmitControlId ); | 
					
						
							|  |  |  | 			if ( !newMenuSubmitControl ) { | 
					
						
							|  |  |  | 				newMenuSubmitControl = new api.Control( newMenuSubmitControlId, { | 
					
						
							|  |  |  | 					section: section.id, | 
					
						
							|  |  |  | 					priority: 1, | 
					
						
							|  |  |  | 					templateId: 'nav-menu-submit-new-button' | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				api.control.add( newMenuSubmitControlId, newMenuSubmitControl ); | 
					
						
							|  |  |  | 				newMenuSubmitControl.active.set( true ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Create the new menu with name and location supplied by the user. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		submit: function() { | 
					
						
							|  |  |  | 			var section = this, | 
					
						
							|  |  |  | 				contentContainer = section.contentContainer, | 
					
						
							|  |  |  | 				nameInput = contentContainer.find( '.menu-name-field' ).first(), | 
					
						
							|  |  |  | 				name = nameInput.val(), | 
					
						
							|  |  |  | 				menuSection; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! name ) { | 
					
						
							|  |  |  | 				nameInput.addClass( 'invalid' ); | 
					
						
							|  |  |  | 				nameInput.focus(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuSection = api.Menus.createNavMenu( name ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Clear name field.
 | 
					
						
							|  |  |  | 			nameInput.val( '' ); | 
					
						
							|  |  |  | 			nameInput.removeClass( 'invalid' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			contentContainer.find( '.assigned-menu-location input[type=checkbox]' ).each( function() { | 
					
						
							|  |  |  | 				var checkbox = $( this ), | 
					
						
							|  |  |  | 				navMenuLocationSetting; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( checkbox.prop( 'checked' ) ) { | 
					
						
							|  |  |  | 					navMenuLocationSetting = api( 'nav_menu_locations[' + checkbox.data( 'location-id' ) + ']' ); | 
					
						
							|  |  |  | 					navMenuLocationSetting.set( menuSection.params.menu_id ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Reset state for next new menu
 | 
					
						
							|  |  |  | 					checkbox.prop( 'checked', false ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.menuAdded ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Focus on the new menu section.
 | 
					
						
							|  |  |  | 			menuSection.focus( { | 
					
						
							|  |  |  | 				completeCallback: function() { | 
					
						
							|  |  |  | 					menuSection.highlightNewItemButton(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Select a default location. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * This method selects a single location by default so we can support | 
					
						
							|  |  |  | 		 * creating a menu for a specific menu location. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {string|null} locationId - The ID of the location to select. `null` clears all selections. | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		selectDefaultLocation: function( locationId ) { | 
					
						
							|  |  |  | 			var locationControl = api.control( this.id + '[locations]' ), | 
					
						
							|  |  |  | 				locationSelections = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( locationId !== null ) { | 
					
						
							|  |  |  | 				locationSelections[ locationId ] = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			locationControl.setSelections( locationSelections ); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenuLocationControl | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer control for menu locations (rendered as a <select>). | 
					
						
							|  |  |  | 	 * Note that 'nav_menu_location' must match the WP_Customize_Nav_Menu_Location_Control::$type. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenuLocationControl | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Control | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuLocationControl = api.Control.extend(/** @lends wp.customize.Menus.MenuLocationControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		initialize: function( id, options ) { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				matches = id.match( /^nav_menu_locations\[(.+?)]/ ); | 
					
						
							|  |  |  | 			control.themeLocation = matches[1]; | 
					
						
							|  |  |  | 			api.Control.prototype.initialize.call( control, id, options ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			var control = this, navMenuIdRegex = /^nav_menu\[(-?\d+)]/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// @todo It would be better if this was added directly on the setting itself, as opposed to the control.
 | 
					
						
							|  |  |  | 			control.setting.validate = function( value ) { | 
					
						
							|  |  |  | 				if ( '' === value ) { | 
					
						
							|  |  |  | 					return 0; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					return parseInt( value, 10 ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Create and Edit menu buttons.
 | 
					
						
							|  |  |  | 			control.container.find( '.create-menu' ).on( 'click', function() { | 
					
						
							|  |  |  | 				var addMenuSection = api.section( 'add_menu' ); | 
					
						
							|  |  |  | 				addMenuSection.selectDefaultLocation( this.dataset.locationId ); | 
					
						
							|  |  |  | 				addMenuSection.focus(); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 			control.container.find( '.edit-menu' ).on( 'click', function() { | 
					
						
							|  |  |  | 				var menuId = control.setting(); | 
					
						
							|  |  |  | 				api.section( 'nav_menu[' + menuId + ']' ).focus(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			control.setting.bind( 'change', function() { | 
					
						
							|  |  |  | 				var menuIsSelected = 0 !== control.setting(); | 
					
						
							|  |  |  | 				control.container.find( '.create-menu' ).toggleClass( 'hidden', menuIsSelected ); | 
					
						
							|  |  |  | 				control.container.find( '.edit-menu' ).toggleClass( 'hidden', ! menuIsSelected ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add/remove menus from the available options when they are added and removed.
 | 
					
						
							|  |  |  | 			api.bind( 'add', function( setting ) { | 
					
						
							|  |  |  | 				var option, menuId, matches = setting.id.match( navMenuIdRegex ); | 
					
						
							|  |  |  | 				if ( ! matches || false === setting() ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				menuId = matches[1]; | 
					
						
							|  |  |  | 				option = new Option( displayNavMenuName( setting().name ), menuId ); | 
					
						
							|  |  |  | 				control.container.find( 'select' ).append( option ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			api.bind( 'remove', function( setting ) { | 
					
						
							|  |  |  | 				var menuId, matches = setting.id.match( navMenuIdRegex ); | 
					
						
							|  |  |  | 				if ( ! matches ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				menuId = parseInt( matches[1], 10 ); | 
					
						
							|  |  |  | 				if ( control.setting() === menuId ) { | 
					
						
							|  |  |  | 					control.setting.set( '' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				control.container.find( 'option[value=' + menuId + ']' ).remove(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			api.bind( 'change', function( setting ) { | 
					
						
							|  |  |  | 				var menuId, matches = setting.id.match( navMenuIdRegex ); | 
					
						
							|  |  |  | 				if ( ! matches ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				menuId = parseInt( matches[1], 10 ); | 
					
						
							|  |  |  | 				if ( false === setting() ) { | 
					
						
							|  |  |  | 					if ( control.setting() === menuId ) { | 
					
						
							|  |  |  | 						control.setting.set( '' ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					control.container.find( 'option[value=' + menuId + ']' ).remove(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					control.container.find( 'option[value=' + menuId + ']' ).text( displayNavMenuName( setting().name ) ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuItemControl = api.Control.extend(/** @lends wp.customize.Menus.MenuItemControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 		 * wp.customize.Menus.MenuItemControl | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * Customizer control for menu items. | 
					
						
							|  |  |  | 		 * Note that 'menu_item' must match the WP_Customize_Menu_Item_Control::$type. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @constructs wp.customize.Menus.MenuItemControl | 
					
						
							|  |  |  | 		 * @augments   wp.customize.Control | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @inheritDoc | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		 */ | 
					
						
							|  |  |  | 		initialize: function( id, options ) { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 			control.expanded = new api.Value( false ); | 
					
						
							|  |  |  | 			control.expandedArgumentsQueue = []; | 
					
						
							|  |  |  | 			control.expanded.bind( function( expanded ) { | 
					
						
							|  |  |  | 				var args = control.expandedArgumentsQueue.shift(); | 
					
						
							|  |  |  | 				args = $.extend( {}, control.defaultExpandedArguments, args ); | 
					
						
							|  |  |  | 				control.onChangeExpanded( expanded, args ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			api.Control.prototype.initialize.call( control, id, options ); | 
					
						
							|  |  |  | 			control.active.validate = function() { | 
					
						
							|  |  |  | 				var value, section = api.section( control.section() ); | 
					
						
							|  |  |  | 				if ( section ) { | 
					
						
							|  |  |  | 					value = section.active(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					value = false; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return value; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Override the embed() method to do nothing, | 
					
						
							|  |  |  | 		 * so that the control isn't embedded on load, | 
					
						
							|  |  |  | 		 * unless the containing section is already expanded. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		embed: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				sectionId = control.section(), | 
					
						
							|  |  |  | 				section; | 
					
						
							|  |  |  | 			if ( ! sectionId ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			section = api.section( sectionId ); | 
					
						
							|  |  |  | 			if ( ( section && section.expanded() ) || api.settings.autofocus.control === control.id ) { | 
					
						
							|  |  |  | 				control.actuallyEmbed(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * This function is called in Section.onChangeExpanded() so the control | 
					
						
							|  |  |  | 		 * will only get embedded when the Section is first expanded. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.3.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		actuallyEmbed: function() { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 			if ( 'resolved' === control.deferred.embedded.state() ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			control.renderContent(); | 
					
						
							|  |  |  | 			control.deferred.embedded.resolve(); // This triggers control.ready().
 | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up the control. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			if ( 'undefined' === typeof this.params.menu_item_id ) { | 
					
						
							|  |  |  | 				throw new Error( 'params.menu_item_id was not defined' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this._setupControlToggle(); | 
					
						
							|  |  |  | 			this._setupReorderUI(); | 
					
						
							|  |  |  | 			this._setupUpdateUI(); | 
					
						
							|  |  |  | 			this._setupRemoveUI(); | 
					
						
							|  |  |  | 			this._setupLinksUI(); | 
					
						
							|  |  |  | 			this._setupTitleUI(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Show/hide the settings when clicking on the menu item handle. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupControlToggle: function() { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.container.find( '.menu-item-handle' ).on( 'click', function( e ) { | 
					
						
							|  |  |  | 				e.preventDefault(); | 
					
						
							|  |  |  | 				e.stopPropagation(); | 
					
						
							|  |  |  | 				var menuControl = control.getMenuControl(), | 
					
						
							|  |  |  | 					isDeleteBtn = $( e.target ).is( '.item-delete, .item-delete *' ), | 
					
						
							|  |  |  | 					isAddNewBtn = $( e.target ).is( '.add-new-menu-item, .add-new-menu-item *' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( $( 'body' ).hasClass( 'adding-menu-items' ) && ! isDeleteBtn && ! isAddNewBtn ) { | 
					
						
							|  |  |  | 					api.Menus.availableMenuItemsPanel.close(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( menuControl.isReordering || menuControl.isSorting ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				control.toggleForm(); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up the menu-item-reorder-nav | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupReorderUI: function() { | 
					
						
							|  |  |  | 			var control = this, template, $reorderNav; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			template = wp.template( 'menu-item-reorder-nav' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the menu item reordering elements to the menu item control.
 | 
					
						
							|  |  |  | 			control.container.find( '.item-controls' ).after( template ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Handle clicks for up/down/left-right on the reorder nav.
 | 
					
						
							|  |  |  | 			$reorderNav = control.container.find( '.menu-item-reorder-nav' ); | 
					
						
							|  |  |  | 			$reorderNav.find( '.menus-move-up, .menus-move-down, .menus-move-left, .menus-move-right' ).on( 'click', function() { | 
					
						
							|  |  |  | 				var moveBtn = $( this ); | 
					
						
							|  |  |  | 				moveBtn.focus(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var isMoveUp = moveBtn.is( '.menus-move-up' ), | 
					
						
							|  |  |  | 					isMoveDown = moveBtn.is( '.menus-move-down' ), | 
					
						
							|  |  |  | 					isMoveLeft = moveBtn.is( '.menus-move-left' ), | 
					
						
							|  |  |  | 					isMoveRight = moveBtn.is( '.menus-move-right' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( isMoveUp ) { | 
					
						
							|  |  |  | 					control.moveUp(); | 
					
						
							|  |  |  | 				} else if ( isMoveDown ) { | 
					
						
							|  |  |  | 					control.moveDown(); | 
					
						
							|  |  |  | 				} else if ( isMoveLeft ) { | 
					
						
							|  |  |  | 					control.moveLeft(); | 
					
						
							|  |  |  | 				} else if ( isMoveRight ) { | 
					
						
							|  |  |  | 					control.moveRight(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				moveBtn.focus(); // Re-focus after the container was moved.
 | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up event handlers for menu item updating. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupUpdateUI: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				settingValue = control.setting(), | 
					
						
							|  |  |  | 				updateNotifications; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.elements = {}; | 
					
						
							|  |  |  | 			control.elements.url = new api.Element( control.container.find( '.edit-menu-item-url' ) ); | 
					
						
							|  |  |  | 			control.elements.title = new api.Element( control.container.find( '.edit-menu-item-title' ) ); | 
					
						
							|  |  |  | 			control.elements.attr_title = new api.Element( control.container.find( '.edit-menu-item-attr-title' ) ); | 
					
						
							|  |  |  | 			control.elements.target = new api.Element( control.container.find( '.edit-menu-item-target' ) ); | 
					
						
							|  |  |  | 			control.elements.classes = new api.Element( control.container.find( '.edit-menu-item-classes' ) ); | 
					
						
							|  |  |  | 			control.elements.xfn = new api.Element( control.container.find( '.edit-menu-item-xfn' ) ); | 
					
						
							|  |  |  | 			control.elements.description = new api.Element( control.container.find( '.edit-menu-item-description' ) ); | 
					
						
							|  |  |  | 			// @todo allow other elements, added by plugins, to be automatically picked up here; allow additional values to be added to setting array.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			_.each( control.elements, function( element, property ) { | 
					
						
							|  |  |  | 				element.bind(function( value ) { | 
					
						
							|  |  |  | 					if ( element.element.is( 'input[type=checkbox]' ) ) { | 
					
						
							|  |  |  | 						value = ( value ) ? element.element.val() : ''; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					var settingValue = control.setting(); | 
					
						
							|  |  |  | 					if ( settingValue && settingValue[ property ] !== value ) { | 
					
						
							|  |  |  | 						settingValue = _.clone( settingValue ); | 
					
						
							|  |  |  | 						settingValue[ property ] = value; | 
					
						
							|  |  |  | 						control.setting.set( settingValue ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				if ( settingValue ) { | 
					
						
							|  |  |  | 					if ( ( property === 'classes' || property === 'xfn' ) && _.isArray( settingValue[ property ] ) ) { | 
					
						
							|  |  |  | 						element.set( settingValue[ property ].join( ' ' ) ); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						element.set( settingValue[ property ] ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.setting.bind(function( to, from ) { | 
					
						
							|  |  |  | 				var itemId = control.params.menu_item_id, | 
					
						
							|  |  |  | 					followingSiblingItemControls = [], | 
					
						
							|  |  |  | 					childrenItemControls = [], | 
					
						
							|  |  |  | 					menuControl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( false === to ) { | 
					
						
							|  |  |  | 					menuControl = api.control( 'nav_menu[' + String( from.nav_menu_term_id ) + ']' ); | 
					
						
							|  |  |  | 					control.container.remove(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					_.each( menuControl.getMenuItemControls(), function( otherControl ) { | 
					
						
							|  |  |  | 						if ( from.menu_item_parent === otherControl.setting().menu_item_parent && otherControl.setting().position > from.position ) { | 
					
						
							|  |  |  | 							followingSiblingItemControls.push( otherControl ); | 
					
						
							|  |  |  | 						} else if ( otherControl.setting().menu_item_parent === itemId ) { | 
					
						
							|  |  |  | 							childrenItemControls.push( otherControl ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Shift all following siblings by the number of children this item has.
 | 
					
						
							|  |  |  | 					_.each( followingSiblingItemControls, function( followingSiblingItemControl ) { | 
					
						
							|  |  |  | 						var value = _.clone( followingSiblingItemControl.setting() ); | 
					
						
							|  |  |  | 						value.position += childrenItemControls.length; | 
					
						
							|  |  |  | 						followingSiblingItemControl.setting.set( value ); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Now move the children up to be the new subsequent siblings.
 | 
					
						
							|  |  |  | 					_.each( childrenItemControls, function( childrenItemControl, i ) { | 
					
						
							|  |  |  | 						var value = _.clone( childrenItemControl.setting() ); | 
					
						
							|  |  |  | 						value.position = from.position + i; | 
					
						
							|  |  |  | 						value.menu_item_parent = from.menu_item_parent; | 
					
						
							|  |  |  | 						childrenItemControl.setting.set( value ); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					menuControl.debouncedReflowMenuItems(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// Update the elements' values to match the new setting properties.
 | 
					
						
							|  |  |  | 					_.each( to, function( value, key ) { | 
					
						
							|  |  |  | 						if ( control.elements[ key] ) { | 
					
						
							|  |  |  | 							control.elements[ key ].set( to[ key ] ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} ); | 
					
						
							|  |  |  | 					control.container.find( '.menu-item-data-parent-id' ).val( to.menu_item_parent ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Handle UI updates when the position or depth (parent) change.
 | 
					
						
							|  |  |  | 					if ( to.position !== from.position || to.menu_item_parent !== from.menu_item_parent ) { | 
					
						
							|  |  |  | 						control.getMenuControl().debouncedReflowMenuItems(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Style the URL field as invalid when there is an invalid_url notification.
 | 
					
						
							|  |  |  | 			updateNotifications = function() { | 
					
						
							|  |  |  | 				control.elements.url.element.toggleClass( 'invalid', control.setting.notifications.has( 'invalid_url' ) ); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			control.setting.notifications.bind( 'add', updateNotifications ); | 
					
						
							|  |  |  | 			control.setting.notifications.bind( 'removed', updateNotifications ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up event handlers for menu item deletion. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupRemoveUI: function() { | 
					
						
							|  |  |  | 			var control = this, $removeBtn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Configure delete button.
 | 
					
						
							|  |  |  | 			$removeBtn = control.container.find( '.item-delete' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$removeBtn.on( 'click', function() { | 
					
						
							|  |  |  | 				// Find an adjacent element to add focus to when this menu item goes away
 | 
					
						
							|  |  |  | 				var addingItems = true, $adjacentFocusTarget, $next, $prev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( ! $( 'body' ).hasClass( 'adding-menu-items' ) ) { | 
					
						
							|  |  |  | 					addingItems = false; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				$next = control.container.nextAll( '.customize-control-nav_menu_item:visible' ).first(); | 
					
						
							|  |  |  | 				$prev = control.container.prevAll( '.customize-control-nav_menu_item:visible' ).first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( $next.length ) { | 
					
						
							|  |  |  | 					$adjacentFocusTarget = $next.find( false === addingItems ? '.item-edit' : '.item-delete' ).first(); | 
					
						
							|  |  |  | 				} else if ( $prev.length ) { | 
					
						
							|  |  |  | 					$adjacentFocusTarget = $prev.find( false === addingItems ? '.item-edit' : '.item-delete' ).first(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					$adjacentFocusTarget = control.container.nextAll( '.customize-control-nav_menu' ).find( '.add-new-menu-item' ).first(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				control.container.slideUp( function() { | 
					
						
							|  |  |  | 					control.setting.set( false ); | 
					
						
							|  |  |  | 					wp.a11y.speak( api.Menus.data.l10n.itemDeleted ); | 
					
						
							|  |  |  | 					$adjacentFocusTarget.focus(); // keyboard accessibility
 | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				control.setting.set( false ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_setupLinksUI: function() { | 
					
						
							|  |  |  | 			var $origBtn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Configure original link.
 | 
					
						
							|  |  |  | 			$origBtn = this.container.find( 'a.original-link' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$origBtn.on( 'click', function( e ) { | 
					
						
							|  |  |  | 				e.preventDefault(); | 
					
						
							|  |  |  | 				api.previewer.previewUrl( e.target.toString() ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Update item handle title when changed. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupTitleUI: function() { | 
					
						
							|  |  |  | 			var control = this, titleEl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Ensure that whitespace is trimmed on blur so placeholder can be shown.
 | 
					
						
							|  |  |  | 			control.container.find( '.edit-menu-item-title' ).on( 'blur', function() { | 
					
						
							|  |  |  | 				$( this ).val( $.trim( $( this ).val() ) ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			titleEl = control.container.find( '.menu-item-title' ); | 
					
						
							|  |  |  | 			control.setting.bind( function( item ) { | 
					
						
							|  |  |  | 				var trimmedTitle, titleText; | 
					
						
							|  |  |  | 				if ( ! item ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				trimmedTitle = $.trim( item.title ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				titleText = trimmedTitle || item.original_title || api.Menus.data.l10n.untitled; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( item._invalid ) { | 
					
						
							|  |  |  | 					titleText = api.Menus.data.l10n.invalidTitleTpl.replace( '%s', titleText ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Don't update to an empty title.
 | 
					
						
							|  |  |  | 				if ( trimmedTitle || item.original_title ) { | 
					
						
							|  |  |  | 					titleEl | 
					
						
							|  |  |  | 						.text( titleText ) | 
					
						
							|  |  |  | 						.removeClass( 'no-title' ); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					titleEl | 
					
						
							|  |  |  | 						.text( titleText ) | 
					
						
							|  |  |  | 						.addClass( 'no-title' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @returns {number} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		getDepth: function() { | 
					
						
							|  |  |  | 			var control = this, setting = control.setting(), depth = 0; | 
					
						
							|  |  |  | 			if ( ! setting ) { | 
					
						
							|  |  |  | 				return 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			while ( setting && setting.menu_item_parent ) { | 
					
						
							|  |  |  | 				depth += 1; | 
					
						
							|  |  |  | 				control = api.control( 'nav_menu_item[' + setting.menu_item_parent + ']' ); | 
					
						
							|  |  |  | 				if ( ! control ) { | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				setting = control.setting(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return depth; | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Amend the control's params with the data necessary for the JS template just in time. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		renderContent: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				settingValue = control.setting(), | 
					
						
							|  |  |  | 				containerClasses; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.params.title = settingValue.title || ''; | 
					
						
							|  |  |  | 			control.params.depth = control.getDepth(); | 
					
						
							|  |  |  | 			control.container.data( 'item-depth', control.params.depth ); | 
					
						
							|  |  |  | 			containerClasses = [ | 
					
						
							|  |  |  | 				'menu-item', | 
					
						
							|  |  |  | 				'menu-item-depth-' + String( control.params.depth ), | 
					
						
							|  |  |  | 				'menu-item-' + settingValue.object, | 
					
						
							|  |  |  | 				'menu-item-edit-inactive' | 
					
						
							|  |  |  | 			]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( settingValue._invalid ) { | 
					
						
							|  |  |  | 				containerClasses.push( 'menu-item-invalid' ); | 
					
						
							|  |  |  | 				control.params.title = api.Menus.data.l10n.invalidTitleTpl.replace( '%s', control.params.title ); | 
					
						
							|  |  |  | 			} else if ( 'draft' === settingValue.status ) { | 
					
						
							|  |  |  | 				containerClasses.push( 'pending' ); | 
					
						
							|  |  |  | 				control.params.title = api.Menus.data.pendingTitleTpl.replace( '%s', control.params.title ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.params.el_classes = containerClasses.join( ' ' ); | 
					
						
							|  |  |  | 			control.params.item_type_label = settingValue.type_label; | 
					
						
							|  |  |  | 			control.params.item_type = settingValue.type; | 
					
						
							|  |  |  | 			control.params.url = settingValue.url; | 
					
						
							|  |  |  | 			control.params.target = settingValue.target; | 
					
						
							|  |  |  | 			control.params.attr_title = settingValue.attr_title; | 
					
						
							|  |  |  | 			control.params.classes = _.isArray( settingValue.classes ) ? settingValue.classes.join( ' ' ) : settingValue.classes; | 
					
						
							|  |  |  | 			control.params.attr_title = settingValue.attr_title; | 
					
						
							|  |  |  | 			control.params.xfn = settingValue.xfn; | 
					
						
							|  |  |  | 			control.params.description = settingValue.description; | 
					
						
							|  |  |  | 			control.params.parent = settingValue.menu_item_parent; | 
					
						
							|  |  |  | 			control.params.original_title = settingValue.original_title || ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.container.addClass( control.params.el_classes ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.Control.prototype.renderContent.call( control ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*********************************************************************** | 
					
						
							|  |  |  | 		 * Begin public API methods | 
					
						
							|  |  |  | 		 **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @return {wp.customize.controlConstructor.nav_menu|null} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		getMenuControl: function() { | 
					
						
							|  |  |  | 			var control = this, settingValue = control.setting(); | 
					
						
							|  |  |  | 			if ( settingValue && settingValue.nav_menu_term_id ) { | 
					
						
							|  |  |  | 				return api.control( 'nav_menu[' + settingValue.nav_menu_term_id + ']' ); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return null; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Expand the accordion section containing a control | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		expandControlSection: function() { | 
					
						
							|  |  |  | 			var $section = this.container.closest( '.accordion-section' ); | 
					
						
							|  |  |  | 			if ( ! $section.hasClass( 'open' ) ) { | 
					
						
							|  |  |  | 				$section.find( '.accordion-section-title:first' ).trigger( 'click' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @since 4.6.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Boolean} expanded | 
					
						
							|  |  |  | 		 * @param {Object} [params] | 
					
						
							|  |  |  | 		 * @returns {Boolean} false if state already applied | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_toggleExpanded: api.Section.prototype._toggleExpanded, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @since 4.6.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Object} [params] | 
					
						
							|  |  |  | 		 * @returns {Boolean} false if already expanded | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		expand: api.Section.prototype.expand, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Expand the menu item form control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.5.0 Added params.completeCallback. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Object}   [params] - Optional params. | 
					
						
							|  |  |  | 		 * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		expandForm: function( params ) { | 
					
						
							|  |  |  | 			this.expand( params ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @since 4.6.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Object} [params] | 
					
						
							|  |  |  | 		 * @returns {Boolean} false if already collapsed | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		collapse: api.Section.prototype.collapse, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Collapse the menu item form control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.5.0 Added params.completeCallback. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Object}   [params] - Optional params. | 
					
						
							|  |  |  | 		 * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		collapseForm: function( params ) { | 
					
						
							|  |  |  | 			this.collapse( params ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Expand or collapse the menu item control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @deprecated this is poor naming, and it is better to directly set control.expanded( showOrHide ) | 
					
						
							|  |  |  | 		 * @since 4.5.0 Added params.completeCallback. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {boolean}  [showOrHide] - If not supplied, will be inverse of current visibility | 
					
						
							|  |  |  | 		 * @param {Object}   [params] - Optional params. | 
					
						
							|  |  |  | 		 * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		toggleForm: function( showOrHide, params ) { | 
					
						
							|  |  |  | 			if ( typeof showOrHide === 'undefined' ) { | 
					
						
							|  |  |  | 				showOrHide = ! this.expanded(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if ( showOrHide ) { | 
					
						
							|  |  |  | 				this.expand( params ); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				this.collapse( params ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Expand or collapse the menu item control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.6.0 | 
					
						
							|  |  |  | 		 * @param {boolean}  [showOrHide] - If not supplied, will be inverse of current visibility | 
					
						
							|  |  |  | 		 * @param {Object}   [params] - Optional params. | 
					
						
							|  |  |  | 		 * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		onChangeExpanded: function( showOrHide, params ) { | 
					
						
							|  |  |  | 			var self = this, $menuitem, $inside, complete; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$menuitem = this.container; | 
					
						
							|  |  |  | 			$inside = $menuitem.find( '.menu-item-settings:first' ); | 
					
						
							|  |  |  | 			if ( 'undefined' === typeof showOrHide ) { | 
					
						
							|  |  |  | 				showOrHide = ! $inside.is( ':visible' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Already expanded or collapsed.
 | 
					
						
							|  |  |  | 			if ( $inside.is( ':visible' ) === showOrHide ) { | 
					
						
							|  |  |  | 				if ( params && params.completeCallback ) { | 
					
						
							|  |  |  | 					params.completeCallback(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( showOrHide ) { | 
					
						
							|  |  |  | 				// Close all other menu item controls before expanding this one.
 | 
					
						
							|  |  |  | 				api.control.each( function( otherControl ) { | 
					
						
							|  |  |  | 					if ( self.params.type === otherControl.params.type && self !== otherControl ) { | 
					
						
							|  |  |  | 						otherControl.collapseForm(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				complete = function() { | 
					
						
							|  |  |  | 					$menuitem | 
					
						
							|  |  |  | 						.removeClass( 'menu-item-edit-inactive' ) | 
					
						
							|  |  |  | 						.addClass( 'menu-item-edit-active' ); | 
					
						
							|  |  |  | 					self.container.trigger( 'expanded' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if ( params && params.completeCallback ) { | 
					
						
							|  |  |  | 						params.completeCallback(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				$menuitem.find( '.item-edit' ).attr( 'aria-expanded', 'true' ); | 
					
						
							|  |  |  | 				$inside.slideDown( 'fast', complete ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				self.container.trigger( 'expand' ); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				complete = function() { | 
					
						
							|  |  |  | 					$menuitem | 
					
						
							|  |  |  | 						.addClass( 'menu-item-edit-inactive' ) | 
					
						
							|  |  |  | 						.removeClass( 'menu-item-edit-active' ); | 
					
						
							|  |  |  | 					self.container.trigger( 'collapsed' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if ( params && params.completeCallback ) { | 
					
						
							|  |  |  | 						params.completeCallback(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				self.container.trigger( 'collapse' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				$menuitem.find( '.item-edit' ).attr( 'aria-expanded', 'false' ); | 
					
						
							|  |  |  | 				$inside.slideUp( 'fast', complete ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Expand the containing menu section, expand the form, and focus on | 
					
						
							|  |  |  | 		 * the first input in the control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.5.0 Added params.completeCallback. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Object}   [params] - Params object. | 
					
						
							|  |  |  | 		 * @param {Function} [params.completeCallback] - Optional callback function when focus has completed. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		focus: function( params ) { | 
					
						
							|  |  |  | 			params = params || {}; | 
					
						
							|  |  |  | 			var control = this, originalCompleteCallback = params.completeCallback, focusControl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			focusControl = function() { | 
					
						
							|  |  |  | 				control.expandControlSection(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				params.completeCallback = function() { | 
					
						
							|  |  |  | 					var focusable; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Note that we can't use :focusable due to a jQuery UI issue. See: https://github.com/jquery/jquery-ui/pull/1583
 | 
					
						
							|  |  |  | 					focusable = control.container.find( '.menu-item-settings' ).find( 'input, select, textarea, button, object, a[href], [tabindex]' ).filter( ':visible' ); | 
					
						
							|  |  |  | 					focusable.first().focus(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if ( originalCompleteCallback ) { | 
					
						
							|  |  |  | 						originalCompleteCallback(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				control.expandForm( params ); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( api.section.has( control.section() ) ) { | 
					
						
							|  |  |  | 				api.section( control.section() ).expand( { | 
					
						
							|  |  |  | 					completeCallback: focusControl | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				focusControl(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Move menu item up one in the menu. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		moveUp: function() { | 
					
						
							|  |  |  | 			this._changePosition( -1 ); | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.movedUp ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Move menu item up one in the menu. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		moveDown: function() { | 
					
						
							|  |  |  | 			this._changePosition( 1 ); | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.movedDown ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Move menu item and all children up one level of depth. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		moveLeft: function() { | 
					
						
							|  |  |  | 			this._changeDepth( -1 ); | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.movedLeft ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Move menu item and children one level deeper, as a submenu of the previous item. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		moveRight: function() { | 
					
						
							|  |  |  | 			this._changeDepth( 1 ); | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.movedRight ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Note that this will trigger a UI update, causing child items to | 
					
						
							|  |  |  | 		 * move as well and cardinal order class names to be updated. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Number} offset 1|-1 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_changePosition: function( offset ) { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				adjacentSetting, | 
					
						
							|  |  |  | 				settingValue = _.clone( control.setting() ), | 
					
						
							|  |  |  | 				siblingSettings = [], | 
					
						
							|  |  |  | 				realPosition; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( 1 !== offset && -1 !== offset ) { | 
					
						
							|  |  |  | 				throw new Error( 'Offset changes by 1 are only supported.' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Skip moving deleted items.
 | 
					
						
							|  |  |  | 			if ( ! control.setting() ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Locate the other items under the same parent (siblings).
 | 
					
						
							|  |  |  | 			_( control.getMenuControl().getMenuItemControls() ).each(function( otherControl ) { | 
					
						
							|  |  |  | 				if ( otherControl.setting().menu_item_parent === settingValue.menu_item_parent ) { | 
					
						
							|  |  |  | 					siblingSettings.push( otherControl.setting ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			siblingSettings.sort(function( a, b ) { | 
					
						
							|  |  |  | 				return a().position - b().position; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			realPosition = _.indexOf( siblingSettings, control.setting ); | 
					
						
							|  |  |  | 			if ( -1 === realPosition ) { | 
					
						
							|  |  |  | 				throw new Error( 'Expected setting to be among siblings.' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Skip doing anything if the item is already at the edge in the desired direction.
 | 
					
						
							|  |  |  | 			if ( ( realPosition === 0 && offset < 0 ) || ( realPosition === siblingSettings.length - 1 && offset > 0 ) ) { | 
					
						
							|  |  |  | 				// @todo Should we allow a menu item to be moved up to break it out of a parent? Adopt with previous or following parent?
 | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Update any adjacent menu item setting to take on this item's position.
 | 
					
						
							|  |  |  | 			adjacentSetting = siblingSettings[ realPosition + offset ]; | 
					
						
							|  |  |  | 			if ( adjacentSetting ) { | 
					
						
							|  |  |  | 				adjacentSetting.set( $.extend( | 
					
						
							|  |  |  | 					_.clone( adjacentSetting() ), | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						position: settingValue.position | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				) ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			settingValue.position += offset; | 
					
						
							|  |  |  | 			control.setting.set( settingValue ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Note that this will trigger a UI update, causing child items to | 
					
						
							|  |  |  | 		 * move as well and cardinal order class names to be updated. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @private | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Number} offset 1|-1 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_changeDepth: function( offset ) { | 
					
						
							|  |  |  | 			if ( 1 !== offset && -1 !== offset ) { | 
					
						
							|  |  |  | 				throw new Error( 'Offset changes by 1 are only supported.' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				settingValue = _.clone( control.setting() ), | 
					
						
							|  |  |  | 				siblingControls = [], | 
					
						
							|  |  |  | 				realPosition, | 
					
						
							|  |  |  | 				siblingControl, | 
					
						
							|  |  |  | 				parentControl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Locate the other items under the same parent (siblings).
 | 
					
						
							|  |  |  | 			_( control.getMenuControl().getMenuItemControls() ).each(function( otherControl ) { | 
					
						
							|  |  |  | 				if ( otherControl.setting().menu_item_parent === settingValue.menu_item_parent ) { | 
					
						
							|  |  |  | 					siblingControls.push( otherControl ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			siblingControls.sort(function( a, b ) { | 
					
						
							|  |  |  | 				return a.setting().position - b.setting().position; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			realPosition = _.indexOf( siblingControls, control ); | 
					
						
							|  |  |  | 			if ( -1 === realPosition ) { | 
					
						
							|  |  |  | 				throw new Error( 'Expected control to be among siblings.' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( -1 === offset ) { | 
					
						
							|  |  |  | 				// Skip moving left an item that is already at the top level.
 | 
					
						
							|  |  |  | 				if ( ! settingValue.menu_item_parent ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				parentControl = api.control( 'nav_menu_item[' + settingValue.menu_item_parent + ']' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Make this control the parent of all the following siblings.
 | 
					
						
							|  |  |  | 				_( siblingControls ).chain().slice( realPosition ).each(function( siblingControl, i ) { | 
					
						
							|  |  |  | 					siblingControl.setting.set( | 
					
						
							|  |  |  | 						$.extend( | 
					
						
							|  |  |  | 							{}, | 
					
						
							|  |  |  | 							siblingControl.setting(), | 
					
						
							|  |  |  | 							{ | 
					
						
							|  |  |  | 								menu_item_parent: control.params.menu_item_id, | 
					
						
							|  |  |  | 								position: i | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						) | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Increase the positions of the parent item's subsequent children to make room for this one.
 | 
					
						
							|  |  |  | 				_( control.getMenuControl().getMenuItemControls() ).each(function( otherControl ) { | 
					
						
							|  |  |  | 					var otherControlSettingValue, isControlToBeShifted; | 
					
						
							|  |  |  | 					isControlToBeShifted = ( | 
					
						
							|  |  |  | 						otherControl.setting().menu_item_parent === parentControl.setting().menu_item_parent && | 
					
						
							|  |  |  | 						otherControl.setting().position > parentControl.setting().position | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					if ( isControlToBeShifted ) { | 
					
						
							|  |  |  | 						otherControlSettingValue = _.clone( otherControl.setting() ); | 
					
						
							|  |  |  | 						otherControl.setting.set( | 
					
						
							|  |  |  | 							$.extend( | 
					
						
							|  |  |  | 								otherControlSettingValue, | 
					
						
							|  |  |  | 								{ position: otherControlSettingValue.position + 1 } | 
					
						
							|  |  |  | 							) | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Make this control the following sibling of its parent item.
 | 
					
						
							|  |  |  | 				settingValue.position = parentControl.setting().position + 1; | 
					
						
							|  |  |  | 				settingValue.menu_item_parent = parentControl.setting().menu_item_parent; | 
					
						
							|  |  |  | 				control.setting.set( settingValue ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else if ( 1 === offset ) { | 
					
						
							|  |  |  | 				// Skip moving right an item that doesn't have a previous sibling.
 | 
					
						
							|  |  |  | 				if ( realPosition === 0 ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Make the control the last child of the previous sibling.
 | 
					
						
							|  |  |  | 				siblingControl = siblingControls[ realPosition - 1 ]; | 
					
						
							|  |  |  | 				settingValue.menu_item_parent = siblingControl.params.menu_item_id; | 
					
						
							|  |  |  | 				settingValue.position = 0; | 
					
						
							|  |  |  | 				_( control.getMenuControl().getMenuItemControls() ).each(function( otherControl ) { | 
					
						
							|  |  |  | 					if ( otherControl.setting().menu_item_parent === settingValue.menu_item_parent ) { | 
					
						
							|  |  |  | 						settingValue.position = Math.max( settingValue.position, otherControl.setting().position ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				settingValue.position += 1; | 
					
						
							|  |  |  | 				control.setting.set( settingValue ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenuNameControl | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer control for a nav menu's name. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenuNameControl | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Control | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuNameControl = api.Control.extend(/** @lends wp.customize.Menus.MenuNameControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( control.setting ) { | 
					
						
							|  |  |  | 				var settingValue = control.setting(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				control.nameElement = new api.Element( control.container.find( '.menu-name-field' ) ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				control.nameElement.bind(function( value ) { | 
					
						
							|  |  |  | 					var settingValue = control.setting(); | 
					
						
							|  |  |  | 					if ( settingValue && settingValue.name !== value ) { | 
					
						
							|  |  |  | 						settingValue = _.clone( settingValue ); | 
					
						
							|  |  |  | 						settingValue.name = value; | 
					
						
							|  |  |  | 						control.setting.set( settingValue ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				if ( settingValue ) { | 
					
						
							|  |  |  | 					control.nameElement.set( settingValue.name ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				control.setting.bind(function( object ) { | 
					
						
							|  |  |  | 					if ( object ) { | 
					
						
							|  |  |  | 						control.nameElement.set( object.name ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenuLocationsControl | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer control for a nav menu's locations. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @since 4.9.0 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenuLocationsControl | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Control | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuLocationsControl = api.Control.extend(/** @lends wp.customize.Menus.MenuLocationsControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up the control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function () { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.container.find( '.assigned-menu-location' ).each(function() { | 
					
						
							|  |  |  | 				var container = $( this ), | 
					
						
							|  |  |  | 					checkbox = container.find( 'input[type=checkbox]' ), | 
					
						
							|  |  |  | 					element = new api.Element( checkbox ), | 
					
						
							|  |  |  | 					navMenuLocationSetting = api( 'nav_menu_locations[' + checkbox.data( 'location-id' ) + ']' ), | 
					
						
							|  |  |  | 					isNewMenu = control.params.menu_id === '', | 
					
						
							|  |  |  | 					updateCheckbox = isNewMenu ? _.noop : function( checked ) { | 
					
						
							|  |  |  | 						element.set( checked ); | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					updateSetting = isNewMenu ? _.noop : function( checked ) { | 
					
						
							|  |  |  | 						navMenuLocationSetting.set( checked ? control.params.menu_id : 0 ); | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					updateSelectedMenuLabel = function( selectedMenuId ) { | 
					
						
							|  |  |  | 						var menuSetting = api( 'nav_menu[' + String( selectedMenuId ) + ']' ); | 
					
						
							|  |  |  | 						if ( ! selectedMenuId || ! menuSetting || ! menuSetting() ) { | 
					
						
							|  |  |  | 							container.find( '.theme-location-set' ).hide(); | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							container.find( '.theme-location-set' ).show().find( 'span' ).text( displayNavMenuName( menuSetting().name ) ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				updateCheckbox( navMenuLocationSetting.get() === control.params.menu_id ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				checkbox.on( 'change', function() { | 
					
						
							|  |  |  | 					// Note: We can't use element.bind( function( checked ){ ... } ) here because it will trigger a change as well.
 | 
					
						
							|  |  |  | 					updateSetting( this.checked ); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				navMenuLocationSetting.bind( function( selectedMenuId ) { | 
					
						
							|  |  |  | 					updateCheckbox( selectedMenuId === control.params.menu_id ); | 
					
						
							|  |  |  | 					updateSelectedMenuLabel( selectedMenuId ); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 				updateSelectedMenuLabel( navMenuLocationSetting.get() ); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set the selected locations. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * This method sets the selected locations and allows us to do things like | 
					
						
							|  |  |  | 		 * set the default location for a new menu. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Object.<string,boolean>} selections - A map of location selections. | 
					
						
							|  |  |  | 		 * @returns {void} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		setSelections: function( selections ) { | 
					
						
							|  |  |  | 			this.container.find( '.menu-location' ).each( function( i, checkboxNode ) { | 
					
						
							|  |  |  | 				var locationId = checkboxNode.dataset.locationId; | 
					
						
							|  |  |  | 				checkboxNode.checked = locationId in selections ? selections[ locationId ] : false; | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenuAutoAddControl | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer control for a nav menu's auto add. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenuAutoAddControl | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Control | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuAutoAddControl = api.Control.extend(/** @lends wp.customize.Menus.MenuAutoAddControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				settingValue = control.setting(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			 * Since the control is not registered in PHP, we need to prevent the | 
					
						
							|  |  |  | 			 * preview's sending of the activeControls to result in this control | 
					
						
							|  |  |  | 			 * being deactivated. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			control.active.validate = function() { | 
					
						
							|  |  |  | 				var value, section = api.section( control.section() ); | 
					
						
							|  |  |  | 				if ( section ) { | 
					
						
							|  |  |  | 					value = section.active(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					value = false; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return value; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.autoAddElement = new api.Element( control.container.find( 'input[type=checkbox].auto_add' ) ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.autoAddElement.bind(function( value ) { | 
					
						
							|  |  |  | 				var settingValue = control.setting(); | 
					
						
							|  |  |  | 				if ( settingValue && settingValue.name !== value ) { | 
					
						
							|  |  |  | 					settingValue = _.clone( settingValue ); | 
					
						
							|  |  |  | 					settingValue.auto_add = value; | 
					
						
							|  |  |  | 					control.setting.set( settingValue ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			if ( settingValue ) { | 
					
						
							|  |  |  | 				control.autoAddElement.set( settingValue.auto_add ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.setting.bind(function( object ) { | 
					
						
							|  |  |  | 				if ( object ) { | 
					
						
							|  |  |  | 					control.autoAddElement.set( object.auto_add ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * wp.customize.Menus.MenuControl | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Customizer control for menus. | 
					
						
							|  |  |  | 	 * Note that 'nav_menu' must match the WP_Menu_Customize_Control::$type | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @class    wp.customize.Menus.MenuControl | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @augments wp.customize.Control | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.MenuControl = api.Control.extend(/** @lends wp.customize.Menus.MenuControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up the control. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				section = api.section( control.section() ), | 
					
						
							|  |  |  | 				menuId = control.params.menu_id, | 
					
						
							|  |  |  | 				menu = control.setting(), | 
					
						
							|  |  |  | 				name, | 
					
						
							|  |  |  | 				widgetTemplate, | 
					
						
							|  |  |  | 				select; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( 'undefined' === typeof this.params.menu_id ) { | 
					
						
							|  |  |  | 				throw new Error( 'params.menu_id was not defined' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			 * Since the control is not registered in PHP, we need to prevent the | 
					
						
							|  |  |  | 			 * preview's sending of the activeControls to result in this control | 
					
						
							|  |  |  | 			 * being deactivated. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			control.active.validate = function() { | 
					
						
							|  |  |  | 				var value; | 
					
						
							|  |  |  | 				if ( section ) { | 
					
						
							|  |  |  | 					value = section.active(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					value = false; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return value; | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.$controlSection = section.headContainer; | 
					
						
							|  |  |  | 			control.$sectionContent = control.container.closest( '.accordion-section-content' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this._setupModel(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.section( control.section(), function( section ) { | 
					
						
							|  |  |  | 				section.deferred.initSortables.done(function( menuList ) { | 
					
						
							|  |  |  | 					control._setupSortable( menuList ); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this._setupAddition(); | 
					
						
							|  |  |  | 			this._setupTitle(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add menu to Navigation Menu widgets.
 | 
					
						
							|  |  |  | 			if ( menu ) { | 
					
						
							|  |  |  | 				name = displayNavMenuName( menu.name ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add the menu to the existing controls.
 | 
					
						
							|  |  |  | 				api.control.each( function( widgetControl ) { | 
					
						
							|  |  |  | 					if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					widgetControl.container.find( '.nav-menu-widget-form-controls:first' ).show(); | 
					
						
							|  |  |  | 					widgetControl.container.find( '.nav-menu-widget-no-menus-message:first' ).hide(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					select = widgetControl.container.find( 'select' ); | 
					
						
							|  |  |  | 					if ( 0 === select.find( 'option[value=' + String( menuId ) + ']' ).length ) { | 
					
						
							|  |  |  | 						select.append( new Option( name, menuId ) ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add the menu to the widget template.
 | 
					
						
							|  |  |  | 				widgetTemplate = $( '#available-widgets-list .widget-tpl:has( input.id_base[ value=nav_menu ] )' ); | 
					
						
							|  |  |  | 				widgetTemplate.find( '.nav-menu-widget-form-controls:first' ).show(); | 
					
						
							|  |  |  | 				widgetTemplate.find( '.nav-menu-widget-no-menus-message:first' ).hide(); | 
					
						
							|  |  |  | 				select = widgetTemplate.find( '.widget-inside select:first' ); | 
					
						
							|  |  |  | 				if ( 0 === select.find( 'option[value=' + String( menuId ) + ']' ).length ) { | 
					
						
							|  |  |  | 					select.append( new Option( name, menuId ) ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			 * Wait for menu items to be added. | 
					
						
							|  |  |  | 			 * Ideally, we'd bind to an event indicating construction is complete, | 
					
						
							|  |  |  | 			 * but deferring appears to be the best option today. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			_.defer( function () { | 
					
						
							|  |  |  | 				control.updateInvitationVisibility(); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Update ordering of menu item controls when the setting is updated. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupModel: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				menuId = control.params.menu_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.setting.bind( function( to ) { | 
					
						
							|  |  |  | 				var name; | 
					
						
							|  |  |  | 				if ( false === to ) { | 
					
						
							|  |  |  | 					control._handleDeletion(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// Update names in the Navigation Menu widgets.
 | 
					
						
							|  |  |  | 					name = displayNavMenuName( to.name ); | 
					
						
							|  |  |  | 					api.control.each( function( widgetControl ) { | 
					
						
							|  |  |  | 						if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						var select = widgetControl.container.find( 'select' ); | 
					
						
							|  |  |  | 						select.find( 'option[value=' + String( menuId ) + ']' ).text( name ); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Allow items in each menu to be re-ordered, and for the order to be previewed. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * Notice that the UI aspects here are handled by wpNavMenu.initSortables() | 
					
						
							|  |  |  | 		 * which is called in MenuSection.onChangeExpanded() | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {object} menuList - The element that has sortable(). | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupSortable: function( menuList ) { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! menuList.is( control.$sectionContent ) ) { | 
					
						
							|  |  |  | 				throw new Error( 'Unexpected menuList.' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuList.on( 'sortstart', function() { | 
					
						
							|  |  |  | 				control.isSorting = true; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuList.on( 'sortstop', function() { | 
					
						
							|  |  |  | 				setTimeout( function() { // Next tick.
 | 
					
						
							|  |  |  | 					var menuItemContainerIds = control.$sectionContent.sortable( 'toArray' ), | 
					
						
							|  |  |  | 						menuItemControls = [], | 
					
						
							|  |  |  | 						position = 0, | 
					
						
							|  |  |  | 						priority = 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					control.isSorting = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Reset horizontal scroll position when done dragging.
 | 
					
						
							|  |  |  | 					control.$sectionContent.scrollLeft( 0 ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					_.each( menuItemContainerIds, function( menuItemContainerId ) { | 
					
						
							|  |  |  | 						var menuItemId, menuItemControl, matches; | 
					
						
							|  |  |  | 						matches = menuItemContainerId.match( /^customize-control-nav_menu_item-(-?\d+)$/, '' ); | 
					
						
							|  |  |  | 						if ( ! matches ) { | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						menuItemId = parseInt( matches[1], 10 ); | 
					
						
							|  |  |  | 						menuItemControl = api.control( 'nav_menu_item[' + String( menuItemId ) + ']' ); | 
					
						
							|  |  |  | 						if ( menuItemControl ) { | 
					
						
							|  |  |  | 							menuItemControls.push( menuItemControl ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					_.each( menuItemControls, function( menuItemControl ) { | 
					
						
							|  |  |  | 						if ( false === menuItemControl.setting() ) { | 
					
						
							|  |  |  | 							// Skip deleted items.
 | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						var setting = _.clone( menuItemControl.setting() ); | 
					
						
							|  |  |  | 						position += 1; | 
					
						
							|  |  |  | 						priority += 1; | 
					
						
							|  |  |  | 						setting.position = position; | 
					
						
							|  |  |  | 						menuItemControl.priority( priority ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// Note that wpNavMenu will be setting this .menu-item-data-parent-id input's value.
 | 
					
						
							|  |  |  | 						setting.menu_item_parent = parseInt( menuItemControl.container.find( '.menu-item-data-parent-id' ).val(), 10 ); | 
					
						
							|  |  |  | 						if ( ! setting.menu_item_parent ) { | 
					
						
							|  |  |  | 							setting.menu_item_parent = 0; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						menuItemControl.setting.set( setting ); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			control.isReordering = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * Keyboard-accessible reordering. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			this.container.find( '.reorder-toggle' ).on( 'click', function() { | 
					
						
							|  |  |  | 				control.toggleReordering( ! control.isReordering ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up UI for adding a new menu item. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupAddition: function() { | 
					
						
							|  |  |  | 			var self = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.container.find( '.add-new-menu-item' ).on( 'click', function( event ) { | 
					
						
							|  |  |  | 				if ( self.$sectionContent.hasClass( 'reordering' ) ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( ! $( 'body' ).hasClass( 'adding-menu-items' ) ) { | 
					
						
							|  |  |  | 					$( this ).attr( 'aria-expanded', 'true' ); | 
					
						
							|  |  |  | 					api.Menus.availableMenuItemsPanel.open( self ); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					$( this ).attr( 'aria-expanded', 'false' ); | 
					
						
							|  |  |  | 					api.Menus.availableMenuItemsPanel.close(); | 
					
						
							|  |  |  | 					event.stopPropagation(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_handleDeletion: function() { | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				section, | 
					
						
							|  |  |  | 				menuId = control.params.menu_id, | 
					
						
							|  |  |  | 				removeSection, | 
					
						
							|  |  |  | 				widgetTemplate, | 
					
						
							|  |  |  | 				navMenuCount = 0; | 
					
						
							|  |  |  | 			section = api.section( control.section() ); | 
					
						
							|  |  |  | 			removeSection = function() { | 
					
						
							|  |  |  | 				section.container.remove(); | 
					
						
							|  |  |  | 				api.section.remove( section.id ); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( section && section.expanded() ) { | 
					
						
							|  |  |  | 				section.collapse({ | 
					
						
							|  |  |  | 					completeCallback: function() { | 
					
						
							|  |  |  | 						removeSection(); | 
					
						
							|  |  |  | 						wp.a11y.speak( api.Menus.data.l10n.menuDeleted ); | 
					
						
							|  |  |  | 						api.panel( 'nav_menus' ).focus(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				removeSection(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.each(function( setting ) { | 
					
						
							|  |  |  | 				if ( /^nav_menu\[/.test( setting.id ) && false !== setting() ) { | 
					
						
							|  |  |  | 					navMenuCount += 1; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Remove the menu from any Navigation Menu widgets.
 | 
					
						
							|  |  |  | 			api.control.each(function( widgetControl ) { | 
					
						
							|  |  |  | 				if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				var select = widgetControl.container.find( 'select' ); | 
					
						
							|  |  |  | 				if ( select.val() === String( menuId ) ) { | 
					
						
							|  |  |  | 					select.prop( 'selectedIndex', 0 ).trigger( 'change' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				widgetControl.container.find( '.nav-menu-widget-form-controls:first' ).toggle( 0 !== navMenuCount ); | 
					
						
							|  |  |  | 				widgetControl.container.find( '.nav-menu-widget-no-menus-message:first' ).toggle( 0 === navMenuCount ); | 
					
						
							|  |  |  | 				widgetControl.container.find( 'option[value=' + String( menuId ) + ']' ).remove(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Remove the menu to the nav menu widget template.
 | 
					
						
							|  |  |  | 			widgetTemplate = $( '#available-widgets-list .widget-tpl:has( input.id_base[ value=nav_menu ] )' ); | 
					
						
							|  |  |  | 			widgetTemplate.find( '.nav-menu-widget-form-controls:first' ).toggle( 0 !== navMenuCount ); | 
					
						
							|  |  |  | 			widgetTemplate.find( '.nav-menu-widget-no-menus-message:first' ).toggle( 0 === navMenuCount ); | 
					
						
							|  |  |  | 			widgetTemplate.find( 'option[value=' + String( menuId ) + ']' ).remove(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Update Section Title as menu name is changed. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_setupTitle: function() { | 
					
						
							|  |  |  | 			var control = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			control.setting.bind( function( menu ) { | 
					
						
							|  |  |  | 				if ( ! menu ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var section = api.section( control.section() ), | 
					
						
							|  |  |  | 					menuId = control.params.menu_id, | 
					
						
							|  |  |  | 					controlTitle = section.headContainer.find( '.accordion-section-title' ), | 
					
						
							|  |  |  | 					sectionTitle = section.contentContainer.find( '.customize-section-title h3' ), | 
					
						
							|  |  |  | 					location = section.headContainer.find( '.menu-in-location' ), | 
					
						
							|  |  |  | 					action = sectionTitle.find( '.customize-action' ), | 
					
						
							|  |  |  | 					name = displayNavMenuName( menu.name ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the control title
 | 
					
						
							|  |  |  | 				controlTitle.text( name ); | 
					
						
							|  |  |  | 				if ( location.length ) { | 
					
						
							|  |  |  | 					location.appendTo( controlTitle ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the section title
 | 
					
						
							|  |  |  | 				sectionTitle.text( name ); | 
					
						
							|  |  |  | 				if ( action.length ) { | 
					
						
							|  |  |  | 					action.prependTo( sectionTitle ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the nav menu name in location selects.
 | 
					
						
							|  |  |  | 				api.control.each( function( control ) { | 
					
						
							|  |  |  | 					if ( /^nav_menu_locations\[/.test( control.id ) ) { | 
					
						
							|  |  |  | 						control.container.find( 'option[value=' + menuId + ']' ).text( name ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the nav menu name in all location checkboxes.
 | 
					
						
							|  |  |  | 				section.contentContainer.find( '.customize-control-checkbox input' ).each( function() { | 
					
						
							|  |  |  | 					if ( $( this ).prop( 'checked' ) ) { | 
					
						
							|  |  |  | 						$( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( name ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*********************************************************************** | 
					
						
							|  |  |  | 		 * Begin public API methods | 
					
						
							|  |  |  | 		 **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Enable/disable the reordering UI | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {Boolean} showOrHide to enable/disable reordering | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		toggleReordering: function( showOrHide ) { | 
					
						
							|  |  |  | 			var addNewItemBtn = this.container.find( '.add-new-menu-item' ), | 
					
						
							|  |  |  | 				reorderBtn = this.container.find( '.reorder-toggle' ), | 
					
						
							|  |  |  | 				itemsTitle = this.$sectionContent.find( '.item-title' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			showOrHide = Boolean( showOrHide ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( showOrHide === this.$sectionContent.hasClass( 'reordering' ) ) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.isReordering = showOrHide; | 
					
						
							|  |  |  | 			this.$sectionContent.toggleClass( 'reordering', showOrHide ); | 
					
						
							|  |  |  | 			this.$sectionContent.sortable( this.isReordering ? 'disable' : 'enable' ); | 
					
						
							|  |  |  | 			if ( this.isReordering ) { | 
					
						
							|  |  |  | 				addNewItemBtn.attr({ 'tabindex': '-1', 'aria-hidden': 'true' }); | 
					
						
							|  |  |  | 				reorderBtn.attr( 'aria-label', api.Menus.data.l10n.reorderLabelOff ); | 
					
						
							|  |  |  | 				wp.a11y.speak( api.Menus.data.l10n.reorderModeOn ); | 
					
						
							|  |  |  | 				itemsTitle.attr( 'aria-hidden', 'false' ); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				addNewItemBtn.removeAttr( 'tabindex aria-hidden' ); | 
					
						
							|  |  |  | 				reorderBtn.attr( 'aria-label', api.Menus.data.l10n.reorderLabelOn ); | 
					
						
							|  |  |  | 				wp.a11y.speak( api.Menus.data.l10n.reorderModeOff ); | 
					
						
							|  |  |  | 				itemsTitle.attr( 'aria-hidden', 'true' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( showOrHide ) { | 
					
						
							|  |  |  | 				_( this.getMenuItemControls() ).each( function( formControl ) { | 
					
						
							|  |  |  | 					formControl.collapseForm(); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @return {wp.customize.controlConstructor.nav_menu_item[]} | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		getMenuItemControls: function() { | 
					
						
							|  |  |  | 			var menuControl = this, | 
					
						
							|  |  |  | 				menuItemControls = [], | 
					
						
							|  |  |  | 				menuTermId = menuControl.params.menu_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.control.each(function( control ) { | 
					
						
							|  |  |  | 				if ( 'nav_menu_item' === control.params.type && control.setting() && menuTermId === control.setting().nav_menu_term_id ) { | 
					
						
							|  |  |  | 					menuItemControls.push( control ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return menuItemControls; | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Make sure that each menu item control has the proper depth. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		reflowMenuItems: function() { | 
					
						
							|  |  |  | 			var menuControl = this, | 
					
						
							|  |  |  | 				menuItemControls = menuControl.getMenuItemControls(), | 
					
						
							|  |  |  | 				reflowRecursively; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			reflowRecursively = function( context ) { | 
					
						
							|  |  |  | 				var currentMenuItemControls = [], | 
					
						
							|  |  |  | 					thisParent = context.currentParent; | 
					
						
							|  |  |  | 				_.each( context.menuItemControls, function( menuItemControl ) { | 
					
						
							|  |  |  | 					if ( thisParent === menuItemControl.setting().menu_item_parent ) { | 
					
						
							|  |  |  | 						currentMenuItemControls.push( menuItemControl ); | 
					
						
							|  |  |  | 						// @todo We could remove this item from menuItemControls now, for efficiency.
 | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				currentMenuItemControls.sort( function( a, b ) { | 
					
						
							|  |  |  | 					return a.setting().position - b.setting().position; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				_.each( currentMenuItemControls, function( menuItemControl ) { | 
					
						
							|  |  |  | 					// Update position.
 | 
					
						
							|  |  |  | 					context.currentAbsolutePosition += 1; | 
					
						
							|  |  |  | 					menuItemControl.priority.set( context.currentAbsolutePosition ); // This will change the sort order.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Update depth.
 | 
					
						
							|  |  |  | 					if ( ! menuItemControl.container.hasClass( 'menu-item-depth-' + String( context.currentDepth ) ) ) { | 
					
						
							|  |  |  | 						_.each( menuItemControl.container.prop( 'className' ).match( /menu-item-depth-\d+/g ), function( className ) { | 
					
						
							|  |  |  | 							menuItemControl.container.removeClass( className ); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 						menuItemControl.container.addClass( 'menu-item-depth-' + String( context.currentDepth ) ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					menuItemControl.container.data( 'item-depth', context.currentDepth ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Process any children items.
 | 
					
						
							|  |  |  | 					context.currentDepth += 1; | 
					
						
							|  |  |  | 					context.currentParent = menuItemControl.params.menu_item_id; | 
					
						
							|  |  |  | 					reflowRecursively( context ); | 
					
						
							|  |  |  | 					context.currentDepth -= 1; | 
					
						
							|  |  |  | 					context.currentParent = thisParent; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update class names for reordering controls.
 | 
					
						
							|  |  |  | 				if ( currentMenuItemControls.length ) { | 
					
						
							|  |  |  | 					_( currentMenuItemControls ).each(function( menuItemControl ) { | 
					
						
							|  |  |  | 						menuItemControl.container.removeClass( 'move-up-disabled move-down-disabled move-left-disabled move-right-disabled' ); | 
					
						
							|  |  |  | 						if ( 0 === context.currentDepth ) { | 
					
						
							|  |  |  | 							menuItemControl.container.addClass( 'move-left-disabled' ); | 
					
						
							|  |  |  | 						} else if ( 10 === context.currentDepth ) { | 
					
						
							|  |  |  | 							menuItemControl.container.addClass( 'move-right-disabled' ); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					currentMenuItemControls[0].container | 
					
						
							|  |  |  | 						.addClass( 'move-up-disabled' ) | 
					
						
							|  |  |  | 						.addClass( 'move-right-disabled' ) | 
					
						
							|  |  |  | 						.toggleClass( 'move-down-disabled', 1 === currentMenuItemControls.length ); | 
					
						
							|  |  |  | 					currentMenuItemControls[ currentMenuItemControls.length - 1 ].container | 
					
						
							|  |  |  | 						.addClass( 'move-down-disabled' ) | 
					
						
							|  |  |  | 						.toggleClass( 'move-up-disabled', 1 === currentMenuItemControls.length ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			reflowRecursively( { | 
					
						
							|  |  |  | 				menuItemControls: menuItemControls, | 
					
						
							|  |  |  | 				currentParent: 0, | 
					
						
							|  |  |  | 				currentDepth: 0, | 
					
						
							|  |  |  | 				currentAbsolutePosition: 0 | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuControl.updateInvitationVisibility( menuItemControls ); | 
					
						
							|  |  |  | 			menuControl.container.find( '.reorder-toggle' ).toggle( menuItemControls.length > 1 ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Note that this function gets debounced so that when a lot of setting | 
					
						
							|  |  |  | 		 * changes are made at once, for instance when moving a menu item that | 
					
						
							|  |  |  | 		 * has child items, this function will only be called once all of the | 
					
						
							|  |  |  | 		 * settings have been updated. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		debouncedReflowMenuItems: _.debounce( function() { | 
					
						
							|  |  |  | 			this.reflowMenuItems.apply( this, arguments ); | 
					
						
							|  |  |  | 		}, 0 ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Add a new item to this menu. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {object} item - Value for the nav_menu_item setting to be created. | 
					
						
							|  |  |  | 		 * @returns {wp.customize.Menus.controlConstructor.nav_menu_item} The newly-created nav_menu_item control instance. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		addItemToMenu: function( item ) { | 
					
						
							|  |  |  | 			var menuControl = this, customizeId, settingArgs, setting, menuItemControl, placeholderId, position = 0, priority = 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			_.each( menuControl.getMenuItemControls(), function( control ) { | 
					
						
							|  |  |  | 				if ( false === control.setting() ) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				priority = Math.max( priority, control.priority() ); | 
					
						
							|  |  |  | 				if ( 0 === control.setting().menu_item_parent ) { | 
					
						
							|  |  |  | 					position = Math.max( position, control.setting().position ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			position += 1; | 
					
						
							|  |  |  | 			priority += 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			item = $.extend( | 
					
						
							|  |  |  | 				{}, | 
					
						
							|  |  |  | 				api.Menus.data.defaultSettingValues.nav_menu_item, | 
					
						
							|  |  |  | 				item, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					nav_menu_term_id: menuControl.params.menu_id, | 
					
						
							|  |  |  | 					original_title: item.title, | 
					
						
							|  |  |  | 					position: position | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			delete item.id; // only used by Backbone
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			placeholderId = api.Menus.generatePlaceholderAutoIncrementId(); | 
					
						
							|  |  |  | 			customizeId = 'nav_menu_item[' + String( placeholderId ) + ']'; | 
					
						
							|  |  |  | 			settingArgs = { | 
					
						
							|  |  |  | 				type: 'nav_menu_item', | 
					
						
							|  |  |  | 				transport: api.Menus.data.settingTransport, | 
					
						
							|  |  |  | 				previewer: api.previewer | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			setting = api.create( customizeId, customizeId, {}, settingArgs ); | 
					
						
							|  |  |  | 			setting.set( item ); // Change from initial empty object to actual item to mark as dirty.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Add the menu item control.
 | 
					
						
							|  |  |  | 			menuItemControl = new api.controlConstructor.nav_menu_item( customizeId, { | 
					
						
							|  |  |  | 				type: 'nav_menu_item', | 
					
						
							|  |  |  | 				section: menuControl.id, | 
					
						
							|  |  |  | 				priority: priority, | 
					
						
							|  |  |  | 				settings: { | 
					
						
							|  |  |  | 					'default': customizeId | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				menu_item_id: placeholderId | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			api.control.add( menuItemControl ); | 
					
						
							|  |  |  | 			setting.preview(); | 
					
						
							|  |  |  | 			menuControl.debouncedReflowMenuItems(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.itemAdded ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return menuItemControl; | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Show an invitation to add new menu items when there are no menu items. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @since 4.9.0 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param {wp.customize.controlConstructor.nav_menu_item[]} optionalMenuItemControls | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		updateInvitationVisibility: function ( optionalMenuItemControls ) { | 
					
						
							|  |  |  | 			var menuItemControls = optionalMenuItemControls || this.getMenuItemControls(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.container.find( '.new-menu-item-invitation' ).toggle( menuItemControls.length === 0 ); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	api.Menus.NewMenuControl = api.Control.extend(/** @lends wp.customize.Menus.NewMenuControl.prototype */{ | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 		 * wp.customize.Menus.NewMenuControl | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 		 * Customizer control for creating new menus and handling deletion of existing menus. | 
					
						
							|  |  |  | 		 * Note that 'new_menu' must match the WP_Customize_New_Menu_Control::$type. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @constructs wp.customize.Menus.NewMenuControl | 
					
						
							|  |  |  | 		 * @augments   wp.customize.Control | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @deprecated 4.9.0 This class is no longer used due to new menu creation UX. | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 		 */ | 
					
						
							|  |  |  | 		initialize: function() { | 
					
						
							|  |  |  | 			if ( 'undefined' !== typeof console && console.warn ) { | 
					
						
							|  |  |  | 				console.warn( '[DEPRECATED] wp.customize.NewMenuControl will be removed. Please use wp.customize.Menus.createNavMenu() instead.' ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			api.Control.prototype.initialize.apply( this, arguments ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Set up the control. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @deprecated 4.9.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ready: function() { | 
					
						
							|  |  |  | 			this._bindHandlers(); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_bindHandlers: function() { | 
					
						
							|  |  |  | 			var self = this, | 
					
						
							|  |  |  | 				name = $( '#customize-control-new_menu_name input' ), | 
					
						
							|  |  |  | 				submit = $( '#create-new-menu-submit' ); | 
					
						
							|  |  |  | 			name.on( 'keydown', function( event ) { | 
					
						
							|  |  |  | 				if ( 13 === event.which ) { // Enter.
 | 
					
						
							|  |  |  | 					self.submit(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 			submit.on( 'click', function( event ) { | 
					
						
							|  |  |  | 				self.submit(); | 
					
						
							|  |  |  | 				event.stopPropagation(); | 
					
						
							|  |  |  | 				event.preventDefault(); | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Create the new menu with the name supplied. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @deprecated 4.9.0 | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		submit: function() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var control = this, | 
					
						
							|  |  |  | 				container = control.container.closest( '.accordion-section-new-menu' ), | 
					
						
							|  |  |  | 				nameInput = container.find( '.menu-name-field' ).first(), | 
					
						
							|  |  |  | 				name = nameInput.val(), | 
					
						
							|  |  |  | 				menuSection; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ( ! name ) { | 
					
						
							|  |  |  | 				nameInput.addClass( 'invalid' ); | 
					
						
							|  |  |  | 				nameInput.focus(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			menuSection = api.Menus.createNavMenu( name ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Clear name field.
 | 
					
						
							|  |  |  | 			nameInput.val( '' ); | 
					
						
							|  |  |  | 			nameInput.removeClass( 'invalid' ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			wp.a11y.speak( api.Menus.data.l10n.menuAdded ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Focus on the new menu section.
 | 
					
						
							|  |  |  | 			menuSection.focus(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Extends wp.customize.controlConstructor with control constructor for | 
					
						
							|  |  |  | 	 * menu_location, menu_item, nav_menu, and new_menu. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	$.extend( api.controlConstructor, { | 
					
						
							|  |  |  | 		nav_menu_location: api.Menus.MenuLocationControl, | 
					
						
							|  |  |  | 		nav_menu_item: api.Menus.MenuItemControl, | 
					
						
							|  |  |  | 		nav_menu: api.Menus.MenuControl, | 
					
						
							|  |  |  | 		nav_menu_name: api.Menus.MenuNameControl, | 
					
						
							|  |  |  | 		new_menu: api.Menus.NewMenuControl, // @todo Remove in a future release. See #42364.
 | 
					
						
							|  |  |  | 		nav_menu_locations: api.Menus.MenuLocationsControl, | 
					
						
							|  |  |  | 		nav_menu_auto_add: api.Menus.MenuAutoAddControl | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Extends wp.customize.panelConstructor with section constructor for menus. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	$.extend( api.panelConstructor, { | 
					
						
							|  |  |  | 		nav_menus: api.Menus.MenusPanel | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Extends wp.customize.sectionConstructor with section constructor for menu. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	$.extend( api.sectionConstructor, { | 
					
						
							|  |  |  | 		nav_menu: api.Menus.MenuSection, | 
					
						
							|  |  |  | 		new_menu: api.Menus.NewMenuSection | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Init Customizer for menus. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.bind( 'ready', function() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Set up the menu items panel.
 | 
					
						
							|  |  |  | 		api.Menus.availableMenuItemsPanel = new api.Menus.AvailableMenuItemsPanelView({ | 
					
						
							|  |  |  | 			collection: api.Menus.availableMenuItems | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		api.bind( 'saved', function( data ) { | 
					
						
							|  |  |  | 			if ( data.nav_menu_updates || data.nav_menu_item_updates ) { | 
					
						
							|  |  |  | 				api.Menus.applySavedData( data ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* | 
					
						
							|  |  |  | 		 * Reset the list of posts created in the customizer once published. | 
					
						
							|  |  |  | 		 * The setting is updated quietly (bypassing events being triggered) | 
					
						
							|  |  |  | 		 * so that the customized state doesn't become immediately dirty. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		api.state( 'changesetStatus' ).bind( function( status ) { | 
					
						
							|  |  |  | 			if ( 'publish' === status ) { | 
					
						
							|  |  |  | 				api( 'nav_menus_created_posts' )._value = []; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Open and focus menu control.
 | 
					
						
							|  |  |  | 		api.previewer.bind( 'focus-nav-menu-item-control', api.Menus.focusMenuItemControl ); | 
					
						
							|  |  |  | 	} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * When customize_save comes back with a success, make sure any inserted | 
					
						
							|  |  |  | 	 * nav menus and items are properly re-added with their newly-assigned IDs. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus.applySavedData | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @param {object} data | 
					
						
							|  |  |  | 	 * @param {array} data.nav_menu_updates | 
					
						
							|  |  |  | 	 * @param {array} data.nav_menu_item_updates | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.applySavedData = function( data ) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var insertedMenuIdMapping = {}, insertedMenuItemIdMapping = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_( data.nav_menu_updates ).each(function( update ) { | 
					
						
							|  |  |  | 			var oldCustomizeId, newCustomizeId, customizeId, oldSetting, newSetting, setting, settingValue, oldSection, newSection, wasSaved, widgetTemplate, navMenuCount, shouldExpandNewSection; | 
					
						
							|  |  |  | 			if ( 'inserted' === update.status ) { | 
					
						
							|  |  |  | 				if ( ! update.previous_term_id ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected previous_term_id' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if ( ! update.term_id ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected term_id' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				oldCustomizeId = 'nav_menu[' + String( update.previous_term_id ) + ']'; | 
					
						
							|  |  |  | 				if ( ! api.has( oldCustomizeId ) ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected setting to exist: ' + oldCustomizeId ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				oldSetting = api( oldCustomizeId ); | 
					
						
							|  |  |  | 				if ( ! api.section.has( oldCustomizeId ) ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected control to exist: ' + oldCustomizeId ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				oldSection = api.section( oldCustomizeId ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				settingValue = oldSetting.get(); | 
					
						
							|  |  |  | 				if ( ! settingValue ) { | 
					
						
							|  |  |  | 					throw new Error( 'Did not expect setting to be empty (deleted).' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				settingValue = $.extend( _.clone( settingValue ), update.saved_value ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				insertedMenuIdMapping[ update.previous_term_id ] = update.term_id; | 
					
						
							|  |  |  | 				newCustomizeId = 'nav_menu[' + String( update.term_id ) + ']'; | 
					
						
							|  |  |  | 				newSetting = api.create( newCustomizeId, newCustomizeId, settingValue, { | 
					
						
							|  |  |  | 					type: 'nav_menu', | 
					
						
							|  |  |  | 					transport: api.Menus.data.settingTransport, | 
					
						
							|  |  |  | 					previewer: api.previewer | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				shouldExpandNewSection = oldSection.expanded(); | 
					
						
							|  |  |  | 				if ( shouldExpandNewSection ) { | 
					
						
							|  |  |  | 					oldSection.collapse(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add the menu section.
 | 
					
						
							|  |  |  | 				newSection = new api.Menus.MenuSection( newCustomizeId, { | 
					
						
							|  |  |  | 					panel: 'nav_menus', | 
					
						
							|  |  |  | 					title: settingValue.name, | 
					
						
							|  |  |  | 					customizeAction: api.Menus.data.l10n.customizingMenus, | 
					
						
							|  |  |  | 					type: 'nav_menu', | 
					
						
							|  |  |  | 					priority: oldSection.priority.get(), | 
					
						
							|  |  |  | 					menu_id: update.term_id | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add new control for the new menu.
 | 
					
						
							|  |  |  | 				api.section.add( newSection ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the values for nav menus in Navigation Menu controls.
 | 
					
						
							|  |  |  | 				api.control.each( function( setting ) { | 
					
						
							|  |  |  | 					if ( ! setting.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== setting.params.widget_id_base ) { | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					var select, oldMenuOption, newMenuOption; | 
					
						
							|  |  |  | 					select = setting.container.find( 'select' ); | 
					
						
							|  |  |  | 					oldMenuOption = select.find( 'option[value=' + String( update.previous_term_id ) + ']' ); | 
					
						
							|  |  |  | 					newMenuOption = select.find( 'option[value=' + String( update.term_id ) + ']' ); | 
					
						
							|  |  |  | 					newMenuOption.prop( 'selected', oldMenuOption.prop( 'selected' ) ); | 
					
						
							|  |  |  | 					oldMenuOption.remove(); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Delete the old placeholder nav_menu.
 | 
					
						
							|  |  |  | 				oldSetting.callbacks.disable(); // Prevent setting triggering Customizer dirty state when set.
 | 
					
						
							|  |  |  | 				oldSetting.set( false ); | 
					
						
							|  |  |  | 				oldSetting.preview(); | 
					
						
							|  |  |  | 				newSetting.preview(); | 
					
						
							|  |  |  | 				oldSetting._dirty = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Remove nav_menu section.
 | 
					
						
							|  |  |  | 				oldSection.container.remove(); | 
					
						
							|  |  |  | 				api.section.remove( oldCustomizeId ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the nav_menu widget to reflect removed placeholder menu.
 | 
					
						
							|  |  |  | 				navMenuCount = 0; | 
					
						
							|  |  |  | 				api.each(function( setting ) { | 
					
						
							|  |  |  | 					if ( /^nav_menu\[/.test( setting.id ) && false !== setting() ) { | 
					
						
							|  |  |  | 						navMenuCount += 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				widgetTemplate = $( '#available-widgets-list .widget-tpl:has( input.id_base[ value=nav_menu ] )' ); | 
					
						
							|  |  |  | 				widgetTemplate.find( '.nav-menu-widget-form-controls:first' ).toggle( 0 !== navMenuCount ); | 
					
						
							|  |  |  | 				widgetTemplate.find( '.nav-menu-widget-no-menus-message:first' ).toggle( 0 === navMenuCount ); | 
					
						
							|  |  |  | 				widgetTemplate.find( 'option[value=' + String( update.previous_term_id ) + ']' ).remove(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update the nav_menu_locations[...] controls to remove the placeholder menus from the dropdown options.
 | 
					
						
							|  |  |  | 				wp.customize.control.each(function( control ){ | 
					
						
							|  |  |  | 					if ( /^nav_menu_locations\[/.test( control.id ) ) { | 
					
						
							|  |  |  | 						control.container.find( 'option[value=' + String( update.previous_term_id ) + ']' ).remove(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Update nav_menu_locations to reference the new ID.
 | 
					
						
							|  |  |  | 				api.each( function( setting ) { | 
					
						
							|  |  |  | 					var wasSaved = api.state( 'saved' ).get(); | 
					
						
							|  |  |  | 					if ( /^nav_menu_locations\[/.test( setting.id ) && setting.get() === update.previous_term_id ) { | 
					
						
							|  |  |  | 						setting.set( update.term_id ); | 
					
						
							|  |  |  | 						setting._dirty = false; // Not dirty because this is has also just been done on server in WP_Customize_Nav_Menu_Setting::update().
 | 
					
						
							|  |  |  | 						api.state( 'saved' ).set( wasSaved ); | 
					
						
							|  |  |  | 						setting.preview(); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if ( shouldExpandNewSection ) { | 
					
						
							|  |  |  | 					newSection.expand(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else if ( 'updated' === update.status ) { | 
					
						
							|  |  |  | 				customizeId = 'nav_menu[' + String( update.term_id ) + ']'; | 
					
						
							|  |  |  | 				if ( ! api.has( customizeId ) ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected setting to exist: ' + customizeId ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Make sure the setting gets updated with its sanitized server value (specifically the conflict-resolved name).
 | 
					
						
							|  |  |  | 				setting = api( customizeId ); | 
					
						
							|  |  |  | 				if ( ! _.isEqual( update.saved_value, setting.get() ) ) { | 
					
						
							|  |  |  | 					wasSaved = api.state( 'saved' ).get(); | 
					
						
							|  |  |  | 					setting.set( update.saved_value ); | 
					
						
							|  |  |  | 					setting._dirty = false; | 
					
						
							|  |  |  | 					api.state( 'saved' ).set( wasSaved ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Build up mapping of nav_menu_item placeholder IDs to inserted IDs.
 | 
					
						
							|  |  |  | 		_( data.nav_menu_item_updates ).each(function( update ) { | 
					
						
							|  |  |  | 			if ( update.previous_post_id ) { | 
					
						
							|  |  |  | 				insertedMenuItemIdMapping[ update.previous_post_id ] = update.post_id; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_( data.nav_menu_item_updates ).each(function( update ) { | 
					
						
							|  |  |  | 			var oldCustomizeId, newCustomizeId, oldSetting, newSetting, settingValue, oldControl, newControl; | 
					
						
							|  |  |  | 			if ( 'inserted' === update.status ) { | 
					
						
							|  |  |  | 				if ( ! update.previous_post_id ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected previous_post_id' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if ( ! update.post_id ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected post_id' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				oldCustomizeId = 'nav_menu_item[' + String( update.previous_post_id ) + ']'; | 
					
						
							|  |  |  | 				if ( ! api.has( oldCustomizeId ) ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected setting to exist: ' + oldCustomizeId ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				oldSetting = api( oldCustomizeId ); | 
					
						
							|  |  |  | 				if ( ! api.control.has( oldCustomizeId ) ) { | 
					
						
							|  |  |  | 					throw new Error( 'Expected control to exist: ' + oldCustomizeId ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				oldControl = api.control( oldCustomizeId ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				settingValue = oldSetting.get(); | 
					
						
							|  |  |  | 				if ( ! settingValue ) { | 
					
						
							|  |  |  | 					throw new Error( 'Did not expect setting to be empty (deleted).' ); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				settingValue = _.clone( settingValue ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// If the parent menu item was also inserted, update the menu_item_parent to the new ID.
 | 
					
						
							|  |  |  | 				if ( settingValue.menu_item_parent < 0 ) { | 
					
						
							|  |  |  | 					if ( ! insertedMenuItemIdMapping[ settingValue.menu_item_parent ] ) { | 
					
						
							|  |  |  | 						throw new Error( 'inserted ID for menu_item_parent not available' ); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					settingValue.menu_item_parent = insertedMenuItemIdMapping[ settingValue.menu_item_parent ]; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// If the menu was also inserted, then make sure it uses the new menu ID for nav_menu_term_id.
 | 
					
						
							|  |  |  | 				if ( insertedMenuIdMapping[ settingValue.nav_menu_term_id ] ) { | 
					
						
							|  |  |  | 					settingValue.nav_menu_term_id = insertedMenuIdMapping[ settingValue.nav_menu_term_id ]; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				newCustomizeId = 'nav_menu_item[' + String( update.post_id ) + ']'; | 
					
						
							|  |  |  | 				newSetting = api.create( newCustomizeId, newCustomizeId, settingValue, { | 
					
						
							|  |  |  | 					type: 'nav_menu_item', | 
					
						
							|  |  |  | 					transport: api.Menus.data.settingTransport, | 
					
						
							|  |  |  | 					previewer: api.previewer | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add the menu control.
 | 
					
						
							|  |  |  | 				newControl = new api.controlConstructor.nav_menu_item( newCustomizeId, { | 
					
						
							|  |  |  | 					type: 'nav_menu_item', | 
					
						
							|  |  |  | 					menu_id: update.post_id, | 
					
						
							|  |  |  | 					section: 'nav_menu[' + String( settingValue.nav_menu_term_id ) + ']', | 
					
						
							|  |  |  | 					priority: oldControl.priority.get(), | 
					
						
							|  |  |  | 					settings: { | 
					
						
							|  |  |  | 						'default': newCustomizeId | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					menu_item_id: update.post_id | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Remove old control.
 | 
					
						
							|  |  |  | 				oldControl.container.remove(); | 
					
						
							|  |  |  | 				api.control.remove( oldCustomizeId ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Add new control to take its place.
 | 
					
						
							|  |  |  | 				api.control.add( newControl ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Delete the placeholder and preview the new setting.
 | 
					
						
							|  |  |  | 				oldSetting.callbacks.disable(); // Prevent setting triggering Customizer dirty state when set.
 | 
					
						
							|  |  |  | 				oldSetting.set( false ); | 
					
						
							|  |  |  | 				oldSetting.preview(); | 
					
						
							|  |  |  | 				newSetting.preview(); | 
					
						
							|  |  |  | 				oldSetting._dirty = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				newControl.container.toggleClass( 'menu-item-edit-inactive', oldControl.container.hasClass( 'menu-item-edit-inactive' ) ); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* | 
					
						
							|  |  |  | 		 * Update the settings for any nav_menu widgets that had selected a placeholder ID. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		_.each( data.widget_nav_menu_updates, function( widgetSettingValue, widgetSettingId ) { | 
					
						
							|  |  |  | 			var setting = api( widgetSettingId ); | 
					
						
							|  |  |  | 			if ( setting ) { | 
					
						
							|  |  |  | 				setting._value = widgetSettingValue; | 
					
						
							|  |  |  | 				setting.preview(); // Send to the preview now so that menu refresh will use the inserted menu.
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Focus a menu item control. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus.focusMenuItemControl | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @param {string} menuItemId | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.focusMenuItemControl = function( menuItemId ) { | 
					
						
							|  |  |  | 		var control = api.Menus.getMenuItemControl( menuItemId ); | 
					
						
							|  |  |  | 		if ( control ) { | 
					
						
							|  |  |  | 			control.focus(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Get the control for a given menu. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus.getMenuControl | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @param menuId | 
					
						
							|  |  |  | 	 * @return {wp.customize.controlConstructor.menus[]} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.getMenuControl = function( menuId ) { | 
					
						
							|  |  |  | 		return api.control( 'nav_menu[' + menuId + ']' ); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Given a menu item ID, get the control associated with it. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus.getMenuItemControl | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @param {string} menuItemId | 
					
						
							|  |  |  | 	 * @return {object|null} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	api.Menus.getMenuItemControl = function( menuItemId ) { | 
					
						
							|  |  |  | 		return api.control( menuItemIdToSettingId( menuItemId ) ); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus~menuItemIdToSettingId | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @param {String} menuItemId | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	function menuItemIdToSettingId( menuItemId ) { | 
					
						
							|  |  |  | 		return 'nav_menu_item[' + menuItemId + ']'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Apply sanitize_text_field()-like logic to the supplied name, returning a | 
					
						
							|  |  |  | 	 * "unnammed" fallback string if the name is then empty. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-04-16 20:56:22 +01:00
										 |  |  | 	 * @alias wp.customize.Menus~displayNavMenuName | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2019-03-12 09:27:46 +00:00
										 |  |  | 	 * @param {string} name | 
					
						
							|  |  |  | 	 * @returns {string} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	function displayNavMenuName( name ) { | 
					
						
							|  |  |  | 		name = name || ''; | 
					
						
							|  |  |  | 		name = $( '<div>' ).text( name ).html(); // Emulate esc_html() which is used in wp-admin/nav-menus.php.
 | 
					
						
							|  |  |  | 		name = $.trim( name ); | 
					
						
							|  |  |  | 		return name || api.Menus.data.l10n.unnamed; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | })( wp.customize, wp, jQuery ); |