remove debugging code
[roojs1] / ux / Tscroll.js
index e69de29..1c60a8f 100644 (file)
@@ -0,0 +1,395 @@
+/**
+ *
+ * usage:
+ *
+ * new Roo.ux.TouchScroll( { el : id| dom element | roo element } )
+ *
+ *
+ */
+
+
+Roo.ux.TouchScroll = function (cfg) {
+    Roo.apply(this,cfg);
+    this.el = Roo.get(this.el);
+    this.init();
+}
+    
+Roo.apply(Roo.ux.TouchScroll.prototype, {
+    
+       // Define default scroll settings
+        
+        y: 0,
+        scrollHeight: 0,
+        elastic: !navigator.userAgent.match(/android/i),
+        momentum: true,
+        elasticDamp: 0.6,
+        elasticTime: 50,
+        reboundTime: 400,
+        momentumDamp: 0.9,
+        momentumTime: 300,
+        iPadMomentumDamp: 0.95,
+        iPadMomentumTime: 1200,
+        touchTags: ['select', 'input', 'textarea'],
+       
+        _init : false,
+        
+        init: function( ) {
+                
+                
+              // Prevent double-init, just update instead
+            if (this._init) {
+                return this.update();
+            }
+            
+            this._init = true;
+                        
+            // Define element variables
+            var 
+                scrollY = -this.el.getY(),
+                touchY = 0,
+                movedY = 0,
+                pollY = 0,
+                height = 0,
+                maxHeight = 0,
+                scrollHeight = 0,
+                scrolling = false,
+                bouncing = false,
+                moved = false,
+                timeoutID,
+                isiPad = navigator.platform.match(/ipad/i) ? true : false,
+                hasMatrix = 'WebKitCSSMatrix' in window,
+                has3d = hasMatrix && 'm11' in new WebKitCSSMatrix();
+                        
+                // Keep bottom of scroll area at the bottom on resize
+                var update = this.update = function() {
+                        height = el.getHeight();
+                        if (el.dom.scrollHeight) {
+                                scrollHeight = el.dom.scrollHeight;
+                        } else {
+                                scrollHeight = el.dom.getAttribute('scrollHeight');
+                        }
+                        if (scrollHeight < height) {
+                                scrollHeight = height;
+                        }
+                        maxHeight = height - scrollHeight;
+                        clearTimeout(timeoutID);
+                        clampScroll(false);
+                };
+                        
+                // Set up initial variables
+                update();
+                
+                        // Set up transform CSS
+                this.el.setStyle({
+                    '-webkit-transition-property': '-webkit-transform',
+                    '-webkit-transition-timing-function': 'cubic-bezier(0,0,0.2,1)',
+                    '-webkit-transition-duration': '0',
+                    '-webkit-transform': cssTranslate(scrollY)
+                });
+                        
+                        // Listen for screen size change event
+                window.addEventListener('onorientationchange' in window ?
+                                'orientationchange' : 'resize', update, false);
+                        
+                // Listen for touch events
+                this.el.on('touchstart.touchScroll', touchStart);
+                this.el.on('touchmove.touchScroll', touchMove);
+                this.el.on('touchend.touchScroll touchcancel.touchScroll', touchEnd);
+                this.el.on('webkitTransitionEnd.touchScroll', transitionEnd);
+                        
+                        // Set the position of the scroll area using transform CSS
+                var setPosition = this.setPosition = function(y) {
+                        scrollY = y;
+                        this.el.setStyle('-webkit-transform', cssTranslate(scrollY));
+                };
+                
+                        // Transform using a 3D translate if available
+                function cssTranslate(y) {
+                        return 'translate' + (has3d ? '3d(0,' : '(0,') + y + 'px' + (has3d ? ',0)' : ')');
+                }
+                        
+                        // Set CSS transition time
+                function setTransitionTime(time) {
+                        time = time || '0';
+                        this.el.setStyle('-webkit-transition-duration', time + 'ms');
+                }
+    
+                            // Get the actual pixel position made by transform CSS
+                function getPosition() {
+                        if (hasMatrix) {
+                                var transform = window.getComputedStyle(this.el.dom).webkitTransform;
+                                if (!!transform && transform !== 'none') {
+                                        var matrix = new WebKitCSSMatrix(transform);
+                                        return matrix.f;
+                                }
+                        }
+                        return scrollY;
+                }
+                            
+                    // Expose getPosition API
+                this.getPosition = function() {
+                        return getPosition();
+                };
+
+                // Bounce back to the bounds after momentum scrolling
+                function reboundScroll() {
+                        if (scrollY > 0) {
+                                scrollTo(0, o.reboundTime);
+                        } else if (scrollY < maxHeight) {
+                                scrollTo(maxHeight, o.reboundTime);
+                        }
+                }
+
+                // Stop everything once the CSS transition in complete
+                function transitionEnd() {
+                        if (bouncing) {
+                                bouncing = false;
+                                reboundScroll();
+                        }
+
+                        clearTimeout(timeoutID);
+                }
+        
+                // Limit the scrolling to within the bounds
+                function clampScroll(poll) {
+                        if (!hasMatrix || bouncing) {
+                                return;
+                        }
+    
+                        var oldY = pollY;
+                        pollY = getPosition();
+                        
+                        if (pollY > 0) {
+                                if (o.elastic) {
+                                        // Slow down outside top bound
+                                        bouncing = true;
+                                        scrollY = 0;
+                                        momentumScroll(pollY - oldY, o.elasticDamp, 1, height, o.elasticTime);
+                                } else {
+                                        // Stop outside top bound
+                                        setTransitionTime(0);
+                                        setPosition(0);
+                                }
+                        } else if (pollY < maxHeight) {
+                                if (o.elastic) {
+                                        // Slow down outside bottom bound
+                                        bouncing = true;
+                                        scrollY = maxHeight;
+                                        momentumScroll(pollY - oldY, o.elasticDamp, 1, height, o.elasticTime);
+                                } else {
+                                        // Stop outside bottom bound
+                                        setTransitionTime(0);
+                                        setPosition(maxHeight);
+                                }
+                        } else if (poll) {
+                                // Poll the computed position to check if element is out of bounds
+                                timeoutID = setTimeout(clampScroll, 20, true);
+                        }
+                }
+        
+        // Animate to a position using CSS
+                function scrollTo(destY, time) {
+                        if (destY === scrollY) {
+                                return;
+                        }
+                        
+                        moved = true;
+                        setTransitionTime(time);
+                        setPosition(destY);
+                }
+        
+                // Perform a momentum-based scroll using CSS
+                function momentumScroll(d, k, minDist, maxDist, t) {
+                        var ad = Math.abs(d),
+                                dy = 0;
+                        
+                        // Calculate the total distance
+                        while (ad > 0.1) {
+                                ad *= k;
+                                dy += ad;
+                        }
+                        
+                        // Limit to within min and max distances
+                        if (dy > maxDist) {
+                                dy = maxDist;
+                        }
+                        if (dy > minDist) {
+                                if (d < 0) {
+                                        dy = -dy;
+                                }
+                                
+                                dy += scrollY;
+                                
+                                // If outside the bounds, don't go too far
+                                if (height > 0) {
+                                        if (dy > height * 2) {
+                                                var ody = dy;
+                                                dy = height * 2;
+                                        } else if (dy < maxHeight - height * 2) {
+                                                dy = maxHeight - height * 2;
+                                        }
+                                }
+                        
+                                // Perform scroll
+                                scrollTo(Math.round(dy), t);
+                        }
+                        
+                        clampScroll(true);
+                }
+        
+                // Get the touch points from this event
+                function getTouches(e) {
+                        if (e.originalEvent) {
+                                if (e.originalEvent.touches && e.originalEvent.touches.length) {
+                                        return e.originalEvent.touches;
+                                } else if (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length) {
+                                        return e.originalEvent.changedTouches;
+                                }
+                        }
+                        return e.touches;
+                }
+                
+                // Dispatches a fake mouse event from a touch event
+                function dispatchMouseEvent(name, touch, target) {
+                        var e = document.createEvent('MouseEvent');
+                        e.initMouseEvent(name, true, true, touch.view, 1,
+                                        touch.screenX, touch.screenY,
+                                        touch.clientX, touch.clientY,
+                                        false, false, false, false, 0, null);
+                        target.dispatchEvent(e);
+                }
+        
+                // Find the root node of this target
+                function getRootNode(target) {
+                        while (target.nodeType !== 1) {
+                                target = target.parentNode;
+                        }
+                        return target;
+                }
+                
+                // Perform a touch start event
+                function touchStart(e) {
+                    // Allow certain HTML tags to receive touch events
+                    if (o.touchTags.indexOf(e.target.tagName.toLowerCase()) !== -1) {
+                            return;
+                    }
+                    
+                    // Stop the default touches
+                    e.preventDefault();
+                    e.stopPropagation();
+                    
+                    var touch = getTouches(e)[0];
+                    
+                    // Dispatch a fake mouse down event                
+                    dispatchMouseEvent('mousedown', touch, getRootNode(touch.target));
+                    
+                    scrolling = true;
+                    moved = false;
+                    movedY = 0;
+                    
+                    clearTimeout(timeoutID);
+                    setTransitionTime(0);
+                    
+                    // Check scroll position
+                    if (o.momentum) {
+                            var y = getPosition();
+                            if (y !== scrollY) {
+                                    setPosition(y);
+                                    moved = true;
+                            }
+                    }
+
+                    touchY = touch.pageY - scrollY;
+                }
+                        
+                // Perform a touch move event
+                function touchMove(e) {
+                        if (!scrolling) {
+                                return;
+                        }
+                        
+                        var dy = getTouches(e)[0].pageY - touchY;
+                        
+                        // Elastic-drag or stop when moving outside of boundaries
+                        if (dy > 0) {
+                                if (o.elastic) {
+                                        dy /= 2;
+                                } else {
+                                        dy = 0;
+                                }
+                        } else if (dy < maxHeight) {
+                                if (o.elastic) {
+                                        dy = (dy + maxHeight) / 2;
+                                } else {
+                                        dy = maxHeight;
+                                }
+                        }
+                        
+                        movedY = dy - scrollY;
+                        moved = true;
+                        setPosition(dy);
+                }
+                
+                        // Perform a touch end event
+                        function touchEnd(e) {
+                                if (!scrolling) {
+                                        return;
+                                }
+                                
+                                scrolling = false;
+                                
+                                if (moved) {
+                                        // Ease back to within boundaries
+                                        if (scrollY > 0 || scrollY < maxHeight) {
+                                                reboundScroll();
+                                        } else if (o.momentum) {
+                                                // Free scroll with momentum
+                                                momentumScroll(movedY, isiPad ? o.iPadMomentumDamp : o.momentumDamp, 40, 2000, isiPad ? o.iPadMomentumTime : o.momentumTime);
+                                        }                      
+                                } else {
+                                        var touch = getTouches(e)[0],
+                                                target = getRootNode(touch.target);
+                                        
+                                        // Dispatch fake mouse up and click events if this touch event did not move
+                                        dispatchMouseEvent('mouseup', touch, target);
+                                        dispatchMouseEvent('click', touch, target);
+                                }
+                        }
+                
+                });
+        },
+        
+        update: function() {
+                return this.each(function() {
+                        this.update();
+                });
+        },
+        
+        getPosition: function() {
+                var a = [];
+                this.each(function() {
+                        a.push(-this.getPosition());
+                });
+                return a;
+        },
+        
+        setPosition: function(y) {
+                return this.each(function() {
+                        this.setPosition(-y);
+                });
+        }
+        
+};
+       
+       // Public method for touchScroll
+       $.fn.touchScroll = function(method) {
+           if (methods[method]) {
+                       return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+               } else if (typeof method === 'object' || !method) {
+                       return methods.init.apply(this, arguments);
+               } else {
+                       $.error('Method ' +  method + ' does not exist on jQuery.touchScroll');
+               }
+       };
+
+})(jQuery);
\ No newline at end of file