]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/dom/dom-screen.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / dom / dom-screen.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('dom-screen', function(Y) {
9
10 (function(Y) {
11
12 /**
13  * Adds position and region management functionality to DOM.
14  * @module dom
15  * @submodule dom-screen
16  * @for DOM
17  */
18
19 var DOCUMENT_ELEMENT = 'documentElement',
20     COMPAT_MODE = 'compatMode',
21     POSITION = 'position',
22     FIXED = 'fixed',
23     RELATIVE = 'relative',
24     LEFT = 'left',
25     TOP = 'top',
26     _BACK_COMPAT = 'BackCompat',
27     MEDIUM = 'medium',
28     BORDER_LEFT_WIDTH = 'borderLeftWidth',
29     BORDER_TOP_WIDTH = 'borderTopWidth',
30     GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
31     GET_COMPUTED_STYLE = 'getComputedStyle',
32
33     Y_DOM = Y.DOM,
34
35     // TODO: how about thead/tbody/tfoot/tr?
36     // TODO: does caption matter?
37     RE_TABLE = /^t(?:able|d|h)$/i,
38
39     SCROLL_NODE;
40
41 if (Y.UA.ie) {
42     if (Y.config.doc[COMPAT_MODE] !== 'quirks') {
43         SCROLL_NODE = DOCUMENT_ELEMENT; 
44     } else {
45         SCROLL_NODE = 'body';
46     }
47 }
48
49 Y.mix(Y_DOM, {
50     /**
51      * Returns the inner height of the viewport (exludes scrollbar). 
52      * @method winHeight
53      * @return {Number} The current height of the viewport.
54      */
55     winHeight: function(node) {
56         var h = Y_DOM._getWinSize(node).height;
57         return h;
58     },
59
60     /**
61      * Returns the inner width of the viewport (exludes scrollbar). 
62      * @method winWidth
63      * @return {Number} The current width of the viewport.
64      */
65     winWidth: function(node) {
66         var w = Y_DOM._getWinSize(node).width;
67         return w;
68     },
69
70     /**
71      * Document height 
72      * @method docHeight
73      * @return {Number} The current height of the document.
74      */
75     docHeight:  function(node) {
76         var h = Y_DOM._getDocSize(node).height;
77         return Math.max(h, Y_DOM._getWinSize(node).height);
78     },
79
80     /**
81      * Document width 
82      * @method docWidth
83      * @return {Number} The current width of the document.
84      */
85     docWidth:  function(node) {
86         var w = Y_DOM._getDocSize(node).width;
87         return Math.max(w, Y_DOM._getWinSize(node).width);
88     },
89
90     /**
91      * Amount page has been scroll horizontally 
92      * @method docScrollX
93      * @return {Number} The current amount the screen is scrolled horizontally.
94      */
95     docScrollX: function(node, doc) {
96         doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
97         var dv = doc.defaultView,
98             pageOffset = (dv) ? dv.pageXOffset : 0;
99         return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft, pageOffset);
100     },
101
102     /**
103      * Amount page has been scroll vertically 
104      * @method docScrollY
105      * @return {Number} The current amount the screen is scrolled vertically.
106      */
107     docScrollY:  function(node, doc) {
108         doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
109         var dv = doc.defaultView,
110             pageOffset = (dv) ? dv.pageYOffset : 0;
111         return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop, pageOffset);
112     },
113
114     /**
115      * Gets the current position of an element based on page coordinates. 
116      * Element must be part of the DOM tree to have page coordinates
117      * (display:none or elements not appended return false).
118      * @method getXY
119      * @param element The target element
120      * @return {Array} The XY position of the element
121
122      TODO: test inDocument/display?
123      */
124     getXY: function() {
125         if (Y.config.doc[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
126             return function(node) {
127                 var xy = null,
128                     scrollLeft,
129                     scrollTop,
130                     box,
131                     off1, off2,
132                     bLeft, bTop,
133                     mode,
134                     doc,
135                     inDoc,
136                     rootNode;
137
138                 if (node && node.tagName) {
139                     doc = node.ownerDocument;
140                     rootNode = doc[DOCUMENT_ELEMENT];
141
142                     // inline inDoc check for perf
143                     if (rootNode.contains) {
144                         inDoc = rootNode.contains(node); 
145                     } else {
146                         inDoc = Y.DOM.contains(rootNode, node);
147                     }
148
149                     if (inDoc) {
150                         scrollLeft = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollLeft : Y_DOM.docScrollX(node, doc);
151                         scrollTop = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollTop : Y_DOM.docScrollY(node, doc);
152                         box = node[GET_BOUNDING_CLIENT_RECT]();
153                         xy = [box.left, box.top];
154
155                             if (Y.UA.ie) {
156                                 off1 = 2;
157                                 off2 = 2;
158                                 mode = doc[COMPAT_MODE];
159                                 bLeft = Y_DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH);
160                                 bTop = Y_DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH);
161
162                                 if (Y.UA.ie === 6) {
163                                     if (mode !== _BACK_COMPAT) {
164                                         off1 = 0;
165                                         off2 = 0;
166                                     }
167                                 }
168                                 
169                                 if ((mode == _BACK_COMPAT)) {
170                                     if (bLeft !== MEDIUM) {
171                                         off1 = parseInt(bLeft, 10);
172                                     }
173                                     if (bTop !== MEDIUM) {
174                                         off2 = parseInt(bTop, 10);
175                                     }
176                                 }
177                                 
178                                 xy[0] -= off1;
179                                 xy[1] -= off2;
180
181                             }
182
183                         if ((scrollTop || scrollLeft)) {
184                             if (!Y.UA.ios || (Y.UA.ios >= 4.2)) {
185                                 xy[0] += scrollLeft;
186                                 xy[1] += scrollTop;
187                             }
188                             
189                         }
190                     } else {
191                         xy = Y_DOM._getOffset(node);       
192                     }
193                 }
194                 return xy;                   
195             }
196         } else {
197             return function(node) { // manually calculate by crawling up offsetParents
198                 //Calculate the Top and Left border sizes (assumes pixels)
199                 var xy = null,
200                     doc,
201                     parentNode,
202                     bCheck,
203                     scrollTop,
204                     scrollLeft;
205
206                 if (node) {
207                     if (Y_DOM.inDoc(node)) {
208                         xy = [node.offsetLeft, node.offsetTop];
209                         doc = node.ownerDocument;
210                         parentNode = node;
211                         // TODO: refactor with !! or just falsey
212                         bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
213
214                         // TODO: worth refactoring for TOP/LEFT only?
215                         while ((parentNode = parentNode.offsetParent)) {
216                             xy[0] += parentNode.offsetLeft;
217                             xy[1] += parentNode.offsetTop;
218                             if (bCheck) {
219                                 xy = Y_DOM._calcBorders(parentNode, xy);
220                             }
221                         }
222
223                         // account for any scrolled ancestors
224                         if (Y_DOM.getStyle(node, POSITION) != FIXED) {
225                             parentNode = node;
226
227                             while ((parentNode = parentNode.parentNode)) {
228                                 scrollTop = parentNode.scrollTop;
229                                 scrollLeft = parentNode.scrollLeft;
230
231                                 //Firefox does something funky with borders when overflow is not visible.
232                                 if (Y.UA.gecko && (Y_DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
233                                         xy = Y_DOM._calcBorders(parentNode, xy);
234                                 }
235                                 
236
237                                 if (scrollTop || scrollLeft) {
238                                     xy[0] -= scrollLeft;
239                                     xy[1] -= scrollTop;
240                                 }
241                             }
242                             xy[0] += Y_DOM.docScrollX(node, doc);
243                             xy[1] += Y_DOM.docScrollY(node, doc);
244
245                         } else {
246                             //Fix FIXED position -- add scrollbars
247                             xy[0] += Y_DOM.docScrollX(node, doc);
248                             xy[1] += Y_DOM.docScrollY(node, doc);
249                         }
250                     } else {
251                         xy = Y_DOM._getOffset(node);
252                     }
253                 }
254
255                 return xy;                
256             };
257         }
258     }(),// NOTE: Executing for loadtime branching
259
260     /**
261      * Gets the current X position of an element based on page coordinates. 
262      * Element must be part of the DOM tree to have page coordinates
263      * (display:none or elements not appended return false).
264      * @method getX
265      * @param element The target element
266      * @return {Int} The X position of the element
267      */
268
269     getX: function(node) {
270         return Y_DOM.getXY(node)[0];
271     },
272
273     /**
274      * Gets the current Y position of an element based on page coordinates. 
275      * Element must be part of the DOM tree to have page coordinates
276      * (display:none or elements not appended return false).
277      * @method getY
278      * @param element The target element
279      * @return {Int} The Y position of the element
280      */
281
282     getY: function(node) {
283         return Y_DOM.getXY(node)[1];
284     },
285
286     /**
287      * Set the position of an html element in page coordinates.
288      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
289      * @method setXY
290      * @param element The target element
291      * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
292      * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
293      */
294     setXY: function(node, xy, noRetry) {
295         var setStyle = Y_DOM.setStyle,
296             pos,
297             delta,
298             newXY,
299             currentXY;
300
301         if (node && xy) {
302             pos = Y_DOM.getStyle(node, POSITION);
303
304             delta = Y_DOM._getOffset(node);       
305             if (pos == 'static') { // default to relative
306                 pos = RELATIVE;
307                 setStyle(node, POSITION, pos);
308             }
309             currentXY = Y_DOM.getXY(node);
310
311             if (xy[0] !== null) {
312                 setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
313             }
314
315             if (xy[1] !== null) {
316                 setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
317             }
318
319             if (!noRetry) {
320                 newXY = Y_DOM.getXY(node);
321                 if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
322                     Y_DOM.setXY(node, xy, true); 
323                 }
324             }
325           
326         } else {
327         }
328     },
329
330     /**
331      * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
332      * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
333      * @method setX
334      * @param element The target element
335      * @param {Int} x The X values for new position (coordinates are page-based)
336      */
337     setX: function(node, x) {
338         return Y_DOM.setXY(node, [x, null]);
339     },
340
341     /**
342      * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
343      * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
344      * @method setY
345      * @param element The target element
346      * @param {Int} y The Y values for new position (coordinates are page-based)
347      */
348     setY: function(node, y) {
349         return Y_DOM.setXY(node, [null, y]);
350     },
351
352     /**
353      * @method swapXY
354      * @description Swap the xy position with another node
355      * @param {Node} node The node to swap with
356      * @param {Node} otherNode The other node to swap with
357      * @return {Node}
358      */
359     swapXY: function(node, otherNode) {
360         var xy = Y_DOM.getXY(node);
361         Y_DOM.setXY(node, Y_DOM.getXY(otherNode));
362         Y_DOM.setXY(otherNode, xy);
363     },
364
365     _calcBorders: function(node, xy2) {
366         var t = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
367             l = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
368         if (Y.UA.gecko) {
369             if (RE_TABLE.test(node.tagName)) {
370                 t = 0;
371                 l = 0;
372             }
373         }
374         xy2[0] += l;
375         xy2[1] += t;
376         return xy2;
377     },
378
379     _getWinSize: function(node, doc) {
380         doc  = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc;
381         var win = doc.defaultView || doc.parentWindow,
382             mode = doc[COMPAT_MODE],
383             h = win.innerHeight,
384             w = win.innerWidth,
385             root = doc[DOCUMENT_ELEMENT];
386
387         if ( mode && !Y.UA.opera ) { // IE, Gecko
388             if (mode != 'CSS1Compat') { // Quirks
389                 root = doc.body; 
390             }
391             h = root.clientHeight;
392             w = root.clientWidth;
393         }
394         return { height: h, width: w };
395     },
396
397     _getDocSize: function(node) {
398         var doc = (node) ? Y_DOM._getDoc(node) : Y.config.doc,
399             root = doc[DOCUMENT_ELEMENT];
400
401         if (doc[COMPAT_MODE] != 'CSS1Compat') {
402             root = doc.body;
403         }
404
405         return { height: root.scrollHeight, width: root.scrollWidth };
406     }
407 });
408
409 })(Y);
410 (function(Y) {
411 var TOP = 'top',
412     RIGHT = 'right',
413     BOTTOM = 'bottom',
414     LEFT = 'left',
415
416     getOffsets = function(r1, r2) {
417         var t = Math.max(r1[TOP], r2[TOP]),
418             r = Math.min(r1[RIGHT], r2[RIGHT]),
419             b = Math.min(r1[BOTTOM], r2[BOTTOM]),
420             l = Math.max(r1[LEFT], r2[LEFT]),
421             ret = {};
422         
423         ret[TOP] = t;
424         ret[RIGHT] = r;
425         ret[BOTTOM] = b;
426         ret[LEFT] = l;
427         return ret;
428     },
429
430     DOM = Y.DOM;
431
432 Y.mix(DOM, {
433     /**
434      * Returns an Object literal containing the following about this element: (top, right, bottom, left)
435      * @for DOM
436      * @method region
437      * @param {HTMLElement} element The DOM element. 
438      * @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
439      */
440     region: function(node) {
441         var xy = DOM.getXY(node),
442             ret = false;
443         
444         if (node && xy) {
445             ret = DOM._getRegion(
446                 xy[1], // top
447                 xy[0] + node.offsetWidth, // right
448                 xy[1] + node.offsetHeight, // bottom
449                 xy[0] // left
450             );
451         }
452
453         return ret;
454     },
455
456     /**
457      * Find the intersect information for the passes nodes.
458      * @method intersect
459      * @for DOM
460      * @param {HTMLElement} element The first element 
461      * @param {HTMLElement | Object} element2 The element or region to check the interect with
462      * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
463      * @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
464      */
465     intersect: function(node, node2, altRegion) {
466         var r = altRegion || DOM.region(node), region = {},
467             n = node2,
468             off;
469
470         if (n.tagName) {
471             region = DOM.region(n);
472         } else if (Y.Lang.isObject(node2)) {
473             region = node2;
474         } else {
475             return false;
476         }
477         
478         off = getOffsets(region, r);
479         return {
480             top: off[TOP],
481             right: off[RIGHT],
482             bottom: off[BOTTOM],
483             left: off[LEFT],
484             area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
485             yoff: ((off[BOTTOM] - off[TOP])),
486             xoff: (off[RIGHT] - off[LEFT]),
487             inRegion: DOM.inRegion(node, node2, false, altRegion)
488         };
489         
490     },
491     /**
492      * Check if any part of this node is in the passed region
493      * @method inRegion
494      * @for DOM
495      * @param {Object} node2 The node to get the region from or an Object literal of the region
496      * $param {Boolean} all Should all of the node be inside the region
497      * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
498      * @return {Boolean} True if in region, false if not.
499      */
500     inRegion: function(node, node2, all, altRegion) {
501         var region = {},
502             r = altRegion || DOM.region(node),
503             n = node2,
504             off;
505
506         if (n.tagName) {
507             region = DOM.region(n);
508         } else if (Y.Lang.isObject(node2)) {
509             region = node2;
510         } else {
511             return false;
512         }
513             
514         if (all) {
515             return (
516                 r[LEFT]   >= region[LEFT]   &&
517                 r[RIGHT]  <= region[RIGHT]  && 
518                 r[TOP]    >= region[TOP]    && 
519                 r[BOTTOM] <= region[BOTTOM]  );
520         } else {
521             off = getOffsets(region, r);
522             if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
523                 return true;
524             } else {
525                 return false;
526             }
527             
528         }
529     },
530
531     /**
532      * Check if any part of this element is in the viewport
533      * @method inViewportRegion
534      * @for DOM
535      * @param {HTMLElement} element The DOM element. 
536      * @param {Boolean} all Should all of the node be inside the region
537      * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
538      * @return {Boolean} True if in region, false if not.
539      */
540     inViewportRegion: function(node, all, altRegion) {
541         return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
542             
543     },
544
545     _getRegion: function(t, r, b, l) {
546         var region = {};
547
548         region[TOP] = region[1] = t;
549         region[LEFT] = region[0] = l;
550         region[BOTTOM] = b;
551         region[RIGHT] = r;
552         region.width = region[RIGHT] - region[LEFT];
553         region.height = region[BOTTOM] - region[TOP];
554
555         return region;
556     },
557
558     /**
559      * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
560      * @method viewportRegion
561      * @for DOM
562      * @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
563      */
564     viewportRegion: function(node) {
565         node = node || Y.config.doc.documentElement;
566         var ret = false,
567             scrollX,
568             scrollY;
569
570         if (node) {
571             scrollX = DOM.docScrollX(node);
572             scrollY = DOM.docScrollY(node);
573
574             ret = DOM._getRegion(scrollY, // top
575                 DOM.winWidth(node) + scrollX, // right
576                 scrollY + DOM.winHeight(node), // bottom
577                 scrollX); // left
578         }
579
580         return ret;
581     }
582 });
583 })(Y);
584
585
586 }, '3.3.0' ,{requires:['dom-base', 'dom-style', 'event-base']});