ScrollView: Avoid unintentional contraints on X/Y properties
[platform/core/uifw/dali-toolkit.git] / automated-tests / style / popup.js
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 /* ******************************************************************* */
16 var 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
22 function 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
27 function 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
32 function 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
38 function 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
64 function 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
83 Array.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 /* ******************************************************************* */
96 var 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 /* ******************************************************************* */
203 var 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
357 var 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 /* ******************************************************************* */
434 var 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.innerHeight))?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
617 var 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 // --------------------------------------------------------------------
759 var 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
783 Popup.maxIndex = 0;
784 Popup.objects = {};
785 Popup.objectsById = {};
786
787 // The z-index value that popups will start at
788 Popup.minZIndex = 101;
789
790 // Class names to assign to other objects
791 Popup.screenClass = "PopupScreen";
792 Popup.iframeClass = "PopupIframe";
793 Popup.screenIframeClass = "PopupScreenIframe";
794
795 // CLASS METHODS
796 // --------------------------------------------------------------------
797
798 // Hide all currently-visible non-modal dialogs
799 Popup.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
808 Event.add(document, "mouseup", Popup.hideAll, false);
809
810 // A simple class method to show a popup without creating an instance
811 Popup.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
836 Popup.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
841 Popup.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
849 Popup.hide = function(divId) {
850         var popup = Popup.get(divId);
851         if (popup!=null) {
852                 popup.hide();
853         }
854 };
855
856 // PROTOTYPE PROPERTIES
857 // --------------------------------------------------------------------
858 Popup.prototype.content = null;
859 Popup.prototype.className = "PopupDiv";
860 Popup.prototype.style = null; // Styles to be applied to the DIV
861 Popup.prototype.width = null;
862 Popup.prototype.height = null;
863 Popup.prototype.top = null;
864 Popup.prototype.left = null;
865 Popup.prototype.offsetLeft = 0;
866 Popup.prototype.offsetTop = 0;
867 Popup.prototype.constrainToScreen = true;
868 Popup.prototype.autoHide = true;
869 Popup.prototype.useIframeShim = false; /*@cc_on @*/ /*@if (@_win32) {Popup.prototype.useIframeShim = true;} @end @*/ 
870 Popup.prototype.iframe = null;
871 Popup.prototype.position = null; // vertical: "above top center bottom below", horizontal: "adjacent-left,left,center,right,adjacent-right"
872 Popup.prototype.reference = null;
873 Popup.prototype.modal = false;
874 Popup.prototype.destroyDivOnHide = false;
875 Popup.prototype.destroyObjectsOnHide = false;
876 Popup.prototype.screen = null;
877 Popup.prototype.screenIframeShim = null;
878 Popup.prototype.screenOpacity=.4;
879 Popup.prototype.screenColor="#cccccc";
880
881 // INSTANCE METHODS
882 // --------------------------------------------------------------------
883
884 // Show the popup
885 // --------------------------------------------------------------------
886 Popup.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 // --------------------------------------------------------------------
936 Popup.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 // --------------------------------------------------------------------
962 Popup.prototype.showModal = function(options) {
963         this.show(options,true);
964 };
965
966 // Apply user styles to the DIV
967 // --------------------------------------------------------------------
968 Popup.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 // --------------------------------------------------------------------
978 Popup.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 // --------------------------------------------------------------------
1010 Popup.prototype.setTop = function(top) {
1011         this.div.style.top = top+"px";
1012 };
1013 Popup.prototype.setLeft = function(left) {
1014         this.div.style.left = left+"px";
1015 };
1016 Popup.prototype.getTop = function() {
1017         return parseInt(CSS.getStyle(this.div,"top"),10);
1018 };
1019 Popup.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 // --------------------------------------------------------------------
1025 Popup.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 // --------------------------------------------------------------------
1079 Popup.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 // --------------------------------------------------------------------
1088 Popup.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 // --------------------------------------------------------------------
1103 Popup.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 // --------------------------------------------------------------------
1120 Popup.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 // --------------------------------------------------------------------
1137 Popup.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 // --------------------------------------------------------------------
1168 Popup.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 // --------------------------------------------------------------------
1198 Popup.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