| 1 | // SpryMenuBar.js - version 0.7 - Spry Pre-Release 1.6 |
|---|
| 2 | // |
|---|
| 3 | // Copyright (c) 2006. Adobe Systems Incorporated. |
|---|
| 4 | // All rights reserved. |
|---|
| 5 | // |
|---|
| 6 | // Redistribution and use in source and binary forms, with or without |
|---|
| 7 | // modification, are permitted provided that the following conditions are met: |
|---|
| 8 | // |
|---|
| 9 | // * Redistributions of source code must retain the above copyright notice, |
|---|
| 10 | // this list of conditions and the following disclaimer. |
|---|
| 11 | // * Redistributions in binary form must reproduce the above copyright notice, |
|---|
| 12 | // this list of conditions and the following disclaimer in the documentation |
|---|
| 13 | // and/or other materials provided with the distribution. |
|---|
| 14 | // * Neither the name of Adobe Systems Incorporated nor the names of its |
|---|
| 15 | // contributors may be used to endorse or promote products derived from this |
|---|
| 16 | // software without specific prior written permission. |
|---|
| 17 | // |
|---|
| 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|---|
| 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|---|
| 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|---|
| 21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|---|
| 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|---|
| 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|---|
| 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|---|
| 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|---|
| 26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|---|
| 27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|---|
| 28 | // POSSIBILITY OF SUCH DAMAGE. |
|---|
| 29 | |
|---|
| 30 | /******************************************************************************* |
|---|
| 31 | |
|---|
| 32 | SpryMenuBar.js |
|---|
| 33 | This file handles the JavaScript for Spry Menu Bar. You should have no need |
|---|
| 34 | to edit this file. Some highlights of the MenuBar object is that timers are |
|---|
| 35 | used to keep submenus from showing up until the user has hovered over the parent |
|---|
| 36 | menu item for some time, as well as a timer for when they leave a submenu to keep |
|---|
| 37 | showing that submenu until the timer fires. |
|---|
| 38 | |
|---|
| 39 | *******************************************************************************/ |
|---|
| 40 | |
|---|
| 41 | var Spry; if (!Spry) Spry = {}; if (!Spry.Widget) Spry.Widget = {}; |
|---|
| 42 | |
|---|
| 43 | Spry.BrowserSniff = function() |
|---|
| 44 | { |
|---|
| 45 | var b = navigator.appName.toString(); |
|---|
| 46 | var up = navigator.platform.toString(); |
|---|
| 47 | var ua = navigator.userAgent.toString(); |
|---|
| 48 | |
|---|
| 49 | this.mozilla = this.ie = this.opera = r = false; |
|---|
| 50 | var re_opera = /Opera.([0-9\.]*)/i; |
|---|
| 51 | var re_msie = /MSIE.([0-9\.]*)/i; |
|---|
| 52 | var re_gecko = /gecko/i; |
|---|
| 53 | var re_safari = /safari\/([\d\.]*)/i; |
|---|
| 54 | |
|---|
| 55 | if (ua.match(re_opera)) { |
|---|
| 56 | r = ua.match(re_opera); |
|---|
| 57 | this.opera = true; |
|---|
| 58 | this.version = parseFloat(r[1]); |
|---|
| 59 | } else if (ua.match(re_msie)) { |
|---|
| 60 | r = ua.match(re_msie); |
|---|
| 61 | this.ie = true; |
|---|
| 62 | this.version = parseFloat(r[1]); |
|---|
| 63 | } else if (ua.match(re_safari)) { |
|---|
| 64 | this.safari = true; |
|---|
| 65 | this.version = 1.4; |
|---|
| 66 | } else if (ua.match(re_gecko)) { |
|---|
| 67 | var re_gecko_version = /rv:\s*([0-9\.]+)/i; |
|---|
| 68 | r = ua.match(re_gecko_version); |
|---|
| 69 | this.mozilla = true; |
|---|
| 70 | this.version = parseFloat(r[1]); |
|---|
| 71 | } |
|---|
| 72 | this.windows = this.mac = this.linux = false; |
|---|
| 73 | |
|---|
| 74 | this.Platform = ua.match(/windows/i) ? "windows" : |
|---|
| 75 | (ua.match(/linux/i) ? "linux" : |
|---|
| 76 | (ua.match(/mac/i) ? "mac" : |
|---|
| 77 | ua.match(/unix/i)? "unix" : "unknown")); |
|---|
| 78 | this[this.Platform] = true; |
|---|
| 79 | this.v = this.version; |
|---|
| 80 | |
|---|
| 81 | if (this.safari && this.mac && this.mozilla) { |
|---|
| 82 | this.mozilla = false; |
|---|
| 83 | } |
|---|
| 84 | }; |
|---|
| 85 | |
|---|
| 86 | Spry.is = new Spry.BrowserSniff(); |
|---|
| 87 | |
|---|
| 88 | // Constructor for Menu Bar |
|---|
| 89 | // element should be an ID of an unordered list (<ul> tag) |
|---|
| 90 | // preloadImage1 and preloadImage2 are images for the rollover state of a menu |
|---|
| 91 | Spry.Widget.MenuBar = function(element, opts) |
|---|
| 92 | { |
|---|
| 93 | this.init(element, opts); |
|---|
| 94 | }; |
|---|
| 95 | |
|---|
| 96 | Spry.Widget.MenuBar.prototype.init = function(element, opts) |
|---|
| 97 | { |
|---|
| 98 | this.element = this.getElement(element); |
|---|
| 99 | |
|---|
| 100 | // represents the current (sub)menu we are operating on |
|---|
| 101 | this.currMenu = null; |
|---|
| 102 | this.showDelay = 250; |
|---|
| 103 | this.hideDelay = 600; |
|---|
| 104 | if(typeof document.getElementById == 'undefined' || (navigator.vendor == 'Apple Computer, Inc.' && typeof window.XMLHttpRequest == 'undefined') || (Spry.is.ie && typeof document.uniqueID == 'undefined')) |
|---|
| 105 | { |
|---|
| 106 | // bail on older unsupported browsers |
|---|
| 107 | return; |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | // Fix IE6 CSS images flicker |
|---|
| 111 | if (Spry.is.ie && Spry.is.version < 7){ |
|---|
| 112 | try { |
|---|
| 113 | document.execCommand("BackgroundImageCache", false, true); |
|---|
| 114 | } catch(err) {} |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | this.upKeyCode = Spry.Widget.MenuBar.KEY_UP; |
|---|
| 118 | this.downKeyCode = Spry.Widget.MenuBar.KEY_DOWN; |
|---|
| 119 | this.leftKeyCode = Spry.Widget.MenuBar.KEY_LEFT; |
|---|
| 120 | this.rightKeyCode = Spry.Widget.MenuBar.KEY_RIGHT; |
|---|
| 121 | this.escKeyCode = Spry.Widget.MenuBar.KEY_ESC; |
|---|
| 122 | |
|---|
| 123 | this.hoverClass = 'MenuBarItemHover'; |
|---|
| 124 | this.subHoverClass = 'MenuBarItemSubmenuHover'; |
|---|
| 125 | this.subVisibleClass ='MenuBarSubmenuVisible'; |
|---|
| 126 | this.hasSubClass = 'MenuBarItemSubmenu'; |
|---|
| 127 | this.activeClass = 'MenuBarActive'; |
|---|
| 128 | this.isieClass = 'MenuBarItemIE'; |
|---|
| 129 | this.verticalClass = 'MenuBarVertical'; |
|---|
| 130 | this.horizontalClass = 'MenuBarHorizontal'; |
|---|
| 131 | this.enableKeyboardNavigation = true; |
|---|
| 132 | |
|---|
| 133 | this.hasFocus = false; |
|---|
| 134 | // load hover images now |
|---|
| 135 | if(opts) |
|---|
| 136 | { |
|---|
| 137 | for(var k in opts) |
|---|
| 138 | { |
|---|
| 139 | if (typeof this[k] == 'undefined') |
|---|
| 140 | { |
|---|
| 141 | var rollover = new Image; |
|---|
| 142 | rollover.src = opts[k]; |
|---|
| 143 | } |
|---|
| 144 | } |
|---|
| 145 | Spry.Widget.MenuBar.setOptions(this, opts); |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | // safari doesn't support tabindex |
|---|
| 149 | if (Spry.is.safari) |
|---|
| 150 | this.enableKeyboardNavigation = false; |
|---|
| 151 | |
|---|
| 152 | if(this.element) |
|---|
| 153 | { |
|---|
| 154 | this.currMenu = this.element; |
|---|
| 155 | var items = this.element.getElementsByTagName('li'); |
|---|
| 156 | for(var i=0; i<items.length; i++) |
|---|
| 157 | { |
|---|
| 158 | if (i > 0 && this.enableKeyboardNavigation) |
|---|
| 159 | items[i].getElementsByTagName('a')[0].tabIndex='-1'; |
|---|
| 160 | |
|---|
| 161 | this.initialize(items[i], element); |
|---|
| 162 | if(Spry.is.ie) |
|---|
| 163 | { |
|---|
| 164 | this.addClassName(items[i], this.isieClass); |
|---|
| 165 | items[i].style.position = "static"; |
|---|
| 166 | } |
|---|
| 167 | } |
|---|
| 168 | if (this.enableKeyboardNavigation) |
|---|
| 169 | { |
|---|
| 170 | var self = this; |
|---|
| 171 | this.addEventListener(document, 'keydown', function(e){self.keyDown(e); }, false); |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | if(Spry.is.ie) |
|---|
| 175 | { |
|---|
| 176 | if(this.hasClassName(this.element, this.verticalClass)) |
|---|
| 177 | { |
|---|
| 178 | this.element.style.position = "relative"; |
|---|
| 179 | } |
|---|
| 180 | var linkitems = this.element.getElementsByTagName('a'); |
|---|
| 181 | for(var i=0; i<linkitems.length; i++) |
|---|
| 182 | { |
|---|
| 183 | linkitems[i].style.position = "relative"; |
|---|
| 184 | } |
|---|
| 185 | } |
|---|
| 186 | } |
|---|
| 187 | }; |
|---|
| 188 | Spry.Widget.MenuBar.KEY_ESC = 27; |
|---|
| 189 | Spry.Widget.MenuBar.KEY_UP = 38; |
|---|
| 190 | Spry.Widget.MenuBar.KEY_DOWN = 40; |
|---|
| 191 | Spry.Widget.MenuBar.KEY_LEFT = 37; |
|---|
| 192 | Spry.Widget.MenuBar.KEY_RIGHT = 39; |
|---|
| 193 | |
|---|
| 194 | Spry.Widget.MenuBar.prototype.getElement = function(ele) |
|---|
| 195 | { |
|---|
| 196 | if (ele && typeof ele == "string") |
|---|
| 197 | return document.getElementById(ele); |
|---|
| 198 | return ele; |
|---|
| 199 | }; |
|---|
| 200 | |
|---|
| 201 | Spry.Widget.MenuBar.prototype.hasClassName = function(ele, className) |
|---|
| 202 | { |
|---|
| 203 | if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1) |
|---|
| 204 | { |
|---|
| 205 | return false; |
|---|
| 206 | } |
|---|
| 207 | return true; |
|---|
| 208 | }; |
|---|
| 209 | |
|---|
| 210 | Spry.Widget.MenuBar.prototype.addClassName = function(ele, className) |
|---|
| 211 | { |
|---|
| 212 | if (!ele || !className || this.hasClassName(ele, className)) |
|---|
| 213 | return; |
|---|
| 214 | ele.className += (ele.className ? " " : "") + className; |
|---|
| 215 | }; |
|---|
| 216 | |
|---|
| 217 | Spry.Widget.MenuBar.prototype.removeClassName = function(ele, className) |
|---|
| 218 | { |
|---|
| 219 | if (!ele || !className || !this.hasClassName(ele, className)) |
|---|
| 220 | return; |
|---|
| 221 | ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), ""); |
|---|
| 222 | }; |
|---|
| 223 | |
|---|
| 224 | // addEventListener for Menu Bar |
|---|
| 225 | // attach an event to a tag without creating obtrusive HTML code |
|---|
| 226 | Spry.Widget.MenuBar.prototype.addEventListener = function(element, eventType, handler, capture) |
|---|
| 227 | { |
|---|
| 228 | try |
|---|
| 229 | { |
|---|
| 230 | if (element.addEventListener) |
|---|
| 231 | { |
|---|
| 232 | element.addEventListener(eventType, handler, capture); |
|---|
| 233 | } |
|---|
| 234 | else if (element.attachEvent) |
|---|
| 235 | { |
|---|
| 236 | element.attachEvent('on' + eventType, handler); |
|---|
| 237 | } |
|---|
| 238 | } |
|---|
| 239 | catch (e) {} |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | // createIframeLayer for Menu Bar |
|---|
| 243 | // creates an IFRAME underneath a menu so that it will show above form controls and ActiveX |
|---|
| 244 | Spry.Widget.MenuBar.prototype.createIframeLayer = function(menu) |
|---|
| 245 | { |
|---|
| 246 | var layer = document.createElement('iframe'); |
|---|
| 247 | layer.tabIndex = '-1'; |
|---|
| 248 | layer.src = 'javascript:""'; |
|---|
| 249 | layer.frameBorder = '0'; |
|---|
| 250 | layer.scrolling = 'no'; |
|---|
| 251 | menu.parentNode.appendChild(layer); |
|---|
| 252 | |
|---|
| 253 | layer.style.left = menu.offsetLeft + 'px'; |
|---|
| 254 | layer.style.top = menu.offsetTop + 'px'; |
|---|
| 255 | layer.style.width = menu.offsetWidth + 'px'; |
|---|
| 256 | layer.style.height = menu.offsetHeight + 'px'; |
|---|
| 257 | }; |
|---|
| 258 | |
|---|
| 259 | // removeIframeLayer for Menu Bar |
|---|
| 260 | // removes an IFRAME underneath a menu to reveal any form controls and ActiveX |
|---|
| 261 | Spry.Widget.MenuBar.prototype.removeIframeLayer = function(menu) |
|---|
| 262 | { |
|---|
| 263 | var layers = menu.parentNode.getElementsByTagName('iframe'); |
|---|
| 264 | while(layers.length > 0) |
|---|
| 265 | { |
|---|
| 266 | layers[0].parentNode.removeChild(layers[0]); |
|---|
| 267 | } |
|---|
| 268 | }; |
|---|
| 269 | |
|---|
| 270 | // clearMenus for Menu Bar |
|---|
| 271 | // root is the top level unordered list (<ul> tag) |
|---|
| 272 | Spry.Widget.MenuBar.prototype.clearMenus = function(root) |
|---|
| 273 | { |
|---|
| 274 | var menus = root.getElementsByTagName('ul'); |
|---|
| 275 | for(var i=0; i<menus.length; i++) |
|---|
| 276 | this.hideSubmenu(menus[i]); |
|---|
| 277 | |
|---|
| 278 | this.removeClassName(this.element, this.activeClass); |
|---|
| 279 | }; |
|---|
| 280 | |
|---|
| 281 | // bubbledTextEvent for Menu Bar |
|---|
| 282 | // identify bubbled up text events in Safari so we can ignore them |
|---|
| 283 | Spry.Widget.MenuBar.prototype.bubbledTextEvent = function() |
|---|
| 284 | { |
|---|
| 285 | return Spry.is.safari && (event.target == event.relatedTarget.parentNode || (event.eventPhase == 3 && event.target.parentNode == event.relatedTarget)); |
|---|
| 286 | }; |
|---|
| 287 | |
|---|
| 288 | // showSubmenu for Menu Bar |
|---|
| 289 | // set the proper CSS class on this menu to show it |
|---|
| 290 | Spry.Widget.MenuBar.prototype.showSubmenu = function(menu) |
|---|
| 291 | { |
|---|
| 292 | if(this.currMenu) |
|---|
| 293 | { |
|---|
| 294 | this.clearMenus(this.currMenu); |
|---|
| 295 | this.currMenu = null; |
|---|
| 296 | } |
|---|
| 297 | |
|---|
| 298 | if(menu) |
|---|
| 299 | { |
|---|
| 300 | this.addClassName(menu, this.subVisibleClass); |
|---|
| 301 | if(typeof document.all != 'undefined' && !Spry.is.opera && navigator.vendor != 'KDE') |
|---|
| 302 | { |
|---|
| 303 | if(!this.hasClassName(this.element, this.horizontalClass) || menu.parentNode.parentNode != this.element) |
|---|
| 304 | { |
|---|
| 305 | menu.style.top = menu.parentNode.offsetTop + 'px'; |
|---|
| 306 | } |
|---|
| 307 | } |
|---|
| 308 | if(Spry.is.ie && Spry.is.version < 7) |
|---|
| 309 | { |
|---|
| 310 | this.createIframeLayer(menu); |
|---|
| 311 | } |
|---|
| 312 | } |
|---|
| 313 | this.addClassName(this.element, this.activeClass); |
|---|
| 314 | }; |
|---|
| 315 | |
|---|
| 316 | // hideSubmenu for Menu Bar |
|---|
| 317 | // remove the proper CSS class on this menu to hide it |
|---|
| 318 | Spry.Widget.MenuBar.prototype.hideSubmenu = function(menu) |
|---|
| 319 | { |
|---|
| 320 | if(menu) |
|---|
| 321 | { |
|---|
| 322 | this.removeClassName(menu, this.subVisibleClass); |
|---|
| 323 | if(typeof document.all != 'undefined' && !Spry.is.opera && navigator.vendor != 'KDE') |
|---|
| 324 | { |
|---|
| 325 | menu.style.top = ''; |
|---|
| 326 | menu.style.left = ''; |
|---|
| 327 | } |
|---|
| 328 | this.removeIframeLayer(menu); |
|---|
| 329 | } |
|---|
| 330 | }; |
|---|
| 331 | |
|---|
| 332 | // initialize for Menu Bar |
|---|
| 333 | // create event listeners for the Menu Bar widget so we can properly |
|---|
| 334 | // show and hide submenus |
|---|
| 335 | Spry.Widget.MenuBar.prototype.initialize = function(listitem, element) |
|---|
| 336 | { |
|---|
| 337 | var opentime, closetime; |
|---|
| 338 | var link = listitem.getElementsByTagName('a')[0]; |
|---|
| 339 | var submenus = listitem.getElementsByTagName('ul'); |
|---|
| 340 | var menu = (submenus.length > 0 ? submenus[0] : null); |
|---|
| 341 | |
|---|
| 342 | if(menu) |
|---|
| 343 | this.addClassName(link, this.hasSubClass); |
|---|
| 344 | |
|---|
| 345 | if(!Spry.is.ie) |
|---|
| 346 | { |
|---|
| 347 | // define a simple function that comes standard in IE to determine |
|---|
| 348 | // if a node is within another node |
|---|
| 349 | listitem.contains = function(testNode) |
|---|
| 350 | { |
|---|
| 351 | // this refers to the list item |
|---|
| 352 | if(testNode == null) |
|---|
| 353 | return false; |
|---|
| 354 | |
|---|
| 355 | if(testNode == this) |
|---|
| 356 | return true; |
|---|
| 357 | else |
|---|
| 358 | return this.contains(testNode.parentNode); |
|---|
| 359 | }; |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | // need to save this for scope further down |
|---|
| 363 | var self = this; |
|---|
| 364 | this.addEventListener(listitem, 'mouseover', function(e){self.mouseOver(listitem, e);}, false); |
|---|
| 365 | this.addEventListener(listitem, 'mouseout', function(e){if (self.enableKeyboardNavigation) self.clearSelection(); self.mouseOut(listitem, e);}, false); |
|---|
| 366 | |
|---|
| 367 | if (this.enableKeyboardNavigation) |
|---|
| 368 | { |
|---|
| 369 | this.addEventListener(link, 'blur', function(e){self.onBlur(listitem);}, false); |
|---|
| 370 | this.addEventListener(link, 'focus', function(e){self.keyFocus(listitem, e);}, false); |
|---|
| 371 | } |
|---|
| 372 | }; |
|---|
| 373 | Spry.Widget.MenuBar.prototype.keyFocus = function (listitem, e) |
|---|
| 374 | { |
|---|
| 375 | this.lastOpen = listitem.getElementsByTagName('a')[0]; |
|---|
| 376 | this.addClassName(this.lastOpen, listitem.getElementsByTagName('ul').length > 0 ? this.subHoverClass : this.hoverClass); |
|---|
| 377 | this.hasFocus = true; |
|---|
| 378 | }; |
|---|
| 379 | Spry.Widget.MenuBar.prototype.onBlur = function (listitem) |
|---|
| 380 | { |
|---|
| 381 | this.clearSelection(listitem); |
|---|
| 382 | }; |
|---|
| 383 | Spry.Widget.MenuBar.prototype.clearSelection = function(el){ |
|---|
| 384 | //search any intersection with the current open element |
|---|
| 385 | if (!this.lastOpen) |
|---|
| 386 | return; |
|---|
| 387 | |
|---|
| 388 | if (el) |
|---|
| 389 | { |
|---|
| 390 | el = el.getElementsByTagName('a')[0]; |
|---|
| 391 | |
|---|
| 392 | // check children |
|---|
| 393 | var item = this.lastOpen; |
|---|
| 394 | while (item != this.element) |
|---|
| 395 | { |
|---|
| 396 | var tmp = el; |
|---|
| 397 | while (tmp != this.element) |
|---|
| 398 | { |
|---|
| 399 | if (tmp == item) |
|---|
| 400 | return; |
|---|
| 401 | try{ |
|---|
| 402 | tmp = tmp.parentNode; |
|---|
| 403 | }catch(err){break;} |
|---|
| 404 | } |
|---|
| 405 | item = item.parentNode; |
|---|
| 406 | } |
|---|
| 407 | } |
|---|
| 408 | var item = this.lastOpen; |
|---|
| 409 | while (item != this.element) |
|---|
| 410 | { |
|---|
| 411 | this.hideSubmenu(item.parentNode); |
|---|
| 412 | var link = item.getElementsByTagName('a')[0]; |
|---|
| 413 | this.removeClassName(link, this.hoverClass); |
|---|
| 414 | this.removeClassName(link, this.subHoverClass); |
|---|
| 415 | item = item.parentNode; |
|---|
| 416 | } |
|---|
| 417 | this.lastOpen = false; |
|---|
| 418 | }; |
|---|
| 419 | Spry.Widget.MenuBar.prototype.keyDown = function (e) |
|---|
| 420 | { |
|---|
| 421 | if (!this.hasFocus) |
|---|
| 422 | return; |
|---|
| 423 | |
|---|
| 424 | if (!this.lastOpen) |
|---|
| 425 | { |
|---|
| 426 | this.hasFocus = false; |
|---|
| 427 | return; |
|---|
| 428 | } |
|---|
| 429 | |
|---|
| 430 | var e = e|| event; |
|---|
| 431 | var listitem = this.lastOpen.parentNode; |
|---|
| 432 | var link = this.lastOpen; |
|---|
| 433 | var submenus = listitem.getElementsByTagName('ul'); |
|---|
| 434 | var menu = (submenus.length > 0 ? submenus[0] : null); |
|---|
| 435 | var hasSubMenu = (menu) ? true : false; |
|---|
| 436 | |
|---|
| 437 | Spry.Widget.MenuBar.stopPropagation(e); |
|---|
| 438 | |
|---|
| 439 | var opts = [listitem, menu, null, this.getSibling(listitem, 'previousSibling'), this.getSibling(listitem, 'nextSibling')]; |
|---|
| 440 | |
|---|
| 441 | if (!opts[3]) |
|---|
| 442 | opts[2] = (listitem.parentNode.parentNode.nodeName.toLowerCase() == 'li')?listitem.parentNode.parentNode:null; |
|---|
| 443 | |
|---|
| 444 | |
|---|
| 445 | var found = 0; |
|---|
| 446 | switch (e.keyCode){ |
|---|
| 447 | case this.upKeyCode: |
|---|
| 448 | found = this.getElementForKey(opts, 'y', 1); |
|---|
| 449 | break; |
|---|
| 450 | case this.downKeyCode: |
|---|
| 451 | found = this.getElementForKey(opts, 'y', -1); |
|---|
| 452 | break; |
|---|
| 453 | case this.leftKeyCode: |
|---|
| 454 | found = this.getElementForKey(opts, 'x', 1); |
|---|
| 455 | break; |
|---|
| 456 | case this.rightKeyCode: |
|---|
| 457 | found = this.getElementForKey(opts, 'x', -1); |
|---|
| 458 | break; |
|---|
| 459 | case this.escKeyCode: |
|---|
| 460 | case 9: |
|---|
| 461 | this.clearSelection(); |
|---|
| 462 | this.hasFocus = false; |
|---|
| 463 | default: return; |
|---|
| 464 | } |
|---|
| 465 | switch (found) |
|---|
| 466 | { |
|---|
| 467 | case 0: return; |
|---|
| 468 | case 1: |
|---|
| 469 | //subopts |
|---|
| 470 | this.mouseOver(listitem, e); |
|---|
| 471 | break; |
|---|
| 472 | case 2: |
|---|
| 473 | //parent |
|---|
| 474 | this.mouseOut(opts[2], e); |
|---|
| 475 | break; |
|---|
| 476 | case 3: |
|---|
| 477 | case 4: |
|---|
| 478 | // left - right |
|---|
| 479 | this.removeClassName(link, hasSubMenu ? this.subHoverClass : this.hoverClass); |
|---|
| 480 | break; |
|---|
| 481 | } |
|---|
| 482 | var link = opts[found].getElementsByTagName('a')[0]; |
|---|
| 483 | if (opts[found].nodeName.toLowerCase() == 'ul') |
|---|
| 484 | opts[found] = opts[found].getElementsByTagName('li')[0]; |
|---|
| 485 | |
|---|
| 486 | this.addClassName(link, opts[found].getElementsByTagName('ul').length > 0 ? this.subHoverClass : this.hoverClass); |
|---|
| 487 | this.lastOpen = link; |
|---|
| 488 | opts[found].getElementsByTagName('a')[0].focus(); |
|---|
| 489 | }; |
|---|
| 490 | Spry.Widget.MenuBar.prototype.mouseOver = function (listitem, e) |
|---|
| 491 | { |
|---|
| 492 | var link = listitem.getElementsByTagName('a')[0]; |
|---|
| 493 | var submenus = listitem.getElementsByTagName('ul'); |
|---|
| 494 | var menu = (submenus.length > 0 ? submenus[0] : null); |
|---|
| 495 | var hasSubMenu = (menu) ? true : false; |
|---|
| 496 | if (this.enableKeyboardNavigation) |
|---|
| 497 | this.clearSelection(listitem); |
|---|
| 498 | |
|---|
| 499 | if(this.bubbledTextEvent()) |
|---|
| 500 | { |
|---|
| 501 | // ignore bubbled text events |
|---|
| 502 | return; |
|---|
| 503 | } |
|---|
| 504 | |
|---|
| 505 | if (listitem.closetime) |
|---|
| 506 | clearTimeout(listitem.closetime); |
|---|
| 507 | |
|---|
| 508 | if(this.currMenu == listitem) |
|---|
| 509 | { |
|---|
| 510 | this.currMenu = null; |
|---|
| 511 | } |
|---|
| 512 | |
|---|
| 513 | // move the focus too |
|---|
| 514 | if (this.hasFocus) |
|---|
| 515 | link.focus(); |
|---|
| 516 | |
|---|
| 517 | // show menu highlighting |
|---|
| 518 | this.addClassName(link, hasSubMenu ? this.subHoverClass : this.hoverClass); |
|---|
| 519 | this.lastOpen = link; |
|---|
| 520 | if(menu && !this.hasClassName(menu, this.subHoverClass)) |
|---|
| 521 | { |
|---|
| 522 | var self = this; |
|---|
| 523 | listitem.opentime = window.setTimeout(function(){self.showSubmenu(menu);}, this.showDelay); |
|---|
| 524 | } |
|---|
| 525 | }; |
|---|
| 526 | Spry.Widget.MenuBar.prototype.mouseOut = function (listitem, e) |
|---|
| 527 | { |
|---|
| 528 | var link = listitem.getElementsByTagName('a')[0]; |
|---|
| 529 | var submenus = listitem.getElementsByTagName('ul'); |
|---|
| 530 | var menu = (submenus.length > 0 ? submenus[0] : null); |
|---|
| 531 | var hasSubMenu = (menu) ? true : false; |
|---|
| 532 | if(this.bubbledTextEvent()) |
|---|
| 533 | { |
|---|
| 534 | // ignore bubbled text events |
|---|
| 535 | return; |
|---|
| 536 | } |
|---|
| 537 | |
|---|
| 538 | var related = (typeof e.relatedTarget != 'undefined' ? e.relatedTarget : e.toElement); |
|---|
| 539 | if(!listitem.contains(related)) |
|---|
| 540 | { |
|---|
| 541 | if (listitem.opentime) |
|---|
| 542 | clearTimeout(listitem.opentime); |
|---|
| 543 | this.currMenu = listitem; |
|---|
| 544 | |
|---|
| 545 | // remove menu highlighting |
|---|
| 546 | this.removeClassName(link, hasSubMenu ? this.subHoverClass : this.hoverClass); |
|---|
| 547 | if(menu) |
|---|
| 548 | { |
|---|
| 549 | var self = this; |
|---|
| 550 | listitem.closetime = window.setTimeout(function(){self.hideSubmenu(menu);}, this.hideDelay); |
|---|
| 551 | } |
|---|
| 552 | if (this.hasFocus) |
|---|
| 553 | link.blur(); |
|---|
| 554 | } |
|---|
| 555 | }; |
|---|
| 556 | Spry.Widget.MenuBar.prototype.getSibling = function(element, sibling) |
|---|
| 557 | { |
|---|
| 558 | var child = element[sibling]; |
|---|
| 559 | while (child && child.nodeName.toLowerCase() !='li') |
|---|
| 560 | child = child[sibling]; |
|---|
| 561 | |
|---|
| 562 | return child; |
|---|
| 563 | }; |
|---|
| 564 | Spry.Widget.MenuBar.prototype.getElementForKey = function(els, prop, dir) |
|---|
| 565 | { |
|---|
| 566 | var found = 0; |
|---|
| 567 | var rect = Spry.Widget.MenuBar.getPosition; |
|---|
| 568 | var ref = rect(els[found]); |
|---|
| 569 | |
|---|
| 570 | var hideSubmenu = false; |
|---|
| 571 | //make the subelement visible to compute the position |
|---|
| 572 | if (els[1] && !this.hasClassName(els[1], this.MenuBarSubmenuVisible)) |
|---|
| 573 | { |
|---|
| 574 | els[1].style.visibility = 'hidden'; |
|---|
| 575 | this.showSubmenu(els[1]); |
|---|
| 576 | hideSubmenu = true; |
|---|
| 577 | } |
|---|
| 578 | |
|---|
| 579 | for (var i = 0; i < els.length; i++) |
|---|
| 580 | if (els[i]) |
|---|
| 581 | { |
|---|
| 582 | var tmp = rect(els[i]); |
|---|
| 583 | if ( (dir * tmp[prop]) < (dir * ref[prop])) |
|---|
| 584 | { |
|---|
| 585 | ref = tmp; |
|---|
| 586 | found = i; |
|---|
| 587 | } |
|---|
| 588 | } |
|---|
| 589 | |
|---|
| 590 | // hide back the submenu |
|---|
| 591 | if (els[1] && hideSubmenu){ |
|---|
| 592 | this.hideSubmenu(els[1]); |
|---|
| 593 | els[1].style.visibility = ''; |
|---|
| 594 | } |
|---|
| 595 | |
|---|
| 596 | return found; |
|---|
| 597 | }; |
|---|
| 598 | Spry.Widget.MenuBar.camelize = function(str) |
|---|
| 599 | { |
|---|
| 600 | if (str.indexOf('-') == -1){ |
|---|
| 601 | return str; |
|---|
| 602 | } |
|---|
| 603 | var oStringList = str.split('-'); |
|---|
| 604 | var isFirstEntry = true; |
|---|
| 605 | var camelizedString = ''; |
|---|
| 606 | |
|---|
| 607 | for(var i=0; i < oStringList.length; i++) |
|---|
| 608 | { |
|---|
| 609 | if(oStringList[i].length>0) |
|---|
| 610 | { |
|---|
| 611 | if(isFirstEntry) |
|---|
| 612 | { |
|---|
| 613 | camelizedString = oStringList[i]; |
|---|
| 614 | isFirstEntry = false; |
|---|
| 615 | } |
|---|
| 616 | else |
|---|
| 617 | { |
|---|
| 618 | var s = oStringList[i]; |
|---|
| 619 | camelizedString += s.charAt(0).toUpperCase() + s.substring(1); |
|---|
| 620 | } |
|---|
| 621 | } |
|---|
| 622 | } |
|---|
| 623 | |
|---|
| 624 | return camelizedString; |
|---|
| 625 | }; |
|---|
| 626 | |
|---|
| 627 | Spry.Widget.MenuBar.getStyleProp = function(element, prop) |
|---|
| 628 | { |
|---|
| 629 | var value; |
|---|
| 630 | try |
|---|
| 631 | { |
|---|
| 632 | if (element.style) |
|---|
| 633 | value = element.style[Spry.Widget.MenuBar.camelize(prop)]; |
|---|
| 634 | |
|---|
| 635 | if (!value) |
|---|
| 636 | if (document.defaultView && document.defaultView.getComputedStyle) |
|---|
| 637 | { |
|---|
| 638 | var css = document.defaultView.getComputedStyle(element, null); |
|---|
| 639 | value = css ? css.getPropertyValue(prop) : null; |
|---|
| 640 | } |
|---|
| 641 | else if (element.currentStyle) |
|---|
| 642 | { |
|---|
| 643 | value = element.currentStyle[Spry.Widget.MenuBar.camelize(prop)]; |
|---|
| 644 | } |
|---|
| 645 | } |
|---|
| 646 | catch (e) {} |
|---|
| 647 | |
|---|
| 648 | return value == 'auto' ? null : value; |
|---|
| 649 | }; |
|---|
| 650 | Spry.Widget.MenuBar.getIntProp = function(element, prop) |
|---|
| 651 | { |
|---|
| 652 | var a = parseInt(Spry.Widget.MenuBar.getStyleProp(element, prop),10); |
|---|
| 653 | if (isNaN(a)) |
|---|
| 654 | return 0; |
|---|
| 655 | return a; |
|---|
| 656 | }; |
|---|
| 657 | |
|---|
| 658 | Spry.Widget.MenuBar.getPosition = function(el, doc) |
|---|
| 659 | { |
|---|
| 660 | doc = doc || document; |
|---|
| 661 | if (typeof(el) == 'string') { |
|---|
| 662 | el = doc.getElementById(el); |
|---|
| 663 | } |
|---|
| 664 | |
|---|
| 665 | if (!el) { |
|---|
| 666 | return false; |
|---|
| 667 | } |
|---|
| 668 | |
|---|
| 669 | if (el.parentNode === null || Spry.Widget.MenuBar.getStyleProp(el, 'display') == 'none') { |
|---|
| 670 | //element must be visible to have a box |
|---|
| 671 | return false; |
|---|
| 672 | } |
|---|
| 673 | |
|---|
| 674 | var ret = {x:0, y:0}; |
|---|
| 675 | var parent = null; |
|---|
| 676 | var box; |
|---|
| 677 | |
|---|
| 678 | if (el.getBoundingClientRect) { // IE |
|---|
| 679 | box = el.getBoundingClientRect(); |
|---|
| 680 | var scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop; |
|---|
| 681 | var scrollLeft = doc.documentElement.scrollLeft || doc.body.scrollLeft; |
|---|
| 682 | ret.x = box.left + scrollLeft; |
|---|
| 683 | ret.y = box.top + scrollTop; |
|---|
| 684 | } else if (doc.getBoxObjectFor) { // gecko |
|---|
| 685 | box = doc.getBoxObjectFor(el); |
|---|
| 686 | ret.x = box.x; |
|---|
| 687 | ret.y = box.y; |
|---|
| 688 | } else { // safari/opera |
|---|
| 689 | ret.x = el.offsetLeft; |
|---|
| 690 | ret.y = el.offsetTop; |
|---|
| 691 | parent = el.offsetParent; |
|---|
| 692 | if (parent != el) { |
|---|
| 693 | while (parent) { |
|---|
| 694 | ret.x += parent.offsetLeft; |
|---|
| 695 | ret.y += parent.offsetTop; |
|---|
| 696 | parent = parent.offsetParent; |
|---|
| 697 | } |
|---|
| 698 | } |
|---|
| 699 | // opera & (safari absolute) incorrectly account for body offsetTop |
|---|
| 700 | if (Spry.is.opera || Spry.is.safari && Spry.Widget.MenuBar.getStyleProp(el, 'position') == 'absolute') |
|---|
| 701 | ret.y -= doc.body.offsetTop; |
|---|
| 702 | } |
|---|
| 703 | if (el.parentNode) |
|---|
| 704 | parent = el.parentNode; |
|---|
| 705 | else |
|---|
| 706 | parent = null; |
|---|
| 707 | if (parent.nodeName){ |
|---|
| 708 | var cas = parent.nodeName.toUpperCase(); |
|---|
| 709 | while (parent && cas != 'BODY' && cas != 'HTML') { |
|---|
| 710 | cas = parent.nodeName.toUpperCase(); |
|---|
| 711 | ret.x -= parent.scrollLeft; |
|---|
| 712 | ret.y -= parent.scrollTop; |
|---|
| 713 | if (parent.parentNode) |
|---|
| 714 | parent = parent.parentNode; |
|---|
| 715 | else |
|---|
| 716 | parent = null; |
|---|
| 717 | } |
|---|
| 718 | } |
|---|
| 719 | // adjust the margin |
|---|
| 720 | var gi = Spry.Widget.MenuBar.getIntProp; |
|---|
| 721 | var btw = gi(el, "margin-top"); |
|---|
| 722 | var blw = gi(el, "margin-left"); |
|---|
| 723 | ret.x -= blw; |
|---|
| 724 | ret.y -= btw; |
|---|
| 725 | return ret; |
|---|
| 726 | }; |
|---|
| 727 | Spry.Widget.MenuBar.stopPropagation = function(ev) |
|---|
| 728 | { |
|---|
| 729 | if (ev.stopPropagation) |
|---|
| 730 | ev.stopPropagation(); |
|---|
| 731 | else |
|---|
| 732 | ev.cancelBubble = true; |
|---|
| 733 | }; |
|---|
| 734 | Spry.Widget.MenuBar.setOptions = function(obj, optionsObj, ignoreUndefinedProps) |
|---|
| 735 | { |
|---|
| 736 | if (!optionsObj) |
|---|
| 737 | return; |
|---|
| 738 | for (var optionName in optionsObj) |
|---|
| 739 | { |
|---|
| 740 | if (ignoreUndefinedProps && optionsObj[optionName] == undefined) |
|---|
| 741 | continue; |
|---|
| 742 | obj[optionName] = optionsObj[optionName]; |
|---|
| 743 | } |
|---|
| 744 | }; |
|---|