src/cm/media/js/lib/yui/yui3.0.0/examples/node-focusmanager/assets/menubutton.js
changeset 0 40c8f766c9b8
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     1 YUI().use("*", function (Y) {
       
     2 
       
     3 	var menuButton = Y.one("#button-1"),
       
     4 		menu;
       
     5 
       
     6 
       
     7 	var initMenu = function () {
       
     8 
       
     9 		menu = new Y.Overlay({
       
    10 			contentBox: "#menu-1",
       
    11 			visible: false,
       
    12 			tabIndex: null
       
    13 		});
       
    14 
       
    15 		menu.render();
       
    16 
       
    17 
       
    18 		Y.one("#menu-1").setStyle("display", "");
       
    19 
       
    20 		var boundingBox = menu.get("boundingBox"),
       
    21 			contentBox = menu.get("contentBox");
       
    22 
       
    23 		boundingBox.addClass("yui-buttonmenu");
       
    24 		contentBox.addClass("yui-buttonmenu-content");
       
    25 
       
    26 
       
    27 		// Append a decorator element to the bounding box to render the shadow.
       
    28 
       
    29 		boundingBox.append('<div class="yui-menu-shadow"></div>');
       
    30 
       
    31 
       
    32 		//	Apply the ARIA roles, states and properties to the menu.
       
    33 
       
    34 		boundingBox.setAttrs({
       
    35 			role: "menu",
       
    36 			"aria-labelledby": menuButton.get("id")
       
    37 		});
       
    38 
       
    39 		boundingBox.all("input").set("role", "menuitem");
       
    40 
       
    41 
       
    42 		//	For NVDA: Add the role of "presentation" to each LI 
       
    43 		//	element to prevent NVDA from announcing the 
       
    44 		//	"listitem" role.
       
    45 
       
    46 		boundingBox.all("div,ul,li").set("role", "presentation");
       
    47 
       
    48 
       
    49 		//	Use the FocusManager Node Plugin to manage the focusability
       
    50 		//	of each menuitem in the menu.
       
    51 
       
    52 		contentBox.plug(Y.Plugin.NodeFocusManager, { 
       
    53 
       
    54 				descendants: "input",
       
    55 				keys: { next: "down:40", // Down arrow
       
    56 						previous: "down:38" },	// Up arrow
       
    57 				focusClass: {
       
    58 					className: "yui-menuitem-active",
       
    59 					fn: function (node) {
       
    60 						return node.get("parentNode");
       
    61 					}
       
    62 				},
       
    63 				circular: true
       
    64 
       
    65 			});
       
    66 
       
    67 
       
    68 		//	Subscribe to the change event for the "focused" attribute
       
    69 		//	to listen for when the menu initially gains focus, and 
       
    70 		//	when the menu has lost focus completely.
       
    71 
       
    72 		contentBox.focusManager.after("focusedChange", function (event) {
       
    73 
       
    74 			if (!event.newVal) {	// The menu has lost focus
       
    75 
       
    76 				//	Set the "activeDescendant" attribute to 0 when the 
       
    77 				//	menu is hidden so that the user can tab from the 
       
    78 				//	button to the first item in the menu the next time 
       
    79 				//	the menu is made visible.
       
    80 
       
    81 				this.set("activeDescendant", 0);
       
    82 
       
    83 			}
       
    84 
       
    85 		});
       
    86 
       
    87 
       
    88 		//	Hide the button's menu if the user presses the escape key
       
    89 		//	while focused either on the button or its menu.
       
    90 
       
    91 		Y.on("key", function () {
       
    92 
       
    93 			menu.hide();
       
    94 			menuButton.focus();				
       
    95 
       
    96 		}, [menuButton, boundingBox] ,"down:27");
       
    97 
       
    98 
       
    99 		if (Y.UA.ie === 6) {
       
   100 
       
   101 			//	Set the width and height of the menu's bounding box -  
       
   102 			//	this is necessary for IE 6 so that the CSS for the 
       
   103 			//	shadow element can simply set the shadow's width and 
       
   104 			//	height to 100% to ensure that dimensions of the shadow 
       
   105 			//	are always sync'd to the that of its parent menu.
       
   106 
       
   107 			menu.on("visibleChange", function (event) {
       
   108 
       
   109 				if (event.newVal) {
       
   110 
       
   111 					boundingBox.setStyles({ height: "", width: "" });
       
   112 
       
   113 					boundingBox.setStyles({ 
       
   114 						height: (boundingBox.get("offsetHeight") + "px"), 
       
   115 						width: (boundingBox.get("offsetWidth") + "px") });
       
   116 
       
   117 				}
       
   118 
       
   119 			});
       
   120 
       
   121 		}
       
   122 
       
   123 
       
   124 		menu.after("visibleChange", function (event) {
       
   125 
       
   126 			var bVisible = event.newVal;
       
   127 
       
   128 			//	Focus the first item when the menu is made visible
       
   129 			//	to allow users to navigate the menu via the keyboard
       
   130 
       
   131 			if (bVisible) {
       
   132 
       
   133 				//	Need to set focus via a timer for Webkit and Opera
       
   134 				Y.Lang.later(0, contentBox.focusManager, contentBox.focusManager.focus);
       
   135 
       
   136 			}
       
   137 
       
   138 			boundingBox.set("aria-hidden", (!bVisible));
       
   139 
       
   140 		});				
       
   141 
       
   142 
       
   143 		//	Hide the menu when one of menu items is clicked.
       
   144 
       
   145 		boundingBox.delegate("click", function (event) {
       
   146 
       
   147 			alert("You clicked " + this.query("input").get("value"));
       
   148 
       
   149 			contentBox.focusManager.blur();
       
   150 			menu.hide();
       
   151 
       
   152 		}, "li");
       
   153 
       
   154 
       
   155 		//	Focus each menuitem as the user moves the mouse over 
       
   156 		//	the menu.
       
   157 
       
   158 		boundingBox.delegate("mouseenter", function (event) {
       
   159 
       
   160 			var focusManager = contentBox.focusManager;
       
   161 
       
   162 			if (focusManager.get("focused")) {
       
   163 				focusManager.focus(this.query("input"));
       
   164 			}
       
   165 
       
   166 		}, "li");
       
   167 
       
   168 
       
   169 		//	Hide the menu if the user clicks outside of it or if the 
       
   170 		//	user doesn't click on the button
       
   171 
       
   172 		boundingBox.get("ownerDocument").on("mousedown", function (event) {
       
   173 
       
   174 			var oTarget = event.target;
       
   175 
       
   176 			if (!oTarget.compareTo(menuButton) && 
       
   177 				!menuButton.contains(oTarget) && 
       
   178 				!oTarget.compareTo(boundingBox) && 
       
   179 				!boundingBox.contains(oTarget)) {
       
   180 
       
   181 				menu.hide();
       
   182 
       
   183 			}
       
   184 
       
   185 		});
       
   186 
       
   187 	};
       
   188 
       
   189 
       
   190 	menuButton.addClass("yui-menubutton");
       
   191 
       
   192 
       
   193 	//	Hide the list until it is transformed into a menu
       
   194 
       
   195 	Y.one("#menu-1").setStyle("display", "none");
       
   196 
       
   197 
       
   198 	//	Remove the "yui-loading" class from the documentElement
       
   199 	//	now that the necessary YUI dependencies are loaded and the 
       
   200 	//	menu button has been skinned.
       
   201 
       
   202 	menuButton.get("ownerDocument").get("documentElement").removeClass("yui-loading");
       
   203 
       
   204 
       
   205 	//	Apply the ARIA roles, states and properties to the anchor.
       
   206 
       
   207 	menuButton.setAttrs({
       
   208 		role: "button",
       
   209 		"aria-haspopup": true
       
   210 	});
       
   211 
       
   212 
       
   213 	//	Remove the "href" attribute from the anchor element to  
       
   214 	//	prevent JAWS and NVDA from reading the value of the "href"
       
   215 	//	attribute when the anchor is focused.
       
   216 
       
   217 	if ((Y.UA.gecko || Y.UA.ie) && navigator.userAgent.indexOf("Windows") > -1) {
       
   218 
       
   219 		menuButton.removeAttribute("href");
       
   220 
       
   221 		//	Since the anchor's "href" attribute has been removed, the 
       
   222 		//	element will not fire the click event in Firefox when the 
       
   223 		//	user presses the enter key.  To fix this, dispatch the 
       
   224 		//	"click" event to the anchor when the user presses the 
       
   225 		//	enter key.
       
   226 
       
   227 		Y.on("key", function (event) {
       
   228 
       
   229 			menuButton.simulate("click");
       
   230 
       
   231 		}, menuButton, "down:13");
       
   232 
       
   233 	}
       
   234 
       
   235 
       
   236 	//	Set the "tabIndex" attribute of the anchor element to 0 to 
       
   237 	//	place it in the browser's default tab flow.  This is 
       
   238 	//	necessary since 1) anchor elements are not in the default 
       
   239 	//	tab flow in Opera and 2) removing the "href" attribute  
       
   240 	//	prevents the anchor from firing its "click" event 
       
   241 	//	in Firefox.
       
   242 
       
   243 	menuButton.set("tabIndex", 0);
       
   244 
       
   245 
       
   246 	var showMenu = function (event) {
       
   247 
       
   248 		//	For performance: Defer the creation of the menu until 
       
   249 		//	the first time the button is clicked.
       
   250 
       
   251 		if (!menu) {
       
   252 			initMenu();
       
   253 		}
       
   254 
       
   255 
       
   256 		if (!menu.get("visible")) {
       
   257 
       
   258 	        menu.set("align", {
       
   259 	            node: menuButton,
       
   260 	            points: [Y.WidgetPositionExt.TL, Y.WidgetPositionExt.BL]
       
   261 	        });
       
   262 
       
   263 			menu.show();
       
   264 
       
   265 		}
       
   266 
       
   267 		//	Prevent the anchor element from being focused 
       
   268 		//	when the users mouses down on it.
       
   269 		event.preventDefault();
       
   270 
       
   271 	}; 
       
   272 
       
   273 
       
   274 	//	Bind both a "mousedown" and "click" event listener to 
       
   275 	//	ensure the button's menu can be invoked using both the 
       
   276 	//	mouse and the keyboard.
       
   277 
       
   278 	menuButton.on("mousedown", showMenu);
       
   279 	menuButton.on("click", showMenu);
       
   280 	
       
   281 });