1/*======================================================================*\ 2|| #################################################################### || 3|| # vBulletin 3.5.4 4|| # ---------------------------------------------------------------- # || 5|| # Copyright ©2000-2006 Jelsoft Enterprises Ltd. All Rights Reserved. || 6|| # This file may not be redistributed in whole or significant part. # || 7|| # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # || 8|| # http://www.vbulletin.com | http://www.vbulletin.com/license.html # || 9|| #################################################################### || 10\*======================================================================*/ 11 12/** 13* vBulletin popup menu example usage: 14* 15* To create a new popup menu: 16* <element id="x">Click me <script type="text/javascript"> vBmenu.register('x'); </script></element> 17* 18* To create a dynamic popup menu with a title and two options: 19* <element id="x">Click me</element> 20* <script type="text/javascript"> 21* menu = new vB_Menu_Builder('x'); 22* menu.set_title('My Menu'); 23* menu.add_option('Option 1', 'script.php?opt=1'); 24* menu.add_option('Option 2', 'script.php?opt=2'); 25* menu.build(); 26* </script> 27*/ 28 29// ############################################################################# 30// vB_Popup_Handler 31// ############################################################################# 32 33/** 34* vBulletin popup menu registry 35*/ 36function vB_Popup_Handler() 37{ 38 /** 39 * Options: 40 * 41 * @var integer Number of steps to use in sliding menus open 42 * @var boolean Use opacity face in menu open? 43 */ 44 this.open_steps = 10; 45 this.open_fade = false;
46 47 this.active = false; 48 49 this.menus = new Array(); 50 this.activemenu = null; 51 52 this.hidden_selects = new Array(); 53} 54 55// ============================================================================= 56// vB_Popup_Handler methods 57 58/** 59* Activate / Deactivate the menu system 60* 61* @param boolean Active state for menus 62*/ 63vB_Popup_Handler.prototype.activate = function(active) 64{ 65 this.active = active; 66} 67 68/** 69* Register a control object as a menu control 70* 71* @param string ID of the control object 72* @param boolean Do not add an image (true) 73* 74* @return vB_Popup_Menu 75*/ 76vB_Popup_Handler.prototype.register = function(controlkey, noimage) 77{ 78 this.menus[controlkey] = new vB_Popup_Menu(controlkey, noimage); 79 80 return this.menus[controlkey]; 81} 82 83/** 84* Hide active menu 85*/ 86vB_Popup_Handler.prototype.hide = function() 87{ 88 if (this.activemenu != null) 89 { 90 //this.activemenu.hide(); 91 this.menus[this.activemenu].hide(); 92 } 93} 94 95 96// ############################################################################# 97// initialize menu registry 98 99vBmenu = new vB_Popup_Handler(); 100 101/** 102* Function to allow anything to hide all menus 103* 104* @param event Event object 105* 106* @return mixed 107*/ 108function vbmenu_hide(e) 109{ 110 if (e && e.button && e.button != 1 && e.type == 'click') 111 { 112 return true; 113 } 114 else 115 { 116 vBmenu.hide(); 117 } 118} 119 120// ############################################################################# 121// vB_Popup_Menu 122// ############################################################################# 123 124/**
125* vBulletin popup menu class constructor 126* 127* Manages a single menu and control object 128* Initializes control object 129* 130* @param string ID of the control object 131*/ 132function vB_Popup_Menu(controlkey, noimage) 133{ 134 this.controlkey = controlkey; 135 this.menuname = this.controlkey.split('.')[0] + '_menu'; 136 137 this.init_control(noimage); 138 139 if (fetch_object(this.menuname)) 140 { 141 this.init_menu(); 142 } 143 144 this.slide_open = (is_opera ? false : true); 145 this.open_steps = vBmenu.open_steps; 146} 147 148// ============================================================================= 149// vB_Popup_Menu methods 150 151/** 152* Initialize the control object 153*/ 154vB_Popup_Menu.prototype.init_control = function(noimage) 155{ 156 this.controlobj = fetch_object(this.controlkey); 157 this.controlobj.state = false; 158 159 if (this.controlobj.firstChild && (this.controlobj.firstChild.tagName == 'TEXTAREA' || this.controlobj.firstChild.tagName == 'INPUT')) 160 { 161 // do nothing 162 } 163 else 164 { 165 if (!noimage && !(is_mac && is_ie)) 166 { 167 var space = document.createTextNode(' '); 168 this.controlobj.appendChild(space); 169 170 var img = document.createElement('img'); 171 img.src = IMGDIR_MISC + '/menu_open.gif'; 172 img.border = 0; 173 img.title = ''; 174 img.alt = ''; 175 this.controlobj.appendChild(img); 176 } 177 178 this.controlobj.unselectable = true; 179 if (!noimage) 180 { 181 this.controlobj.style.cursor = pointer_cursor; 182 } 183 this.controlobj.onclick = vB_Popup_Events.prototype.controlobj_onclick; 184 this.controlobj.onmouseover = vB_Popup_Events.prototype.controlobj_onmouseover; 185 } 186} 187 188/** 189* Init the popup menu object 190*/ 191vB_Popup_Menu.prototype.init_menu = function() 192{ 193 this.menuobj = fetch_object(this.menuname); 194 195 if (this.menuobj && !this.menuobj.initialized) 196 { 197 this.menuobj.initialized = true; 198 this.menuobj.onclick = e_by_gum; 199 this.menuobj.style.position = 'absolute'; 200 this.menuobj.style.zIndex = 50; 201 202 // init popup filters (ie only) 203 if (is_ie && !is_mac) 204 { 205 this.menuobj.style.filter += "progid:DXImageTransform.Microsoft.alpha(enabled=1,opacity=100)"; 206 this.menuobj.style.filter += "progid:DXImageTransform.Microsoft.shadow(direction=135,color=#8E8E8E,strength=3)"; 207 } 208 209 this.init_menu_contents(); 210 } 211} 212 213/** 214* Init the popup menu contents 215*/ 216vB_Popup_Menu.prototype.init_menu_contents = function() 217{ 218 var tds = fetch_tags(this.menuobj, 'td'); 219 for (var i = 0; i < tds.length; i++) 220 { 221 if (tds[i].className == 'vbmenu_option') 222 { 223 if (tds[i].title && tds[i].title == 'nohilite') 224 { 225 // not an active cell 226 tds[i].title = ''; 227 } 228 else 229 { 230 // create a reference back to the menu class 231 tds[i].controlkey = this.controlkey; 232 233 // handle mouseover / mouseout highlighting events 234 tds[i].onmouseover = vB_Popup_Events.prototype.menuoption_onmouseover; 235 tds[i].onmouseout = vB_Popup_Events.prototype.menuoption_onmouseout; 236 237 if (typeof tds[i].onclick == 'function') 238 { 239 // allow onclick events from <td> elements to override <a> elements inside 240 tds[i].ofunc = tds[i].onclick; 241 tds[i].onclick = vB_Popup_Events.prototype.menuoption_onclick_function; 242 } 243 else 244 { 245 // attempt to emulate a click on internal <a> elements 246 tds[i].onclick = vB_Popup_Events.prototype.menuoption_onclick_link; 247 } 248 249 // wondering what this was supposed to do actually... 250 if (!is_saf && !is_kon) 251 { 252 try 253 { 254 links = fetch_tags(tds[i], 'a'); 255 for (var j = 0; j < links.length; j++) 256 { 257 if (typeof links[j].onclick == 'undefined') 258 { 259 links[j].onclick = e_by_gum; 260 } 261 } 262 } 263 catch(e) 264 { 265 // hmmm... 266 } 267 } 268 } 269 } 270 } 271} 272 273/** 274* Show the menu 275* 276* @param object The control object calling the menu 277* @param boolean Use slide (false) or open instantly? (true) 278*/ 279vB_Popup_Menu.prototype.show = function(obj, instant) 280{ 281 if (!vBmenu.active) 282 { 283 return false; 284 } 285 else if (!this.menuobj) 286 { 287 this.init_menu(); 288 } 289 290 if (!this.menuobj) 291 { 292 return false; 293 } 294 295 if (vBmenu.activemenu != null) 296 { 297 vBmenu.menus[vBmenu.activemenu].hide(); 298 } 299 300 vBmenu.activemenu = this.controlkey; 301 302 this.menuobj.style.display = ''; 303 if (vBmenu.slide_open) 304 { 305 this.menuobj.style.clip = 'rect(auto, auto, auto, auto)'; 306 } 307 this.pos = this.fetch_offset(obj); 308 this.leftpx = this.pos['left']; 309 this.toppx = this.pos['top'] + obj.offsetHeight; 310 311 if ((this.leftpx + this.menuobj.offsetWidth) >= document.body.clientWidth && (this.leftpx + obj.offsetWidth - this.menuobj.offsetWidth) > 0) 312 { 313 this.leftpx = this.leftpx + obj.offsetWidth - this.menuobj.offsetWidth; 314 this.direction = 'right'; 315 } 316 else 317 { 318 this.direction = 'left' 319 } 320 321 this.menuobj.style.left = this.leftpx + 'px'; 322 this.menuobj.style.top = this.toppx + 'px'; 323 324 if (!instant && this.slide_open) 325 { 326 this.intervalX = Math.ceil(this.menuobj.offsetWidth / this.open_steps);
327 this.intervalY = Math.ceil(this.menuobj.offsetHeight / this.open_steps); 328 this.slide((this.direction == 'left' ? 0 : this.menuobj.offsetWidth), 0, 0); 329 } 330 else if (this.menuobj.style.clip && vBmenu.slide_open) 331 { 332 this.menuobj.style.clip = 'rect(auto, auto, auto, auto)'; 333 } 334 335 // deal with IE putting <select> elements on top of everything 336 this.handle_overlaps(true); 337 338 if (this.controlobj.editorid) 339 { 340 this.controlobj.state = true; 341 //this.controlobj.editor.menu_context(this.controlobj, 'mousedown'); 342 vB_Editor[this.controlobj.editorid].menu_context(this.controlobj, 'mousedown'); 343 } 344} 345 346/** 347* Hide the menu 348*/ 349vB_Popup_Menu.prototype.hide = function(e) 350{ 351 352 if (e && e.button && e.button != 1) 353 { 354 // get around some context menu issues etc. 355 return true; 356 } 357 358 this.stop_slide(); 359 360 this.menuobj.style.display = 'none'; 361 362 this.handle_overlaps(false); 363 364 if (this.controlobj.editorid) 365 { 366 this.controlobj.state = false; 367 //this.controlobj.editor.menu_context(this.controlobj, 'mouseout'); 368 vB_Editor[this.controlobj.editorid].menu_context(this.controlobj, 'mouseout'); 369 } 370 371 vBmenu.activemenu = null; 372} 373 374/** 375* Hover behaviour for control object 376*/ 377vB_Popup_Menu.prototype.hover = function(obj) 378{ 379 if (vBmenu.activemenu != null) 380 { 381 if (vBmenu.menus[vBmenu.activemenu].controlkey != this.id) 382 { 383 this.show(obj, true); 384 } 385 } 386} 387 388/** 389* Simulate clicking an option in a menu 390* 391* @param event Event object 392* @param object Clicked object 393*/ 394vB_Popup_Menu.prototype.choose = function(e, obj) 395{ 396 var links = fetch_tags(obj, 'a'); 397 if (links[0]) 398 { 399 if (is_ie) 400 { 401 // use this in IE to send HTTP_REFERER 402 links[0].click(); 403 window.event.cancelBubble = true; 404 } 405 else 406 { 407 // other browsers can use this 408 if (e.shiftKey) 409 { 410 window.open(links[0].href); 411 e.stopPropagation(); 412 e.preventDefault(); 413 } 414 else 415 { 416 window.location = links[0].href; 417 e.stopPropagation(); 418 e.preventDefault(); 419 } 420 } 421 422 this.hide(); 423 } 424} 425 426/** 427* Slides menu open 428* 429* @param integer Clip X 430* @param integer Clip Y 431* @param integer Opacity (0-100) 432*/ 433vB_Popup_Menu.prototype.slide = function(clipX, clipY, opacity) 434{ 435 if (this.direction == 'left' && (clipX < this.menuobj.offsetWidth || clipY < this.menuobj.offsetHeight)) 436 { 437 if (vBmenu.open_fade && is_ie) 438 { 439 opacity += 10; 440 this.menuobj.filters.item('DXImageTransform.Microsoft.alpha').opacity = opacity; 441 } 442 443 clipX += this.intervalX; 444 clipY += this.intervalY; 445 446 this.menuobj.style.clip = "rect(auto, " + clipX + "px, " + clipY + "px, auto)"; 447 this.slidetimer = setTimeout("vBmenu.menus[vBmenu.activemenu].slide(" + clipX + ", " + clipY + ", " + opacity + ");", 0); 448 } 449 else if (this.direction == 'right' && (clipX > 0 || clipY < this.menuobj.offsetHeight)) 450 { 451 if (vBmenu.open_fade && is_ie) 452 { 453 opacity += 10; 454 menuobj.filters.item('DXImageTransform.Microsoft.alpha').opacity = opacity; 455 } 456 457 clipX -= this.intervalX; 458 clipY += this.intervalY; 459 460 this.menuobj.style.clip = "rect(auto, " + this.menuobj.offsetWidth + "px, " + clipY + "px, " + clipX + "px)"; 461 this.slidetimer = setTimeout("vBmenu.menus[vBmenu.activemenu].slide(" + clipX + ", " + clipY + ", " + opacity + ");", 0); 462 } 463 else 464 { 465 this.stop_slide(); 466 } 467} 468 469/** 470* Abort menu slider 471*/ 472vB_Popup_Menu.prototype.stop_slide = function() 473{ 474 clearTimeout(this.slidetimer); 475 476 this.menuobj.style.clip = 'rect(auto, auto, auto, auto)'; 477 478 if (vBmenu.open_fade && is_ie) 479 { 480 this.menuobj.filters.item('DXImageTransform.Microsoft.alpha').opacity = 100; 481 } 482} 483 484/** 485* Fetch offset of an object 486* 487* @param object The object to be measured 488* 489* @return array The measured offsets left/top 490*/ 491vB_Popup_Menu.prototype.fetch_offset = function(obj) 492{ 493 var left_offset = obj.offsetLeft; 494 var top_offset = obj.offsetTop; 495 496 while ((obj = obj.offsetParent) != null) 497 { 498 left_offset += obj.offsetLeft; 499 top_offset += obj.offsetTop; 500 } 501 502 return { 'left' : left_offset, 'top' : top_offset }; 503} 504 505/** 506* Detect an overlap of an object and a menu 507* 508* @param object Object to be tested for overlap 509* @param array Array of dimensions for menu object 510* 511* @return boolean True if overlap 512*/ 513vB_Popup_Menu.prototype.overlaps = function(obj, m) 514{ 515 var s = new Array(); 516 var pos = this.fetch_offset(obj); 517 s['L'] = pos['left']; 518 s['T'] = pos['top']; 519 s['R'] = s['L'] + obj.offsetWidth; 520 s['B'] = s['T'] + obj.offsetHeight; 521 522 523 if (s['L'] > m['R'] || s['R'] < m['L'] || s['T'] > m['B'] || s['B'] < m['T']) 524 { 525 return false;
526 } 527 return true; 528} 529 530/** 531* Handle IE overlapping <select> elements 532* 533* @param boolean Hide (true) or show (false) overlapping <select> elements 534*/ 535vB_Popup_Menu.prototype.handle_overlaps = function(dohide) 536{ 537 if (is_ie) 538 { 539 var selects = fetch_tags(document, 'select'); 540 541 if (dohide) 542 { 543 var menuarea = new Array(); menuarea = { 544 'L' : this.leftpx, 545 'R' : this.leftpx + this.menuobj.offsetWidth, 546 'T' : this.toppx, 547 'B' : this.toppx + this.menuobj.offsetHeight 548 }; 549 550 for (var i = 0; i < selects.length; i++) 551 { 552 if (this.overlaps(selects[i], menuarea)) 553 { 554 var hide = true; 555 var s = selects[i]; 556 while (s = s.parentNode) 557 { 558 if (s.className == 'vbmenu_popup') 559 { 560 hide = false; 561 break; 562 } 563 } 564 565 if (hide) 566 { 567 selects[i].style.visibility = 'hidden'; 568 array_push(vBmenu.hidden_selects, i); 569 } 570 } 571 } 572 } 573 else 574 { 575 while (true) 576 { 577 var i = array_pop(vBmenu.hidden_selects); 578 if (typeof i == 'undefined' || i == null) 579 { 580 break; 581 } 582 else 583 { 584 selects[i].style.visibility = 'visible'; 585 } 586 } 587 } 588 } 589} 590 591// ############################################################################# 592// Menu event handler functions 593 594/** 595* Class containing menu popup event handlers 596*/ 597function vB_Popup_Events() 598{ 599} 600 601/** 602* Handles control object click events 603*/ 604vB_Popup_Events.prototype.controlobj_onclick = function(e) 605{ 606 do_an_e(e); 607 if (vBmenu.activemenu == null || vBmenu.menus[vBmenu.activemenu].controlkey != this.id) 608 { 609 vBmenu.menus[this.id].show(this); 610 } 611 else 612 { 613 vBmenu.menus[this.id].hide(); 614 } 615}; 616 617/** 618* Handles control object mouseover events 619*/ 620vB_Popup_Events.prototype.controlobj_onmouseover = function(e) 621{ 622 do_an_e(e); 623 vBmenu.menus[this.id].hover(this); 624}; 625 626/** 627* Handles menu option click events for options with onclick events 628*/ 629vB_Popup_Events.prototype.menuoption_onclick_function = function(e) 630{ 631 this.ofunc(e); 632 vBmenu.menus[this.controlkey].hide(); 633}; 634 635/** 636* Handles menu option click events for options containing links 637*/ 638vB_Popup_Events.prototype.menuoption_onclick_link = function(e) 639{ 640 vBmenu.menus[this.controlkey].choose(e, this); 641}; 642 643/** 644* Handles menu option mouseover events 645*/ 646vB_Popup_Events.prototype.menuoption_onmouseover = function(e) 647{ 648 this.className = 'vbmenu_hilite'; 649}; 650 651/** 652* Handles menu option mouseout events 653*/ 654vB_Popup_Events.prototype.menuoption_onmouseout = function(e) 655{ 656 this.className = 'vbmenu_option'; 657}; 658 659/*======================================================================*\ 660|| #################################################################### 661|| # Downloaded: 13:29, Wed Mar 22nd 2006 662|| # CVS: $RCSfile: vbulletin_menu.js,v $ - $Revision: 1.40 $ 663|| #################################################################### 664\*======================================================================*/
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.