// SpryMenuBarKeyNavigationPlugin.js - version 0.5 - Spry Pre-Release 1.7

//

// Copyright (c) 2010. Adobe Systems Incorporated.

// All rights reserved.

//

// Redistribution and use in source and binary forms, with or without

// modification, are permitted provided that the following conditions are met:

//

//   * Redistributions of source code must retain the above copyright notice,

//     this list of conditions and the following disclaimer.

//   * Redistributions in binary form must reproduce the above copyright notice,

//     this list of conditions and the following disclaimer in the documentation

//     and/or other materials provided with the distribution.

//   * Neither the name of Adobe Systems Incorporated nor the names of its

//     contributors may be used to endorse or promote products derived from this

//     software without specific prior written permission.

//

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

// POSSIBILITY OF SUCH DAMAGE.



(function() { // BeginSpryComponent



if (typeof Spry == "undefined" || !Spry.Widget || !Spry.Widget.MenuBar2)

{

	alert("SpryMenuBarKeyNavigationPlugin.js requires SpryMenu.js!");

	return;

}



var KNP = Spry.Widget.MenuBar2.KeyNavigationPlugin = {

	config: {

		pluginOptionsProp:   "KNP",

		horizontalLayoutMap: { MenuBar: true }

	},



	initialize: function(mb)

	{

		var opts = mb.setOptions({}, KNP.config);



		if (mb[opts.pluginOptionsProp])

			mb.setOptions(opts, mb[opts.pluginOptionsProp]);



		mb[opts.pluginOptionsProp] = opts;



		mb.addObserver(this);

	},



	KEY_TAB:    9,

	KEY_ESC:   27,

	KEY_UP:    38,

	KEY_DOWN:  40,

	KEY_LEFT:  37,

	KEY_RIGHT: 39,

	KEY_SPACE: 32,



	getOptions: function(mb)

	{

		return mb[KNP.config.pluginOptionsProp];

	},



	bindEventCBFunc: function(cbName, mb, mi)

	{

		return function(e) { return KNP[cbName](e, mb, mi); };

	},



	getIndexOf: function(arr, item)

	{

		if (arr && arr.length)

		{

			for (var i = 0; i < arr.length; i++)

			{

				if (arr[i] == item)

					return i;

			}

		}

		return -1;

	},



	menuIsHorizontal: function(mb, m)

	{

		var menuLevel = mb.getMenuLevel(m);

		var cname = menuLevel ? "MenuLevel" + menuLevel : "MenuBar";

		return KNP.getOptions(mb).horizontalLayoutMap[cname] ? true : false;

	},



	goToMenuItemByOffset: function(mb, mi, offset)

	{

		var menu = mb.getParentMenuForElement(mi, true);

		if (menu)

		{

			var mItems = mb.getMenuItemsForMenu(menu);

			if (mItems.length)

			{

				var miIndex = KNP.getIndexOf(mItems, mi);

				if (miIndex >= 0)

				{

				 	miIndex += offset;

					if (miIndex >= 0 && miIndex < mItems.length)

					{

						mi = mItems[miIndex];

						KNP.setCurrentMenuItem(mb, mi);

					}

				}

			}

		}

		return false;

	},



	goToNextMenuItem: function(mb, mi) { return KNP.goToMenuItemByOffset(mb, mi, 1); },

	goToPreviousMenuItem: function(mb, mi) { return KNP.goToMenuItemByOffset(mb, mi, -1); },



	openMenuItemSubMenu: function(mb, mi)

	{

		var subMenu = mb.getSubMenuForMenuItem(mi);

		if (subMenu)

		{

			var subMI = mb.getMenuItemsForMenu(subMenu)[0];

			if (subMI)

				KNP.setCurrentMenuItem(mb, subMI);

		}

	},

	

	closeParentMenu: function(mb, mi)

	{

		var menu = mb.getParentMenuForElement(mi, true);

		if (menu)

		{

			var parentMI = mb.getMenuItemForSubMenu(menu);

			var parentMenu = mb.getParentMenuForElement(menu);

			if (parentMI)

				KNP.setCurrentMenuItem(mb, parentMI);

		}

	},



	setCurrentMenuItem: function(mb, mi)

	{

		var cmi = mb.currentMenuItem;

		if (cmi && cmi == mi)

			return;



		mb.setCurrentMenuItem(mi, true);



		if (cmi)

			mb.hideSubMenu(mb.getParentMenuForElement(cmi), mb.getParentMenuForElement(mi));



		if (mi.focus)

			mi.focus();

	},



	handleKeyDown: function(evt, mb, mi)

	{

		if (mi != mb.currentMenuItem)

			return;



		var menu = mb.getParentMenuForElement(mi, true);

		var isHorizontal = KNP.menuIsHorizontal(mb, menu);

		var result = undefined;



		switch (evt.keyCode)

		{

			case KNP.KEY_TAB:

			case KNP.KEY_ESC:

				mb.setCurrentMenuItem(null, true);

				mb.hideSubMenu(mb.getParentMenuForElement(mi));	

				if (mi.blur)

					mi.blur();

				if (evt.keyCode != KNP.KEY_TAB)

					result = false;

				break;

			case KNP.KEY_RIGHT:

				if (isHorizontal)

					KNP.goToNextMenuItem(mb, mi);

				else

					KNP.openMenuItemSubMenu(mb, mi);

				result = false;

				break;

			case KNP.KEY_LEFT:

				if (isHorizontal)

					KNP.goToPreviousMenuItem(mb, mi);

				else

					KNP.closeParentMenu(mb, mi);

				result = false;

				break;

			case KNP.KEY_UP:

				if (isHorizontal)

					KNP.closeParentMenu(mb, mi);

				else

					KNP.goToPreviousMenuItem(mb, mi);

				result = false;

				break;

			case KNP.KEY_DOWN:

				if (isHorizontal)

					KNP.openMenuItemSubMenu(mb, mi);

				else

					KNP.goToNextMenuItem(mb, mi);

				result = false;

				break;

			case KNP.KEY_SPACE:

				KNP.openMenuItemSubMenu(mb, mi);

				result = false;

				break;

		}



		return result;

	},



	handleFocus: function(evt, mb, mi)

	{

		if (!mb.currentMenuItem)

			mb.setCurrentMenuItem(mi, true);

	},



	onPostTransformMarkup: function(mb, evt)

	{

		var links = Spry.$$("." + mb.menuItemClass, mb.element);

		if (links.length)

		{

			for (var i = 0; i < links.length; i++)

			{

				var l = links[i];

				l.tabIndex = i ? "-1" : "0";

				mb.addEventListener(l, "keydown", KNP.bindEventCBFunc("handleKeyDown", mb, l), false);

				mb.addEventListener(l, "focus", KNP.bindEventCBFunc("handleFocus", mb, l), false);

			}

		}

	}

};



// We want to add our plugin to the default configuration for MenuBar2 if it is included!



Spry.Widget.MenuBar2.config.plugIns.push(Spry.Widget.MenuBar2.KeyNavigationPlugin);



})(); // EndSpryComponent
