Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / core / src / dom / Element.scroll.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.Element
17  */
18 Ext.override(Ext.Element, {
19     /**
20      * Returns true if this element is scrollable.
21      * @return {Boolean}
22      */
23     isScrollable : function(){
24         var dom = this.dom;
25         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
26     },
27
28     /**
29      * Returns the current scroll position of the element.
30      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
31      */
32     getScroll : function() {
33         var d = this.dom, 
34             doc = document,
35             body = doc.body,
36             docElement = doc.documentElement,
37             l,
38             t,
39             ret;
40
41         if (d == doc || d == body) {
42             if (Ext.isIE && Ext.isStrict) {
43                 l = docElement.scrollLeft; 
44                 t = docElement.scrollTop;
45             } else {
46                 l = window.pageXOffset;
47                 t = window.pageYOffset;
48             }
49             ret = {
50                 left: l || (body ? body.scrollLeft : 0), 
51                 top : t || (body ? body.scrollTop : 0)
52             };
53         } else {
54             ret = {
55                 left: d.scrollLeft, 
56                 top : d.scrollTop
57             };
58         }
59         
60         return ret;
61     },
62     
63     /**
64      * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
65      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
66      * @param {Number} value The new scroll value
67      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
68      * @return {Ext.Element} this
69      */
70     scrollTo : function(side, value, animate) {
71         //check if we're scrolling top or left
72         var top = /top/i.test(side),
73             me = this,
74             dom = me.dom,
75             obj = {},
76             prop;
77         if (!animate || !me.anim) {
78             // just setting the value, so grab the direction
79             prop = 'scroll' + (top ? 'Top' : 'Left');
80             dom[prop] = value;
81         }
82         else {
83             if (!Ext.isObject(animate)) {
84                 animate = {};
85             }
86             obj['scroll' + (top ? 'Top' : 'Left')] = value;
87             me.animate(Ext.applyIf({
88                 to: obj
89             }, animate));
90         }
91         return me;
92     },
93
94     /**
95      * Scrolls this element into view within the passed container.
96      * @param {String/HTMLElement/Ext.Element} container (optional) The container element to scroll (defaults to document.body).  Should be a
97      * string (id), dom node, or Ext.Element.
98      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
99      * @return {Ext.Element} this
100      */
101     scrollIntoView : function(container, hscroll) {
102         container = Ext.getDom(container) || Ext.getBody().dom;
103         var el = this.dom,
104             offsets = this.getOffsetsTo(container),
105             // el's box
106             left = offsets[0] + container.scrollLeft,
107             top = offsets[1] + container.scrollTop,
108             bottom = top + el.offsetHeight,
109             right = left + el.offsetWidth,
110             // ct's box
111             ctClientHeight = container.clientHeight,
112             ctScrollTop = parseInt(container.scrollTop, 10),
113             ctScrollLeft = parseInt(container.scrollLeft, 10),
114             ctBottom = ctScrollTop + ctClientHeight,
115             ctRight = ctScrollLeft + container.clientWidth;
116
117         if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
118             container.scrollTop = top;
119         } else if (bottom > ctBottom) {
120             container.scrollTop = bottom - ctClientHeight;
121         }
122         // corrects IE, other browsers will ignore
123         container.scrollTop = container.scrollTop;
124
125         if (hscroll !== false) {
126             if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
127                 container.scrollLeft = left;
128             }
129             else if (right > ctRight) {
130                 container.scrollLeft = right - container.clientWidth;
131             }
132             container.scrollLeft = container.scrollLeft;
133         }
134         return this;
135     },
136
137     // private
138     scrollChildIntoView : function(child, hscroll) {
139         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
140     },
141
142     /**
143      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
144      * within this element's scrollable range.
145      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
146      * @param {Number} distance How far to scroll the element in pixels
147      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
148      * @return {Boolean} Returns true if a scroll was triggered or false if the element
149      * was scrolled as far as it could go.
150      */
151      scroll : function(direction, distance, animate) {
152         if (!this.isScrollable()) {
153             return false;
154         }
155         var el = this.dom,
156             l = el.scrollLeft, t = el.scrollTop,
157             w = el.scrollWidth, h = el.scrollHeight,
158             cw = el.clientWidth, ch = el.clientHeight,
159             scrolled = false, v,
160             hash = {
161                 l: Math.min(l + distance, w-cw),
162                 r: v = Math.max(l - distance, 0),
163                 t: Math.max(t - distance, 0),
164                 b: Math.min(t + distance, h-ch)
165             };
166             hash.d = hash.b;
167             hash.u = hash.t;
168
169         direction = direction.substr(0, 1);
170         if ((v = hash[direction]) > -1) {
171             scrolled = true;
172             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
173         }
174         return scrolled;
175     }
176 });