1/** 2 * Copyright (c)2005-2009 Matt Kruse (javascripttoolbox.com) 3 * 4 * Dual licensed under the MIT and GPL licenses. 5 * This basically means you can use this code however you want for 6 * free, but don't claim to have written it yourself! 7 * Donations always accepted: http://www.JavascriptToolbox.com/donate/ 8 * 9 * Please do not link to the .js files on javascripttoolbox.com from 10 * your site. Copy the files locally to your server instead. 11 * 12 */ 13/* ******************************************************************* */ 14/* UTIL FUNCTIONS */ 15/* ******************************************************************* */ 16var Util = {'$VERSION':1.06}; 17 18// Util functions - these are GLOBAL so they 19// look like built-in functions. 20 21// Determine if an object is an array 22function isArray(o) { 23 return (o!=null && typeof(o)=="object" && typeof(o.length)=="number" && (o.length==0 || defined(o[0]))); 24}; 25 26// Determine if an object is an Object 27function isObject(o) { 28 return (o!=null && typeof(o)=="object" && defined(o.constructor) && o.constructor==Object && !defined(o.nodeName)); 29}; 30 31// Determine if a reference is defined 32function defined(o) { 33 return (typeof(o)!="undefined"); 34}; 35 36// Iterate over an array, object, or list of items and run code against each item 37// Similar functionality to Perl's map() function 38function map(func) { 39 var i,j,o; 40 var results = []; 41 if (typeof(func)=="string") { 42 func = new Function('$_',func); 43 } 44 for (i=1; i<arguments.length; i++) { 45 o = arguments[i]; 46 if (isArray(o)) { 47 for (j=0; j<o.length; j++) { 48 results[results.length] = func(o[j]); 49 } 50 } 51 else if (isObject(o)) { 52 for (j in o) { 53 results[results.length] = func(o[j]); 54 } 55 } 56 else { 57 results[results.length] = func(o); 58 } 59 } 60 return results; 61}; 62 63// Set default values in an object if they are undefined 64function setDefaultValues(o,values) { 65 if (!defined(o) || o==null) { 66 o = {}; 67 } 68 if (!defined(values) || values==null) { 69 return o; 70 } 71 for (var val in values) { 72 if (!defined(o[val])) { 73 o[val] = values[val]; 74 } 75 } 76 return o; 77}; 78 79/* ******************************************************************* */ 80/* DEFAULT OBJECT PROTOTYPE ENHANCEMENTS */ 81/* ******************************************************************* */ 82// These functions add useful functionality to built-in objects 83Array.prototype.contains = function(o) { 84 var i,l; 85 if (!(l = this.length)) { return false; } 86 for (i=0; i<l; i++) { 87 if (o==this[i]) { 88 return true; 89 } 90 } 91}; 92 93/* ******************************************************************* */ 94/* DOM FUNCTIONS */ 95/* ******************************************************************* */ 96var DOM = (function() { 97 var dom = {}; 98 99 // Get a parent tag with a given nodename 100 dom.getParentByTagName = function(o,tagNames) { 101 if(o==null) { return null; } 102 if (isArray(tagNames)) { 103 tagNames = map("return $_.toUpperCase()",tagNames); 104 while (o=o.parentNode) { 105 if (o.nodeName && tagNames.contains(o.nodeName)) { 106 return o; 107 } 108 } 109 } 110 else { 111 tagNames = tagNames.toUpperCase(); 112 while (o=o.parentNode) { 113 if (o.nodeName && tagNames==o.nodeName) { 114 return o; 115 } 116 } 117 } 118 return null; 119 }; 120 121 // Remove a node from its parent 122 dom.removeNode = function(o) { 123 if (o!=null && o.parentNode && o.parentNode.removeChild) { 124 // First remove all attributes which are func references, to avoid memory leaks 125 for (var i in o) { 126 if (typeof(o[i])=="function") { 127 o[i] = null; 128 } 129 } 130 o.parentNode.removeChild(o); 131 return true; 132 } 133 return false; 134 }; 135 136 // Get the outer width in pixels of an object, including borders, padding, and margin 137 dom.getOuterWidth = function(o) { 138 if (defined(o.offsetWidth)) { 139 return o.offsetWidth; 140 } 141 return null; 142 }; 143 144 // Get the outer height in pixels of an object, including borders, padding, and margin 145 dom.getOuterHeight = function(o) { 146 if (defined(o.offsetHeight)) { 147 return o.offsetHeight; 148 } 149 return null; 150 }; 151 152 // Resolve an item, an array of items, or an object of items 153 dom.resolve = function() { 154 var results = new Array(); 155 var i,j,o; 156 for (var i=0; i<arguments.length; i++) { 157 var o = arguments[i]; 158 if (o==null) { 159 if (arguments.length==1) { 160 return null; 161 } 162 results[results.length] = null; 163 } 164 else if (typeof(o)=='string') { 165 if (document.getElementById) { 166 o = document.getElementById(o); 167 } 168 else if (document.all) { 169 o = document.all[o]; 170 } 171 if (arguments.length==1) { 172 return o; 173 } 174 results[results.length] = o; 175 } 176 else if (isArray(o)) { 177 for (j=0; j<o.length; j++) { 178 results[results.length] = o[j]; 179 } 180 } 181 else if (isObject(o)) { 182 for (j in o) { 183 results[results.length] = o[j]; 184 } 185 } 186 else if (arguments.length==1) { 187 return o; 188 } 189 else { 190 results[results.length] = o; 191 } 192 } 193 return results; 194 }; 195 dom.$ = dom.resolve; 196 197 return dom; 198})(); 199 200/* ******************************************************************* */ 201/* CSS FUNCTIONS */ 202/* ******************************************************************* */ 203var CSS = (function(){ 204 var css = {}; 205
206 // Convert an RGB string in the form "rgb (255, 255, 255)" to "#ffffff" 207 css.rgb2hex = function(rgbString) { 208 if (typeof(rgbString)!="string" || !defined(rgbString.match)) { return null; } 209 var result = rgbString.match(/^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/); 210 if (result==null) { return rgbString; } 211 var rgb = +result[1] << 16 | +result[2] << 8 | +result[3]; 212 var hex = ""; 213 var digits = "0123456789abcdef"; 214 while(rgb!=0) { 215 hex = digits.charAt(rgb&0xf)+hex; 216 rgb>>>=4; 217 } 218 while(hex.length<6) { hex='0'+hex; } 219 return "#" + hex; 220 }; 221 222 // Convert hyphen style names like border-width to camel case like borderWidth 223 css.hyphen2camel = function(property) { 224 if (!defined(property) || property==null) { return null; } 225 if (property.indexOf("-")<0) { return property; } 226 var str = ""; 227 var c = null; 228 var l = property.length; 229 for (var i=0; i<l; i++) { 230 c = property.charAt(i); 231 str += (c!="-")?c:property.charAt(++i).toUpperCase(); 232 } 233 return str; 234 }; 235 236 // Determine if an object or class string contains a given class. 237 css.hasClass = function(obj,className) { 238 if (!defined(obj) || obj==null || !RegExp) { return false; } 239 var re = new RegExp("(^|\\s)" + className + "(\\s|$)"); 240 if (typeof(obj)=="string") { 241 return re.test(obj); 242 } 243 else if (typeof(obj)=="object" && obj.className) { 244 return re.test(obj.className); 245 } 246 return false; 247 }; 248 249 // Add a class to an object 250 css.addClass = function(obj,className) { 251 if (typeof(obj)!="object" || obj==null || !defined(obj.className)) { return false; } 252 if (obj.className==null || obj.className=='') { 253 obj.className = className; 254 return true; 255 } 256 if (css.hasClass(obj,className)) { return true; } 257 obj.className = obj.className + " " + className; 258 return true; 259 }; 260 261 // Remove a class from an object 262 css.removeClass = function(obj,className) { 263 if (typeof(obj)!="object" || obj==null || !defined(obj.className) || obj.className==null) { return false; } 264 if (!css.hasClass(obj,className)) { return false; } 265 var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)"); 266 obj.className = obj.className.replace(re,' '); 267 return true; 268 }; 269 270 // Fully replace a class with a new one 271 css.replaceClass = function(obj,className,newClassName) { 272 if (typeof(obj)!="object" || obj==null || !defined(obj.className) || obj.className==null) { return false; } 273 css.removeClass(obj,className); 274 css.addClass(obj,newClassName); 275 return true; 276 }; 277 278 // Get the currently-applied style of an object 279 css.getStyle = function(o, property) { 280 if (o==null) { return null; } 281 var val = null; 282 var camelProperty = css.hyphen2camel(property); 283 // Handle "float" property as a special case 284 if (property=="float") { 285 val = css.getStyle(o,"cssFloat"); 286 if (val==null) { 287 val = css.getStyle(o,"styleFloat"); 288 } 289 } 290 else if (o.currentStyle && defined(o.currentStyle[camelProperty])) { 291 val = o.currentStyle[camelProperty]; 292 } 293 else if (window.getComputedStyle) { 294 val = window.getComputedStyle(o,null).getPropertyValue(property); 295 } 296 else if (o.style && defined(o.style[camelProperty])) { 297 val = o.style[camelProperty]; 298 } 299 // For color values, make the value consistent across browsers 300 // Convert rgb() colors back to hex for consistency 301 if (/^\s*rgb\s*\(/.test(val)) { 302 val = css.rgb2hex(val); 303 } 304 // Lowercase all #hex values 305 if (/^#/.test(val)) { 306 val = val.toLowerCase(); 307 } 308 return val; 309 }; 310 css.get = css.getStyle; 311 312 // Set a style on an object 313 css.setStyle = function(o, property, value) { 314 if (o==null || !defined(o.style) || !defined(property) || property==null || !defined(value)) { return false; } 315 if (property=="float") { 316 o.style["cssFloat"] = value; 317 o.style["styleFloat"] = value; 318 } 319 else if (property=="opacity") { 320 o.style['-moz-opacity'] = value; 321 o.style['-khtml-opacity'] = value; 322 o.style.opacity = value; 323 if (defined(o.style.filter)) { 324 o.style.filter = "alpha(opacity=" + value*100 + ")"; 325 } 326 } 327 else { 328 o.style[css.hyphen2camel(property)] = value; 329 } 330 return true; 331 }; 332 css.set = css.setStyle; 333 334 // Get a unique ID which doesn't already exist on the page 335 css.uniqueIdNumber=1000; 336 css.createId = function(o) { 337 if (defined(o) && o!=null && defined(o.id) && o.id!=null && o.id!="") { 338 return o.id; 339 } 340 var id = null; 341 while (id==null || document.getElementById(id)!=null) { 342 id = "ID_"+(css.uniqueIdNumber++); 343 } 344 if (defined(o) && o!=null && (!defined(o.id)||o.id=="")) { 345 o.id = id; 346 } 347 return id; 348 }; 349 350 return css; 351})(); 352 353/* ******************************************************************* */ 354/* EVENT FUNCTIONS */ 355/* ******************************************************************* */ 356 357var Event = (function(){ 358 var ev = {}; 359 360 // Resolve an event using IE's window.event if necessary 361 // -------------------------------------------------------------------- 362 ev.resolve = function(e) { 363 if (!defined(e) && defined(window.event)) { 364 e = window.event; 365 } 366 return e; 367 }; 368 369 // Add an event handler to a function 370 // Note: Don't use 'this' within functions added using this method, since 371 // the attachEvent and addEventListener models differ. 372 // -------------------------------------------------------------------- 373 ev.add = function( obj, type, fn, capture ) { 374 if (obj.addEventListener) { 375 obj.addEventListener( type, fn, capture ); 376 return true; 377 } 378 else if (obj.attachEvent) { 379 obj.attachEvent( "on"+type, fn ); 380 return true; 381 } 382 return false;
383 }; 384 385 // Get the mouse position of an event 386 // -------------------------------------------------------------------- 387 // PageX/Y, where they exist, are more reliable than ClientX/Y because 388 // of some browser bugs in Opera/Safari 389 ev.getMouseX = function(e) { 390 e = ev.resolve(e); 391 if (defined(e.pageX)) { 392 return e.pageX; 393 } 394 if (defined(e.clientX)) { 395 return e.clientX+Screen.getScrollLeft(); 396 } 397 return null; 398 }; 399 ev.getMouseY = function(e) { 400 e = ev.resolve(e); 401 if (defined(e.pageY)) { 402 return e.pageY; 403 } 404 if (defined(e.clientY)) { 405 return e.clientY+Screen.getScrollTop(); 406 } 407 return null; 408 }; 409 410 // Stop the event from bubbling up to parent elements. 411 // Two method names map to the same function 412 // -------------------------------------------------------------------- 413 ev.cancelBubble = function(e) { 414 e = ev.resolve(e); 415 if (typeof(e.stopPropagation)=="function") { e.stopPropagation(); } 416 if (defined(e.cancelBubble)) { e.cancelBubble = true; } 417 }; 418 ev.stopPropagation = ev.cancelBubble; 419 420 // Prevent the default handling of the event to occur 421 // -------------------------------------------------------------------- 422 ev.preventDefault = function(e) { 423 e = ev.resolve(e); 424 if (typeof(e.preventDefault)=="function") { e.preventDefault(); } 425 if (defined(e.returnValue)) { e.returnValue = false; } 426 }; 427 428 return ev; 429})(); 430 431/* ******************************************************************* */ 432/* SCREEN FUNCTIONS */ 433/* ******************************************************************* */ 434var Screen = (function() { 435 var screen = {}; 436 437 // Get a reference to the body 438 // -------------------------------------------------------------------- 439 screen.getBody = function() { 440 if (document.body) { 441 return document.body; 442 } 443 if (document.getElementsByTagName) { 444 var bodies = document.getElementsByTagName("BODY"); 445 if (bodies!=null && bodies.length>0) { 446 return bodies[0]; 447 } 448 } 449 return null; 450 }; 451 452 // Get the amount that the main document has scrolled from top 453 // -------------------------------------------------------------------- 454 screen.getScrollTop = function() { 455 if (document.documentElement && defined(document.documentElement.scrollTop) && document.documentElement.scrollTop>0) { 456 return document.documentElement.scrollTop; 457 } 458 if (document.body && defined(document.body.scrollTop)) { 459 return document.body.scrollTop; 460 } 461 return null; 462 }; 463 464 // Get the amount that the main document has scrolled from left 465 // -------------------------------------------------------------------- 466 screen.getScrollLeft = function() { 467 if (document.documentElement && defined(document.documentElement.scrollLeft) && document.documentElement.scrollLeft>0) { 468 return document.documentElement.scrollLeft; 469 } 470 if (document.body && defined(document.body.scrollLeft)) { 471 return document.body.scrollLeft; 472 } 473 return null; 474 }; 475 476 // Util function to default a bad number to 0 477 // -------------------------------------------------------------------- 478 screen.zero = function(n) { 479 return (!defined(n) || isNaN(n))?0:n; 480 }; 481 482 // Get the width of the entire document 483 // -------------------------------------------------------------------- 484 screen.getDocumentWidth = function() { 485 var width = 0; 486 var body = screen.getBody(); 487 if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) { 488 var rightMargin = parseInt(CSS.get(body,'marginRight'),10) || 0; 489 var leftMargin = parseInt(CSS.get(body,'marginLeft'), 10) || 0; 490 width = Math.max(body.offsetWidth + leftMargin + rightMargin, document.documentElement.clientWidth); 491 } 492 else { 493 width = Math.max(body.clientWidth, body.scrollWidth); 494 } 495 if (isNaN(width) || width==0) { 496 width = screen.zero(self.innerWidth); 497 } 498 return width; 499 }; 500 501 // Get the height of the entire document 502 // -------------------------------------------------------------------- 503 screen.getDocumentHeight = function() { 504 var body = screen.getBody(); 505 var innerHeight = (defined(self.innerHeight)&&!isNaN(self.innerHe
505ight))?self.innerHeight:0; 506 if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) { 507 var topMargin = parseInt(CSS.get(body,'marginTop'),10) || 0; 508 var bottomMargin = parseInt(CSS.get(body,'marginBottom'), 10) || 0; 509 return Math.max(body.offsetHeight + topMargin + bottomMargin, document.documentElement.clientHeight, document.documentElement.scrollHeight, screen.zero(self.innerHeight)); 510 } 511 return Math.max(body.scrollHeight, body.clientHeight, screen.zero(self.innerHeight)); 512 }; 513 514 // Get the width of the viewport (viewable area) in the browser window 515 // -------------------------------------------------------------------- 516 screen.getViewportWidth = function() { 517 if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) { 518 return document.documentElement.clientWidth; 519 } 520 else if (document.compatMode && document.body) { 521 return document.body.clientWidth; 522 } 523 return screen.zero(self.innerWidth); 524 }; 525 526 // Get the height of the viewport (viewable area) in the browser window 527 // -------------------------------------------------------------------- 528 screen.getViewportHeight = function() { 529 if (!window.opera && document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) { 530 return document.documentElement.clientHeight; 531 } 532 else if (document.compatMode && !window.opera && document.body) { 533 return document.body.clientHeight; 534 } 535 return screen.zero(self.innerHeight); 536 }; 537 538 return screen; 539})();var Sort = (function(){ 540 var sort = {}; 541 sort.AlphaNumeric = function(a,b) { 542 if (a==b) { return 0; } 543 if (a<b) { return -1; } 544 return 1; 545 }; 546 547 sort.Default = sort.AlphaNumeric; 548 549 sort.NumericConversion = function(val) { 550 if (typeof(val)!="number") { 551 if (typeof(val)=="string") { 552 val = parseFloat(val.replace(/,/g,'')); 553 if (isNaN(val) || val==null) { val=0; } 554 } 555 else { 556 val = 0; 557 } 558 } 559 return val; 560 }; 561 562 sort.Numeric = function(a,b) { 563 return sort.NumericConversion(a)-sort.NumericConversion(b); 564 }; 565 566 sort.IgnoreCaseConversion = function(val) { 567 if (val==null) { val=""; } 568 return (""+val).toLowerCase(); 569 }; 570 571 sort.IgnoreCase = function(a,b) { 572 return sort.AlphaNumeric(sort.IgnoreCaseConversion(a),sort.IgnoreCaseConversion(b)); 573 }; 574 575 sort.CurrencyConversion = function(val) { 576 if (typeof(val)=="string") { 577 val = val.replace(/^[^\d\.]/,''); 578 } 579 return sort.NumericConversion(val); 580 }; 581 582 sort.Currency = function(a,b) { 583 return sort.Numeric(sort.CurrencyConversion(a),sort.CurrencyConversion(b)); 584 }; 585 586 sort.DateConversion = function(val) { 587 // inner util function to parse date formats 588 function getdate(str) { 589 // inner util function to convert 2-digit years to 4 590 function fixYear(yr) { 591 yr = +yr; 592 if (yr<50) { yr += 2000; } 593 else if (yr<100) { yr += 1900; } 594 return yr; 595 }; 596 var ret; 597 // YYYY-MM-DD 598 if (ret=str.match(/(\d{2,4})-(\d{1,2})-(\d{1,2})/)) { 599 return (fixYear(ret[1])*10000) + (ret[2]*100) + (+ret[3]); 600 } 601 // MM/DD/YY[YY] or MM-DD-YY[YY] 602 if (ret=str.match(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2,4})/)) { 603 return (fixYear(ret[3])*10000) + (ret[1]*100) + (+ret[2]); 604 } 605 return 99999999; // So non-parsed dates will be last, not first 606 }; 607 return getdate(val); 608 }; 609 610 sort.Date = function(a,b) { 611 return sort.Numeric(sort.DateConversion(a),sort.DateConversion(b)); 612 }; 613 614 return sort; 615})(); 616 617var Position = (function() { 618 // Resolve a string identifier to an object 619 // ======================================== 620 function resolveObject(s) { 621 if (document.getElementById && document.getElementById(s)!=null) { 622 return document.getElementById(s); 623 } 624 else if (document.all && document.all[s]!=null) { 625 return document.all[s]; 626 } 627 else if (document.anchors && document.anchors.length && document.anchors.length>0 && document.anchors[0].x) { 628 for (var i=0; i<document.anchors.length; i++) { 629 if (document.anchors[i].name==s) { 630 return document.anchors[i] 631 } 632 } 633 } 634 } 635 636 var pos = {}; 637 pos.$VERSION = 1.0; 638 639 // Set the position of an object 640 // ============================= 641 pos.set = function(o,left,top) { 642 if (typeof(o)=="string") { 643 o = resolveObject(o); 644 } 645 if (o==null || !o.style) { 646 return false;
647 } 648 649 // If the second parameter is an object, it is assumed to be the result of getPosition() 650 if (typeof(left)=="object") { 651 var pos = left; 652 left = pos.left; 653 top = pos.top; 654 } 655 656 o.style.left = left + "px"; 657 o.style.top = top + "px"; 658 return true; 659 }; 660 661 // Retrieve the position and size of an object 662 // =========================================== 663 pos.get = function(o) { 664 var fixBrowserQuirks = true; 665 // If a string is passed in instead of an object ref, resolve it 666 if (typeof(o)=="string") { 667 o = resolveObject(o); 668 } 669 670 if (o==null) { 671 return null; 672 } 673 674 var left = 0; 675 var top = 0; 676 var width = 0; 677 var height = 0; 678 var parentNode = null; 679 var offsetParent = null; 680 681 682 offsetParent = o.offsetParent; 683 var originalObject = o; 684 var el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references 685 while (el.parentNode!=null) { 686 el = el.parentNode; 687 if (el.offsetParent==null) { 688 } 689 else { 690 var considerScroll = true; 691 /* 692 In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already 693 take its scroll position into account. If elements further up the chain are scrollable, their 694 scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value 695 which must be ignored. 696 */ 697 if (fixBrowserQuirks && window.opera) { 698 if (el==originalObject.parentNode || el.nodeName=="TR") { 699 considerScroll = false; 700 } 701 } 702 if (considerScroll) { 703 if (el.scrollTop && el.scrollTop>0) { 704 top -= el.scrollTop; 705 } 706 if (el.scrollLeft && el.scrollLeft>0) { 707 left -= el.scrollLeft; 708 } 709 } 710 } 711 // If this node is also the offsetParent, add on the offsets and reset to the new offsetParent 712 if (el == offsetParent) { 713 left += o.offsetLeft; 714 if (el.clientLeft && el.nodeName!="TABLE") { 715 left += el.clientLeft; 716 } 717 top += o.offsetTop; 718 if (el.clientTop && el.nodeName!="TABLE") { 719 top += el.clientTop; 720 } 721 o = el; 722 if (o.offsetParent==null) { 723 if (o.offsetLeft) { 724 left += o.offsetLeft; 725 } 726 if (o.offsetTop) { 727 top += o.offsetTop; 728 } 729 } 730 offsetParent = o.offsetParent; 731 } 732 } 733 734 735 if (originalObject.offsetWidth) { 736 width = originalObject.offsetWidth; 737 } 738 if (originalObject.offsetHeight) { 739 height = originalObject.offsetHeight; 740 } 741 742 return {'left':left, 'top':top, 'width':width, 'height':height 743 }; 744 }; 745 746 // Retrieve the position of an object's center point 747 // ================================================= 748 pos.getCenter = function(o) { 749 var c = this.get(o); 750 if (c==null) { return null; } 751 c.left = c.left + (c.width/2); 752 c.top = c.top + (c.height/2); 753 return c; 754 }; 755 756 return pos; 757})();// CLASS CONSTRUCTOR 758// -------------------------------------------------------------------- 759var Popup = function(div, options) { 760 this.div = defined(div)?div:null; 761 this.index = Popup.maxIndex++; 762 this.ref = "Popup.objects["+this.index+"]"; 763 Popup.objects[this.index] = this; 764 // Store a reference to the DIV by id, also 765 if (typeof(this.div)=="string") { 766 Popup.objectsById[this.div] = this; 767 } 768 if (defined(this.div) && this.div!=null && defined(this.div.id)) { 769 Popup.objectsById[this.div.id] = this.div.id; 770 } 771 // Apply passed-in options 772 if (defined(options) && options!=null && typeof(options)=="object") { 773 for (var i in options) { 774 this[i] = options[i]; 775 } 776 } 777 return this; 778}; 779 780// CLASS PROPERTIES 781// -------------------------------------------------------------------- 782// Index of popup objects, to maintain a global reference if necessary 783Popup.maxIndex = 0; 784Popup.objects = {}; 785Popup.objectsById = {}; 786 787// The z-index value that popups will start at 788Popup.minZIndex = 10001; 789 790// Class names to assign to other objects 791Popup.screenClass = "PopupScreen"; 792Popup.iframeClass = "PopupIframe"; 793Popup.screenIframeClass = "PopupScreenIframe"; 794 795// CLASS METHODS 796// -------------------------------------------------------------------- 797 798// Hide all currently-visible non-modal dialogs 799Popup.hideAll = function() { 800 for (var i in Popup.objects) { 801 var p = Popup.objects[i]; 802 if (!p.modal && p.autoHide) { 803 p.hide(); 804 } 805 } 806}; 807// Catch global events as a trigger to hide auto-hide popups 808Event.add(document, "mouseup", Popup.hideAll, false); 809 810// A simple class method to show a popup without creating an instance 811Popup.show = function(divObject, referenceObject, position, options, modal) { 812 var popup; 813 if (defined(divObject)) { 814 popup = new Popup(divObject); 815 } 816 else { 817 popup = new Popup(); 818 popup.destroyDivOnHide = true; 819 } 820 if (defined(referenceObject)) { popup.reference = DOM.resolve(referenceObject); }
821 if (defined(position)) { popup.position = position; } 822 if (defined(options) && options!=null && typeof(options)=="object") { 823 for (var i in options) { 824 popup[i] = options[i]; 825 } 826 } 827 if (typeof(modal)=="boolean") { 828 popup.modal = modal; 829 } 830 popup.destroyObjectsOnHide = true; 831 popup.show(); 832 return popup; 833}; 834 835// A simple class method to show a modal popup 836Popup.showModal = function(divObject, referenceObject, position, options) { 837 Popup.show(divObject, referenceObject, position, options, true); 838}; 839 840// A method to retrieve a popup object based on a div ID 841Popup.get = function(divId) { 842 if (defined(Popup.objectsById[divId])) { 843 return Popup.objectsById[divId]; 844 } 845 return null; 846}; 847 848// A method to hide a popup based on a div id 849Popup.hide = function(divId) { 850 var popup = Popup.get(divId); 851 if (popup!=null) { 852 popup.hide(); 853 } 854}; 855 856// PROTOTYPE PROPERTIES 857// -------------------------------------------------------------------- 858Popup.prototype.content = null; 859Popup.prototype.className = "PopupDiv"; 860Popup.prototype.style = null; // Styles to be applied to the DIV 861Popup.prototype.width = null; 862Popup.prototype.height = null; 863Popup.prototype.top = null; 864Popup.prototype.left = null; 865Popup.prototype.offsetLeft = 0; 866Popup.prototype.offsetTop = 0; 867Popup.prototype.constrainToScreen = true; 868Popup.prototype.autoHide = true; 869Popup.prototype.useIframeShim = false; /*@cc_on @*/ /*@if (@_win32) {Popup.prototype.useIframeShim = true;} @end @*/ 870Popup.prototype.iframe = null; 871Popup.prototype.position = null; // vertical: "above top center bottom below", horizontal: "adjacent-left,left,center,right,adjacent-right" 872Popup.prototype.reference = null; 873Popup.prototype.modal = false; 874Popup.prototype.destroyDivOnHide = false;
875Popup.prototype.destroyObjectsOnHide = false; 876Popup.prototype.screen = null; 877Popup.prototype.screenIframeShim = null; 878Popup.prototype.screenOpacity=.4; 879Popup.prototype.screenColor="#cccccc"; 880 881// INSTANCE METHODS 882// -------------------------------------------------------------------- 883 884// Show the popup 885// -------------------------------------------------------------------- 886Popup.prototype.show = function(options, modal) { 887 this.modal = this.modal || (typeof(modal)=="boolean" && modal); 888 if (defined(options) && options!=null && typeof(options)=="object") { 889 for (var i in options) { 890 this[i] = options[i]; 891 } 892 } 893 this.div = DOM.resolve(this.div); 894 CSS.setStyle(this.div,'position','absolute'); 895 896 // If there is no div pre-defined to use, create one 897 if (this.div==null) { 898 this.div = this.createDiv(); 899 } 900 if (this.content!=null) { 901 this.div.innerHTML = this.content; 902 this.content = null; 903 } 904 if (this.className!=null) { 905 this.div.className = this.className; 906 } 907 if (this.style!=null) { 908 this.applyStyle(); 909 } 910 if (this.width!=null) { 911 this.div.style.width = this.width+"px"; 912 this.div.style.overflowX="auto"; 913 } 914 if (this.height!=null) { 915 this.div.style.height = this.height+"px"; 916 this.div.style.overflowY="auto"; 917 } 918 919 // Do the actual display - this is a separate method so display transitions can be implemented 920 this.transition(); 921 922 // Make sure clicks on the DIV don't bubble up to the document 923 this.div.onclick = function(e) { 924 Event.cancelBubble(Event.resolve(e)); 925 }; 926 this.div.onmouseup = this.div.onclick; 927 928 // Focus to the DIV if possible 929 if (this.modal && this.div.focus) { 930 this.div.focus(); 931 } 932}; 933 934// Show the popup but make it modal 935// -------------------------------------------------------------------- 936Popup.prototype.transition = function() { 937 if (this.modal) { 938 this.addScreen(); 939 } 940 941 // Make the DIV displayed but hidden so its size can be measured 942 CSS.setStyle(this.div,'visibility','hidden'); 943 CSS.setStyle(this.div,'display','block'); 944 945 // Position the popup 946 this.setPosition(); 947 948 // Add the shim if necessary 949 if (this.useIframeShim) { 950 this.addIframeShim(); 951 } 952 953 // Make sure the DIV is higher than the shim 954 this.div.style.zIndex = Popup.minZIndex++; 955 956 CSS.setStyle(this.div,'display','block'); 957 CSS.setStyle(this.div,'visibility','visible'); 958}; 959 960// Show the popup but make it modal 961// -------------------------------------------------------------------- 962Popup.prototype.showModal = function(options) { 963 this.show(options,true); 964}; 965 966// Apply user styles to the DIV 967// -------------------------------------------------------------------- 968Popup.prototype.applyStyle = function() { 969 if (this.div!=null && this.style!=null && typeof(this.style)=="object") { 970 for (var i in this.style) { 971 this.div.style[i] = this.style[i]; 972 } 973 } 974}; 975 976// Hide the popup 977// -------------------------------------------------------------------- 978Popup.prototype.hide = function() { 979 // If this was a temp object creating on-the-fly, then remove objects from the DOM so 980 // The document doesn't get littered with extra objects 981 if (this.destroyDivOnHide) { 982 DOM.removeNode(this.div); 983 this.div = null; 984 delete Popup.objects[this.id]; 985 } 986 else if (this.div!=null) { 987 CSS.setStyle(this.div,'display','none'); 988 } 989 990 if (this.destroyObjectsOnHide) { 991 DOM.removeNode(this.iframe); 992 DOM.removeNode(this.screen); 993 DOM.removeNode(this.screenIframeShim); 994 } 995 else { 996 if (this.iframe!=null) { 997 this.iframe.style.display = "none"; 998 } 999 if (this.screen!=null) { 1000 this.screen.style.display = "none"; 1001 } 1002 if (this.screenIframeShim!=null) { 1003 this.screenIframeShim.style.display = "none"; 1004 } 1005 } 1006}; 1007 1008// Util funcs for position 1009// -------------------------------------------------------------------- 1010Popup.prototype.setTop = function(top) { 1011 this.div.style.top = top+"px"; 1012}; 1013Popup.prototype.setLeft = function(left) { 1014 this.div.style.left = left+"px"; 1015}; 1016Popup.prototype.getTop = function() { 1017 return parseInt(CSS.getStyle(this.div,"top"),10); 1018}; 1019Popup.prototype.getLeft = function() { 1020 return parseInt(CSS.getStyle(this.div,"left"),10); 1021}; 1022 1023// All the logic to position the popup based on various criteria
1024// -------------------------------------------------------------------- 1025Popup.prototype.setPosition = function() { 1026 if (this.position!=null) { 1027 var m = this.position.match(/^(\S+)\s+(\S+)/); 1028 if (m!=null && m.length==3) { 1029 var v = m[1]; 1030 var h = m[2]; 1031 1032 var ref = this.reference; 1033 if (ref==null) { ref = Screen.getBody(); } 1034 var p = Position.get(ref); 1035 var refTop = p.top; 1036 var refLeft = p.left; 1037 var refWidth = DOM.getOuterWidth(ref); 1038 var refHeight = DOM.getOuterHeight(ref); 1039 1040 var width = DOM.getOuterWidth(this.div); 1041 var height = DOM.getOuterHeight(this.div); 1042 1043 var scrollLeft = Screen.getScrollLeft(); 1044 var scrollTop = Screen.getScrollTop(); 1045 1046 // Set vertical position relative to reference object 1047 if (v=="above") { this.setTop(refTop-height+this.offsetTop); } 1048 else if (v=="top") { this.setTop(refTop+this.offsetTop); } 1049 else if (v=="center") { this.setTop(refTop+(refHeight/2)-(height/2)+this.offsetTop); } 1050 else if (v=="bottom") { this.setTop(refTop+refHeight-height+this.offsetTop); } 1051 else if (v=="below") { this.setTop(refTop+refHeight+this.offsetTop); } 1052 1053 // Set horizontal position relative to reference object 1054 if (h=="adjacent-left") { this.setLeft(refLeft-width+this.offsetLeft); } 1055 else if (h=="left") { this.setLeft(refLeft+this.offsetLeft); } 1056 else if (h=="center") { this.setLeft(refLeft+(refWidth/2)-(width/2)+this.offsetLeft); } 1057 else if (h=="right") { this.setLeft(refLeft+refWidth-width+this.offsetLeft); } 1058 else if (h=="adjacent-right") { this.setLeft(refLeft+refWidth+this.offsetLeft); } 1059 } 1060 } 1061 else if (this.top==null && this.left==null) { 1062 this.center(); 1063 } 1064 else { 1065 if (this.top==null) { this.top=0; } 1066 if (this.left==null) { this.left=0; } 1067 this.div.style.top = this.top+this.offsetTop+"px"; 1068 this.div.style.left = this.left+this.offsetLeft+"px"; 1069 } 1070 1071 // Re-position to make sure it stays on the screen 1072 if (this.constrainToScreen) { 1073 this.fitToScreen(); 1074 } 1075}; 1076 1077// Append an object to the body 1078// -------------------------------------------------------------------- 1079Popup.prototype.appendToBody = function(o) { 1080 var body = Screen.getBody(); 1081 if (body && body.appendChild) { 1082 body.appendChild(o); 1083 } 1084}; 1085 1086// Create a new DIV object to be used for a popup 1087// -------------------------------------------------------------------- 1088Popup.prototype.createDiv = function() { 1089 if (document.createElement) { 1090 var d = document.createElement("DIV"); 1091 d.style.position="absolute"; 1092 d.style.display="block"; 1093 d.style.visibility="hidden"; 1094 this.appendToBody(d); 1095 return d; 1096 } 1097 alert("ERROR: Couldn't create DIV element in Popup.prototype.createDiv()"); 1098 return null; 1099}; 1100 1101// Create a new IFRAME object to be used behind the popup 1102// -------------------------------------------------------------------- 1103Popup.prototype.createIframe = function() { 1104 if (document.createElement) { 1105 var i= document.createElement("IFRAME"); 1106 i.style.position="absolute"; 1107 i.style.display="block"; 1108 i.style.visibility="hidden"; 1109 i.style.background="none"; 1110 this.appendToBody(i); 1111 return i; 1112 } 1113 else { 1114 alert("ERROR: Couldn't create IFRAME object in Popup.prototype.createIframe()"); 1115 } 1116}; 1117 1118// Add an IFRAME shim for the DIV 1119// -------------------------------------------------------------------- 1120Popup.prototype.addIframeShim = function() { 1121 if (this.iframe==null) { 1122 this.iframe = this.createIframe(); 1123 } 1124 this.iframe.className = Popup.iframeClass; 1125 CSS.setStyle(this.iframe,'top',this.getTop()+"px"); 1126 CSS.setStyle(this.iframe,'left',this.getLeft()+"px"); 1127 CSS.setStyle(this.iframe,'width',DOM.getOuterWidth(this.div) + "px"); 1128 CSS.setStyle(this.iframe,'height',DOM.getOuterHeight(this.div) + "px"); 1129 CSS.setStyle(this.iframe,'zIndex',Popup.minZIndex++); 1130 CSS.setStyle(this.iframe,'opacity',0); 1131 CSS.setStyle(this.iframe,'visibility','visible'); 1132 CSS.setStyle(this.iframe,'display','block'); 1133}; 1134 1135// Create a "screen" to make a popup modal 1136// -------------------------------------------------------------------- 1137Popup.prototype.addScreen = function() { 1138 if (this.screen==null) { 1139 this.screen = this.createDiv(); 1140 this.screen.style.top="0px"; 1141 this.screen.style.left="0px"; 1142 this.screen.style.backgroundColor = this.screenColor; 1143 this.screen.className=Popup.screenClass;; 1144 CSS.setStyle(this.screen,"opacity",this.screenOpacity); 1145 this.screen.onclick = function(e) { Event.cancelBubble(Event.resolve(e)); } 1146 } 1147 if (this.screenIframeShim==null) { 1148 this.screenIframeShim = this.createIframe(); 1149 this.screenIframeShim.style.top="0px"; 1150 this.screenIframeShim.style.left="0px"; 1151 this.screenIframeShim.className=Popup.screenIframeClass; 1152 CSS.setStyle(this.screenIframeShim,"opacity",0); 1153 } 1154 this.screen.style.width = Screen.getDocumentWidth()+"px"; 1155 this.screen.style.height = Screen.getDocumentHeight()+"px"; 1156 this.screenIframeShim.style.width = Screen.getDocumentWidth()+"px"; 1157 this.screenIframeShim.style.height = Screen.getDocumentHeight()+"px"; 1158 this.screenIframeShim.style.zIndex = Popup.minZIndex++; 1159 this.screenIframeShim.style.visibility="visible"; 1160 this.screenIframeShim.style.display="block"; 1161 this.screen.style.zIndex = Popup.minZIndex++; 1162 this.screen.style.visibility="visible"; 1163 this.screen.style.display="block"; 1164}; 1165 1166// Re-position the DIV so it stays on the screen 1167// -------------------------------------------------------------------- 1168Popup.prototype.fitToScreen = function() { 1169 var width = DOM.getOuterWidth(this.div); 1170 var height = DOM.getOuterHeight(this.div); 1171 var top = this.getTop(); 1172 var left = this.getLeft(); 1173 1174 var clientWidth = Screen.getViewportWidth();
1175 var clientHeight = Screen.getViewportHeight(); 1176 1177 var scrollLeft = Screen.getScrollLeft(); 1178 var scrollTop = Screen.getScrollTop(); 1179 1180 if (top-scrollTop+height>clientHeight) { 1181 top = top - ((top+height) - (scrollTop+clientHeight)); 1182 this.div.style.top = top + "px"; 1183 } 1184 if (left-scrollLeft+width>clientWidth) { 1185 left = left - ((left+width) - (scrollLeft+clientWidth)); 1186 this.div.style.left = left + "px"; 1187 } 1188 if (top<scrollTop) { 1189 this.div.style.top=scrollTop+"px"; 1190 } 1191 if (left<scrollLeft) { 1192 this.div.style.left=scrollLeft+"px"; 1193 } 1194}; 1195 1196// Center the DIV object 1197// -------------------------------------------------------------------- 1198Popup.prototype.center = function() { 1199 var left = DOM.getOuterWidth(this.div); 1200 var top = DOM.getOuterHeight(this.div); 1201 if (isNaN(left)) { left=0; } 1202 if (isNaN(top)) { top=0; } 1203 var clientW = Screen.getViewportWidth(); 1204 var clientH = Screen.getViewportHeight(); 1205 if (clientW!=null && clientH!=null) { 1206 top = (clientH-top)/2; 1207 left = (clientW-left)/2; 1208 } 1209 top += Screen.getScrollTop(); 1210 left += Screen.getScrollLeft(); 1211 1212 this.div.style.top = top+this.offsetTop+"px"; 1213 this.div.style.left = left+this.offsetLeft+"px"; 1214}; 1215
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.