WordPress/wp-admin/js/nav-menu.js
Andrew Nacin 2710bcade1 Switch to .min for compressed JS and CSS files.
* This moves our "development" versions from .dev.js to .js (same for css).
 * The compressed version then moves from .js to .min.js (same for css).

By switching to the standard .min convention, it sets expectations for developers,
and works nicely with existing tools such as ack.

fixes #21633.



git-svn-id: http://core.svn.wordpress.org/trunk@21592 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2012-08-23 00:04:18 +00:00

966 lines
29 KiB
JavaScript

/**
* WordPress Administration Navigation Menu
* Interface JS functions
*
* @version 2.0.0
*
* @package WordPress
* @subpackage Administration
*/
var wpNavMenu;
(function($) {
var api = wpNavMenu = {
options : {
menuItemDepthPerLevel : 30, // Do not use directly. Use depthToPx and pxToDepth instead.
globalMaxDepth : 11
},
menuList : undefined, // Set in init.
targetList : undefined, // Set in init.
menusChanged : false,
isRTL: !! ( 'undefined' != typeof isRtl && isRtl ),
negateIfRTL: ( 'undefined' != typeof isRtl && isRtl ) ? -1 : 1,
// Functions that run on init.
init : function() {
api.menuList = $('#menu-to-edit');
api.targetList = api.menuList;
this.jQueryExtensions();
this.attachMenuEditListeners();
this.setupInputWithDefaultTitle();
this.attachQuickSearchListeners();
this.attachThemeLocationsListeners();
this.attachTabsPanelListeners();
this.attachUnsavedChangesListener();
if( api.menuList.length ) // If no menu, we're in the + tab.
this.initSortables();
this.initToggles();
this.initTabManager();
},
jQueryExtensions : function() {
// jQuery extensions
$.fn.extend({
menuItemDepth : function() {
var margin = api.isRTL ? this.eq(0).css('margin-right') : this.eq(0).css('margin-left');
return api.pxToDepth( margin && -1 != margin.indexOf('px') ? margin.slice(0, -2) : 0 );
},
updateDepthClass : function(current, prev) {
return this.each(function(){
var t = $(this);
prev = prev || t.menuItemDepth();
$(this).removeClass('menu-item-depth-'+ prev )
.addClass('menu-item-depth-'+ current );
});
},
shiftDepthClass : function(change) {
return this.each(function(){
var t = $(this),
depth = t.menuItemDepth();
$(this).removeClass('menu-item-depth-'+ depth )
.addClass('menu-item-depth-'+ (depth + change) );
});
},
childMenuItems : function() {
var result = $();
this.each(function(){
var t = $(this), depth = t.menuItemDepth(), next = t.next();
while( next.length && next.menuItemDepth() > depth ) {
result = result.add( next );
next = next.next();
}
});
return result;
},
updateParentMenuItemDBId : function() {
return this.each(function(){
var item = $(this),
input = item.find('.menu-item-data-parent-id'),
depth = item.menuItemDepth(),
parent = item.prev();
if( depth == 0 ) { // Item is on the top level, has no parent
input.val(0);
} else { // Find the parent item, and retrieve its object id.
while( ! parent[0] || ! parent[0].className || -1 == parent[0].className.indexOf('menu-item') || ( parent.menuItemDepth() != depth - 1 ) )
parent = parent.prev();
input.val( parent.find('.menu-item-data-db-id').val() );
}
});
},
hideAdvancedMenuItemFields : function() {
return this.each(function(){
var that = $(this);
$('.hide-column-tog').not(':checked').each(function(){
that.find('.field-' + $(this).val() ).addClass('hidden-field');
});
});
},
/**
* Adds selected menu items to the menu.
*
* @param jQuery metabox The metabox jQuery object.
*/
addSelectedToMenu : function(processMethod) {
if ( 0 == $('#menu-to-edit').length ) {
return false;
}
return this.each(function() {
var t = $(this), menuItems = {},
checkboxes = t.find('.tabs-panel-active .categorychecklist li input:checked'),
re = new RegExp('menu-item\\[(\[^\\]\]*)');
processMethod = processMethod || api.addMenuItemToBottom;
// If no items are checked, bail.
if ( !checkboxes.length )
return false;
// Show the ajax spinner
t.find('img.waiting').show();
// Retrieve menu item data
$(checkboxes).each(function(){
var t = $(this),
listItemDBIDMatch = re.exec( t.attr('name') ),
listItemDBID = 'undefined' == typeof listItemDBIDMatch[1] ? 0 : parseInt(listItemDBIDMatch[1], 10);
if ( this.className && -1 != this.className.indexOf('add-to-top') )
processMethod = api.addMenuItemToTop;
menuItems[listItemDBID] = t.closest('li').getItemData( 'add-menu-item', listItemDBID );
});
// Add the items
api.addItemToMenu(menuItems, processMethod, function(){
// Deselect the items and hide the ajax spinner
checkboxes.removeAttr('checked');
t.find('img.waiting').hide();
});
});
},
getItemData : function( itemType, id ) {
itemType = itemType || 'menu-item';
var itemData = {}, i,
fields = [
'menu-item-db-id',
'menu-item-object-id',
'menu-item-object',
'menu-item-parent-id',
'menu-item-position',
'menu-item-type',
'menu-item-title',
'menu-item-url',
'menu-item-description',
'menu-item-attr-title',
'menu-item-target',
'menu-item-classes',
'menu-item-xfn'
];
if( !id && itemType == 'menu-item' ) {
id = this.find('.menu-item-data-db-id').val();
}
if( !id ) return itemData;
this.find('input').each(function() {
var field;
i = fields.length;
while ( i-- ) {
if( itemType == 'menu-item' )
field = fields[i] + '[' + id + ']';
else if( itemType == 'add-menu-item' )
field = 'menu-item[' + id + '][' + fields[i] + ']';
if (
this.name &&
field == this.name
) {
itemData[fields[i]] = this.value;
}
}
});
return itemData;
},
setItemData : function( itemData, itemType, id ) { // Can take a type, such as 'menu-item', or an id.
itemType = itemType || 'menu-item';
if( !id && itemType == 'menu-item' ) {
id = $('.menu-item-data-db-id', this).val();
}
if( !id ) return this;
this.find('input').each(function() {
var t = $(this), field;
$.each( itemData, function( attr, val ) {
if( itemType == 'menu-item' )
field = attr + '[' + id + ']';
else if( itemType == 'add-menu-item' )
field = 'menu-item[' + id + '][' + attr + ']';
if ( field == t.attr('name') ) {
t.val( val );
}
});
});
return this;
}
});
},
initToggles : function() {
// init postboxes
postboxes.add_postbox_toggles('nav-menus');
// adjust columns functions for menus UI
columns.useCheckboxesForHidden();
columns.checked = function(field) {
$('.field-' + field).removeClass('hidden-field');
}
columns.unchecked = function(field) {
$('.field-' + field).addClass('hidden-field');
}
// hide fields
api.menuList.hideAdvancedMenuItemFields();
},
initSortables : function() {
var currentDepth = 0, originalDepth, minDepth, maxDepth,
prev, next, prevBottom, nextThreshold, helperHeight, transport,
menuEdge = api.menuList.offset().left,
body = $('body'), maxChildDepth,
menuMaxDepth = initialMenuMaxDepth();
// Use the right edge if RTL.
menuEdge += api.isRTL ? api.menuList.width() : 0;
api.menuList.sortable({
handle: '.menu-item-handle',
placeholder: 'sortable-placeholder',
start: function(e, ui) {
var height, width, parent, children, tempHolder;
// handle placement for rtl orientation
if ( api.isRTL )
ui.item[0].style.right = 'auto';
transport = ui.item.children('.menu-item-transport');
// Set depths. currentDepth must be set before children are located.
originalDepth = ui.item.menuItemDepth();
updateCurrentDepth(ui, originalDepth);
// Attach child elements to parent
// Skip the placeholder
parent = ( ui.item.next()[0] == ui.placeholder[0] ) ? ui.item.next() : ui.item;
children = parent.childMenuItems();
transport.append( children );
// Update the height of the placeholder to match the moving item.
height = transport.outerHeight();
// If there are children, account for distance between top of children and parent
height += ( height > 0 ) ? (ui.placeholder.css('margin-top').slice(0, -2) * 1) : 0;
height += ui.helper.outerHeight();
helperHeight = height;
height -= 2; // Subtract 2 for borders
ui.placeholder.height(height);
// Update the width of the placeholder to match the moving item.
maxChildDepth = originalDepth;
children.each(function(){
var depth = $(this).menuItemDepth();
maxChildDepth = (depth > maxChildDepth) ? depth : maxChildDepth;
});
width = ui.helper.find('.menu-item-handle').outerWidth(); // Get original width
width += api.depthToPx(maxChildDepth - originalDepth); // Account for children
width -= 2; // Subtract 2 for borders
ui.placeholder.width(width);
// Update the list of menu items.
tempHolder = ui.placeholder.next();
tempHolder.css( 'margin-top', helperHeight + 'px' ); // Set the margin to absorb the placeholder
ui.placeholder.detach(); // detach or jQuery UI will think the placeholder is a menu item
$(this).sortable( "refresh" ); // The children aren't sortable. We should let jQ UI know.
ui.item.after( ui.placeholder ); // reattach the placeholder.
tempHolder.css('margin-top', 0); // reset the margin
// Now that the element is complete, we can update...
updateSharedVars(ui);
},
stop: function(e, ui) {
var children, depthChange = currentDepth - originalDepth;
// Return child elements to the list
children = transport.children().insertAfter(ui.item);
// Update depth classes
if( depthChange != 0 ) {
ui.item.updateDepthClass( currentDepth );
children.shiftDepthClass( depthChange );
updateMenuMaxDepth( depthChange );
}
// Register a change
api.registerChange();
// Update the item data.
ui.item.updateParentMenuItemDBId();
// address sortable's incorrectly-calculated top in opera
ui.item[0].style.top = 0;
// handle drop placement for rtl orientation
if ( api.isRTL ) {
ui.item[0].style.left = 'auto';
ui.item[0].style.right = 0;
}
// The width of the tab bar might have changed. Just in case.
api.refreshMenuTabs( true );
},
change: function(e, ui) {
// Make sure the placeholder is inside the menu.
// Otherwise fix it, or we're in trouble.
if( ! ui.placeholder.parent().hasClass('menu') )
(prev.length) ? prev.after( ui.placeholder ) : api.menuList.prepend( ui.placeholder );
updateSharedVars(ui);
},
sort: function(e, ui) {
var offset = ui.helper.offset(),
edge = api.isRTL ? offset.left + ui.helper.width() : offset.left,
depth = api.negateIfRTL * api.pxToDepth( edge - menuEdge );
// Check and correct if depth is not within range.
// Also, if the dragged element is dragged upwards over
// an item, shift the placeholder to a child position.
if ( depth > maxDepth || offset.top < prevBottom ) depth = maxDepth;
else if ( depth < minDepth ) depth = minDepth;
if( depth != currentDepth )
updateCurrentDepth(ui, depth);
// If we overlap the next element, manually shift downwards
if( nextThreshold && offset.top + helperHeight > nextThreshold ) {
next.after( ui.placeholder );
updateSharedVars( ui );
$(this).sortable( "refreshPositions" );
}
}
});
function updateSharedVars(ui) {
var depth;
prev = ui.placeholder.prev();
next = ui.placeholder.next();
// Make sure we don't select the moving item.
if( prev[0] == ui.item[0] ) prev = prev.prev();
if( next[0] == ui.item[0] ) next = next.next();
prevBottom = (prev.length) ? prev.offset().top + prev.height() : 0;
nextThreshold = (next.length) ? next.offset().top + next.height() / 3 : 0;
minDepth = (next.length) ? next.menuItemDepth() : 0;
if( prev.length )
maxDepth = ( (depth = prev.menuItemDepth() + 1) > api.options.globalMaxDepth ) ? api.options.globalMaxDepth : depth;
else
maxDepth = 0;
}
function updateCurrentDepth(ui, depth) {
ui.placeholder.updateDepthClass( depth, currentDepth );
currentDepth = depth;
}
function initialMenuMaxDepth() {
if( ! body[0].className ) return 0;
var match = body[0].className.match(/menu-max-depth-(\d+)/);
return match && match[1] ? parseInt(match[1]) : 0;
}
function updateMenuMaxDepth( depthChange ) {
var depth, newDepth = menuMaxDepth;
if ( depthChange === 0 ) {
return;
} else if ( depthChange > 0 ) {
depth = maxChildDepth + depthChange;
if( depth > menuMaxDepth )
newDepth = depth;
} else if ( depthChange < 0 && maxChildDepth == menuMaxDepth ) {
while( ! $('.menu-item-depth-' + newDepth, api.menuList).length && newDepth > 0 )
newDepth--;
}
// Update the depth class.
body.removeClass( 'menu-max-depth-' + menuMaxDepth ).addClass( 'menu-max-depth-' + newDepth );
menuMaxDepth = newDepth;
}
},
attachMenuEditListeners : function() {
var that = this;
$('#update-nav-menu').bind('click', function(e) {
if ( e.target && e.target.className ) {
if ( -1 != e.target.className.indexOf('item-edit') ) {
return that.eventOnClickEditLink(e.target);
} else if ( -1 != e.target.className.indexOf('menu-save') ) {
return that.eventOnClickMenuSave(e.target);
} else if ( -1 != e.target.className.indexOf('menu-delete') ) {
return that.eventOnClickMenuDelete(e.target);
} else if ( -1 != e.target.className.indexOf('item-delete') ) {
return that.eventOnClickMenuItemDelete(e.target);
} else if ( -1 != e.target.className.indexOf('item-cancel') ) {
return that.eventOnClickCancelLink(e.target);
}
}
});
$('#add-custom-links input[type="text"]').keypress(function(e){
if ( e.keyCode === 13 ) {
e.preventDefault();
$("#submit-customlinkdiv").click();
}
});
},
/**
* An interface for managing default values for input elements
* that is both JS and accessibility-friendly.
*
* Input elements that add the class 'input-with-default-title'
* will have their values set to the provided HTML title when empty.
*/
setupInputWithDefaultTitle : function() {
var name = 'input-with-default-title';
$('.' + name).each( function(){
var $t = $(this), title = $t.attr('title'), val = $t.val();
$t.data( name, title );
if( '' == val ) $t.val( title );
else if ( title == val ) return;
else $t.removeClass( name );
}).focus( function(){
var $t = $(this);
if( $t.val() == $t.data(name) )
$t.val('').removeClass( name );
}).blur( function(){
var $t = $(this);
if( '' == $t.val() )
$t.addClass( name ).val( $t.data(name) );
});
},
attachThemeLocationsListeners : function() {
var loc = $('#nav-menu-theme-locations'), params = {};
params['action'] = 'menu-locations-save';
params['menu-settings-column-nonce'] = $('#menu-settings-column-nonce').val();
loc.find('input[type="submit"]').click(function() {
loc.find('select').each(function() {
params[this.name] = $(this).val();
});
loc.find('.waiting').show();
$.post( ajaxurl, params, function(r) {
loc.find('.waiting').hide();
});
return false;
});
},
attachQuickSearchListeners : function() {
var searchTimer;
$('.quick-search').keypress(function(e){
var t = $(this);
if( 13 == e.which ) {
api.updateQuickSearchResults( t );
return false;
}
if( searchTimer ) clearTimeout(searchTimer);
searchTimer = setTimeout(function(){
api.updateQuickSearchResults( t );
}, 400);
}).attr('autocomplete','off');
},
updateQuickSearchResults : function(input) {
var panel, params,
minSearchLength = 2,
q = input.val();
if( q.length < minSearchLength ) return;
panel = input.parents('.tabs-panel');
params = {
'action': 'menu-quick-search',
'response-format': 'markup',
'menu': $('#menu').val(),
'menu-settings-column-nonce': $('#menu-settings-column-nonce').val(),
'q': q,
'type': input.attr('name')
};
$('img.waiting', panel).show();
$.post( ajaxurl, params, function(menuMarkup) {
api.processQuickSearchQueryResponse(menuMarkup, params, panel);
});
},
addCustomLink : function( processMethod ) {
var url = $('#custom-menu-item-url').val(),
label = $('#custom-menu-item-name').val();
processMethod = processMethod || api.addMenuItemToBottom;
if ( '' == url || 'http://' == url )
return false;
// Show the ajax spinner
$('.customlinkdiv img.waiting').show();
this.addLinkToMenu( url, label, processMethod, function() {
// Remove the ajax spinner
$('.customlinkdiv img.waiting').hide();
// Set custom link form back to defaults
$('#custom-menu-item-name').val('').blur();
$('#custom-menu-item-url').val('http://');
});
},
addLinkToMenu : function(url, label, processMethod, callback) {
processMethod = processMethod || api.addMenuItemToBottom;
callback = callback || function(){};
api.addItemToMenu({
'-1': {
'menu-item-type': 'custom',
'menu-item-url': url,
'menu-item-title': label
}
}, processMethod, callback);
},
addItemToMenu : function(menuItem, processMethod, callback) {
var menu = $('#menu').val(),
nonce = $('#menu-settings-column-nonce').val();
processMethod = processMethod || function(){};
callback = callback || function(){};
params = {
'action': 'add-menu-item',
'menu': menu,
'menu-settings-column-nonce': nonce,
'menu-item': menuItem
};
$.post( ajaxurl, params, function(menuMarkup) {
var ins = $('#menu-instructions');
processMethod(menuMarkup, params);
if( ! ins.hasClass('menu-instructions-inactive') && ins.siblings().length )
ins.addClass('menu-instructions-inactive');
callback();
});
},
/**
* Process the add menu item request response into menu list item.
*
* @param string menuMarkup The text server response of menu item markup.
* @param object req The request arguments.
*/
addMenuItemToBottom : function( menuMarkup, req ) {
$(menuMarkup).hideAdvancedMenuItemFields().appendTo( api.targetList );
},
addMenuItemToTop : function( menuMarkup, req ) {
$(menuMarkup).hideAdvancedMenuItemFields().prependTo( api.targetList );
},
attachUnsavedChangesListener : function() {
$('#menu-management input, #menu-management select, #menu-management, #menu-management textarea').change(function(){
api.registerChange();
});
if ( 0 != $('#menu-to-edit').length ) {
window.onbeforeunload = function(){
if ( api.menusChanged )
return navMenuL10n.saveAlert;
};
} else {
// Make the post boxes read-only, as they can't be used yet
$('#menu-settings-column').find('input,select').prop('disabled', true).end().find('a').attr('href', '#').unbind('click');
}
},
registerChange : function() {
api.menusChanged = true;
},
attachTabsPanelListeners : function() {
$('#menu-settings-column').bind('click', function(e) {
var selectAreaMatch, panelId, wrapper, items,
target = $(e.target);
if ( target.hasClass('nav-tab-link') ) {
panelId = /#(.*)$/.exec(e.target.href);
if ( panelId && panelId[1] )
panelId = panelId[1]
else
return false;
wrapper = target.parents('.inside').first();
// upon changing tabs, we want to uncheck all checkboxes
$('input', wrapper).removeAttr('checked');
$('.tabs-panel-active', wrapper).removeClass('tabs-panel-active').addClass('tabs-panel-inactive');
$('#' + panelId, wrapper).removeClass('tabs-panel-inactive').addClass('tabs-panel-active');
$('.tabs', wrapper).removeClass('tabs');
target.parent().addClass('tabs');
// select the search bar
$('.quick-search', wrapper).focus();
return false;
} else if ( target.hasClass('select-all') ) {
selectAreaMatch = /#(.*)$/.exec(e.target.href);
if ( selectAreaMatch && selectAreaMatch[1] ) {
items = $('#' + selectAreaMatch[1] + ' .tabs-panel-active .menu-item-title input');
if( items.length === items.filter(':checked').length )
items.removeAttr('checked');
else
items.prop('checked', true);
return false;
}
} else if ( target.hasClass('submit-add-to-menu') ) {
api.registerChange();
if ( e.target.id && 'submit-customlinkdiv' == e.target.id )
api.addCustomLink( api.addMenuItemToBottom );
else if ( e.target.id && -1 != e.target.id.indexOf('submit-') )
$('#' + e.target.id.replace(/submit-/, '')).addSelectedToMenu( api.addMenuItemToBottom );
return false;
} else if ( target.hasClass('page-numbers') ) {
$.post( ajaxurl, e.target.href.replace(/.*\?/, '').replace(/action=([^&]*)/, '') + '&action=menu-get-metabox',
function( resp ) {
if ( -1 == resp.indexOf('replace-id') )
return;
var metaBoxData = $.parseJSON(resp),
toReplace = document.getElementById(metaBoxData['replace-id']),
placeholder = document.createElement('div'),
wrap = document.createElement('div');
if ( ! metaBoxData['markup'] || ! toReplace )
return;
wrap.innerHTML = metaBoxData['markup'] ? metaBoxData['markup'] : '';
toReplace.parentNode.insertBefore( placeholder, toReplace );
placeholder.parentNode.removeChild( toReplace );
placeholder.parentNode.insertBefore( wrap, placeholder );
placeholder.parentNode.removeChild( placeholder );
}
);
return false;
}
});
},
initTabManager : function() {
var fixed = $('.nav-tabs-wrapper'),
fluid = fixed.children('.nav-tabs'),
active = fluid.children('.nav-tab-active'),
tabs = fluid.children('.nav-tab'),
tabsWidth = 0,
fixedRight, fixedLeft,
arrowLeft, arrowRight, resizeTimer, css = {},
marginFluid = api.isRTL ? 'margin-right' : 'margin-left',
marginFixed = api.isRTL ? 'margin-left' : 'margin-right',
msPerPx = 2;
/**
* Refreshes the menu tabs.
* Will show and hide arrows where necessary.
* Scrolls to the active tab by default.
*
* @param savePosition {boolean} Optional. Prevents scrolling so
* that the current position is maintained. Default false.
**/
api.refreshMenuTabs = function( savePosition ) {
var fixedWidth = fixed.width(),
margin = 0, css = {};
fixedLeft = fixed.offset().left;
fixedRight = fixedLeft + fixedWidth;
if( !savePosition )
active.makeTabVisible();
// Prevent space from building up next to the last tab if there's more to show
if( tabs.last().isTabVisible() ) {
margin = fixed.width() - tabsWidth;
margin = margin > 0 ? 0 : margin;
css[marginFluid] = margin + 'px';
fluid.animate( css, 100, "linear" );
}
// Show the arrows only when necessary
if( fixedWidth > tabsWidth )
arrowLeft.add( arrowRight ).hide();
else
arrowLeft.add( arrowRight ).show();
}
$.fn.extend({
makeTabVisible : function() {
var t = this.eq(0), left, right, css = {}, shift = 0;
if( ! t.length ) return this;
left = t.offset().left;
right = left + t.outerWidth();
if( right > fixedRight )
shift = fixedRight - right;
else if ( left < fixedLeft )
shift = fixedLeft - left;
if( ! shift ) return this;
css[marginFluid] = "+=" + api.negateIfRTL * shift + 'px';
fluid.animate( css, Math.abs( shift ) * msPerPx, "linear" );
return this;
},
isTabVisible : function() {
var t = this.eq(0),
left = t.offset().left,
right = left + t.outerWidth();
return ( right <= fixedRight && left >= fixedLeft ) ? true : false;
}
});
// Find the width of all tabs
tabs.each(function(){
tabsWidth += $(this).outerWidth(true);
});
// Set up fixed margin for overflow, unset padding
css['padding'] = 0;
css[marginFixed] = (-1 * tabsWidth) + 'px';
fluid.css( css );
// Build tab navigation
arrowLeft = $('<div class="nav-tabs-arrow nav-tabs-arrow-left"><a>&laquo;</a></div>');
arrowRight = $('<div class="nav-tabs-arrow nav-tabs-arrow-right"><a>&raquo;</a></div>');
// Attach to the document
fixed.wrap('<div class="nav-tabs-nav"/>').parent().prepend( arrowLeft ).append( arrowRight );
// Set the menu tabs
api.refreshMenuTabs();
// Make sure the tabs reset on resize
$(window).resize(function() {
if( resizeTimer ) clearTimeout(resizeTimer);
resizeTimer = setTimeout( api.refreshMenuTabs, 200);
});
// Build arrow functions
$.each([{
arrow : arrowLeft,
next : "next",
last : "first",
operator : "+="
},{
arrow : arrowRight,
next : "prev",
last : "last",
operator : "-="
}], function(){
var that = this;
this.arrow.mousedown(function(){
var marginFluidVal = Math.abs( parseInt( fluid.css(marginFluid) ) ),
shift = marginFluidVal,
css = {};
if( "-=" == that.operator )
shift = Math.abs( tabsWidth - fixed.width() ) - marginFluidVal;
if( ! shift ) return;
css[marginFluid] = that.operator + shift + 'px';
fluid.animate( css, shift * msPerPx, "linear" );
}).mouseup(function(){
var tab, next;
fluid.stop(true);
tab = tabs[that.last]();
while( (next = tab[that.next]()) && next.length && ! next.isTabVisible() ) {
tab = next;
}
tab.makeTabVisible();
});
});
},
eventOnClickEditLink : function(clickedEl) {
var settings, item,
matchedSection = /#(.*)$/.exec(clickedEl.href);
if ( matchedSection && matchedSection[1] ) {
settings = $('#'+matchedSection[1]);
item = settings.parent();
if( 0 != item.length ) {
if( item.hasClass('menu-item-edit-inactive') ) {
if( ! settings.data('menu-item-data') ) {
settings.data( 'menu-item-data', settings.getItemData() );
}
settings.slideDown('fast');
item.removeClass('menu-item-edit-inactive')
.addClass('menu-item-edit-active');
} else {
settings.slideUp('fast');
item.removeClass('menu-item-edit-active')
.addClass('menu-item-edit-inactive');
}
return false;
}
}
},
eventOnClickCancelLink : function(clickedEl) {
var settings = $(clickedEl).closest('.menu-item-settings');
settings.setItemData( settings.data('menu-item-data') );
return false;
},
eventOnClickMenuSave : function(clickedEl) {
var locs = '',
menuName = $('#menu-name'),
menuNameVal = menuName.val();
// Cancel and warn if invalid menu name
if( !menuNameVal || menuNameVal == menuName.attr('title') || !menuNameVal.replace(/\s+/, '') ) {
menuName.parent().addClass('form-invalid');
return false;
}
// Copy menu theme locations
$('#nav-menu-theme-locations select').each(function() {
locs += '<input type="hidden" name="' + this.name + '" value="' + $(this).val() + '" />';
});
$('#update-nav-menu').append( locs );
// Update menu item position data
api.menuList.find('.menu-item-data-position').val( function(index) { return index + 1; } );
window.onbeforeunload = null;
return true;
},
eventOnClickMenuDelete : function(clickedEl) {
// Delete warning AYS
if ( confirm( navMenuL10n.warnDeleteMenu ) ) {
window.onbeforeunload = null;
return true;
}
return false;
},
eventOnClickMenuItemDelete : function(clickedEl) {
var itemID = parseInt(clickedEl.id.replace('delete-', ''), 10);
api.removeMenuItem( $('#menu-item-' + itemID) );
api.registerChange();
return false;
},
/**
* Process the quick search response into a search result
*
* @param string resp The server response to the query.
* @param object req The request arguments.
* @param jQuery panel The tabs panel we're searching in.
*/
processQuickSearchQueryResponse : function(resp, req, panel) {
var matched, newID,
takenIDs = {},
form = document.getElementById('nav-menu-meta'),
pattern = new RegExp('menu-item\\[(\[^\\]\]*)', 'g'),
$items = $('<div>').html(resp).find('li'),
$item;
if( ! $items.length ) {
$('.categorychecklist', panel).html( '<li><p>' + navMenuL10n.noResultsFound + '</p></li>' );
$('img.waiting', panel).hide();
return;
}
$items.each(function(){
$item = $(this);
// make a unique DB ID number
matched = pattern.exec($item.html());
if ( matched && matched[1] ) {
newID = matched[1];
while( form.elements['menu-item[' + newID + '][menu-item-type]'] || takenIDs[ newID ] ) {
newID--;
}
takenIDs[newID] = true;
if ( newID != matched[1] ) {
$item.html( $item.html().replace(new RegExp(
'menu-item\\[' + matched[1] + '\\]', 'g'),
'menu-item[' + newID + ']'
) );
}
}
});
$('.categorychecklist', panel).html( $items );
$('img.waiting', panel).hide();
},
removeMenuItem : function(el) {
var children = el.childMenuItems();
el.addClass('deleting').animate({
opacity : 0,
height: 0
}, 350, function() {
var ins = $('#menu-instructions');
el.remove();
children.shiftDepthClass(-1).updateParentMenuItemDBId();
if( ! ins.siblings().length )
ins.removeClass('menu-instructions-inactive');
});
},
depthToPx : function(depth) {
return depth * api.options.menuItemDepthPerLevel;
},
pxToDepth : function(px) {
return Math.floor(px / api.options.menuItemDepthPerLevel);
}
};
$(document).ready(function(){ wpNavMenu.init(); });
})(jQuery);