OSDN Git Service

update iscroll.js to 3.2.1
authorISHIKAWA Mutsumi <ishikawa@hanzubon.jp>
Thu, 3 Jun 2010 16:55:56 +0000 (01:55 +0900)
committerISHIKAWA Mutsumi <ishikawa@hanzubon.jp>
Thu, 3 Jun 2010 16:55:56 +0000 (01:55 +0900)
data/public/iscroll/iscroll.js

index 5cb2e99..14c97ee 100644 (file)
@@ -7,16 +7,16 @@
  * Released under MIT license
  * http://cubiq.org/dropbox/mit-license.txt
  * 
- * Version 3.1beta1 - Last updated: 2010.05.06
+ * Version 3.2.1 - Last updated: 2010.06.03
  * 
  */
 
+(function(){
+
 function iScroll (el, options) {
        this.element = typeof el == 'object' ? el : document.getElementById(el);
        this.wrapper = this.element.parentNode;
 
-       this.wrapper.style.overflow = 'hidden';
-       this.wrapper.style.position = 'relative';
        this.element.style.webkitTransitionProperty = '-webkit-transform';
        this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0,0,0.25,1)';
        this.element.style.webkitTransitionDuration = '0';
@@ -25,6 +25,8 @@ function iScroll (el, options) {
        // Get options
        this.options = {
                bounce: true,
+               checkDOMChanges: true,
+               topOnDOMChanges: false,
                hScrollBar: true,
                vScrollBar: true
        };
@@ -40,13 +42,16 @@ function iScroll (el, options) {
        this.element.addEventListener('touchstart', this);
        this.element.addEventListener('touchmove', this);
        this.element.addEventListener('touchend', this);
-       this.element.addEventListener('DOMSubtreeModified', this);
        window.addEventListener('orientationchange', this);
+
+       if (this.options.checkDOMChanges) {
+               this.element.addEventListener('DOMSubtreeModified', this);
+       }
 }
 
 iScroll.prototype = {
-       _x: 0,
-       _y: 0,
+       x: 0,
+       y: 0,
 
        handleEvent: function (e) {
                switch (e.type) {
@@ -54,34 +59,50 @@ iScroll.prototype = {
                        case 'touchmove': this.onTouchMove(e); break;
                        case 'touchend': this.onTouchEnd(e); break;
                        case 'webkitTransitionEnd': this.onTransitionEnd(e); break;
-                       case 'orientationchange': this.refresh(); /*this.scrollTo(0,0,'0');*/ break;
-                       case 'DOMSubtreeModified': this.refresh(); break;
+                       case 'orientationchange': this.refresh(); break;
+                       case 'DOMSubtreeModified': this.onDOMModified(e); break;
+               }
+       },
+       
+       onDOMModified: function (e) {
+               this.refresh();
+               
+               if (this.options.topOnDOMChanges && (this.x!=0 || this.y!=0)) {
+                       this.scrollTo(0,0,'0');
                }
        },
 
        refresh: function () {
-               this.element.style.webkitTransitionDuration = '0';
                this.scrollWidth = this.wrapper.clientWidth;
                this.scrollHeight = this.wrapper.clientHeight;
                this.maxScrollX = this.scrollWidth - this.element.offsetWidth;
                this.maxScrollY = this.scrollHeight - this.element.offsetHeight;
-               
+
                var resetX = this.x, resetY = this.y;
-               if (this.scrollX && this.x < this.maxScrollX) {
-                       resetX = this.maxScrollX;
+               if (this.scrollX) {
+                       if (this.maxScrollX >= 0) {
+                               resetX = 0;
+                       } else if (this.x < this.maxScrollX) {
+                               resetX = this.maxScrollX;
+                       }
                }
-               if (this.scrollY && this.y < this.maxScrollY) {
-                       resetY = this.maxScrollY;
+               if (this.scrollY) {
+                       if (this.maxScrollY >= 0) {
+                               resetY = 0;
+                       } else if (this.y < this.maxScrollY) {
+                               resetY = this.maxScrollY;
+                       }
+               }
+               if (resetX!=this.x || resetY!=this.y) {
+                       this.scrollTo(resetX,resetY,'0');
                }
-               // If content width/lenght has been modified, reset scroller position
-               this.scrollTo(resetX,resetY,'0');
 
                this.scrollX = this.element.offsetWidth > this.scrollWidth ? true : false;
                this.scrollY = this.element.offsetHeight > this.scrollHeight ? true : false;
 
                // Update horizontal scrollbar
                if (this.options.hScrollBar && this.scrollX) {
-                       this.scrollBarX = new scrollbar('horizontal', this.wrapper);                    
+                       this.scrollBarX = (this.scrollBarX instanceof scrollbar) ? this.scrollBarX : new scrollbar('horizontal', this.wrapper);
                        this.scrollBarX.init(this.scrollWidth, this.element.offsetWidth);
                } else if (this.scrollBarX) {
                        this.scrollBarX = this.scrollBarX.remove();
@@ -89,33 +110,25 @@ iScroll.prototype = {
 
                // Update vertical scrollbar
                if (this.options.vScrollBar && this.scrollY) {
-                       this.scrollBarY = new scrollbar('vertical', this.wrapper);                      
+                       this.scrollBarY = (this.scrollBarY instanceof scrollbar) ? this.scrollBarY : new scrollbar('vertical', this.wrapper);
                        this.scrollBarY.init(this.scrollHeight, this.element.offsetHeight);
                } else if (this.scrollBarY) {
                        this.scrollBarY = this.scrollBarY.remove();
                }
        },
 
-       get x() {
-               return this._x;
-       },
-
-       get y() {
-               return this._y;
-       },
-
        setPosition: function (x, y) { 
-               this._x = x !== null ? x : this._x;
-               this._y = y !== null ? y : this._y;
+               this.x = x !== null ? x : this.x;
+               this.y = y !== null ? y : this.y;
 
-               this.element.style.webkitTransform = 'translate3d(' + this._x + 'px,' + this._y + 'px,0)';
+               this.element.style.webkitTransform = 'translate3d(' + this.x + 'px,' + this.y + 'px,0)';
 
                // Move the scrollbars
                if (this.scrollBarX) {
-                       this.scrollBarX.setPosition(this.scrollBarX.maxScroll / this.maxScrollX * this._x);
+                       this.scrollBarX.setPosition(this.scrollBarX.maxScroll / this.maxScrollX * this.x);
                }
                if (this.scrollBarY) {
-                       this.scrollBarY.setPosition(this.scrollBarY.maxScroll / this.maxScrollY * this._y);
+                       this.scrollBarY.setPosition(this.scrollBarY.maxScroll / this.maxScrollY * this.y);
                }
        },
                
@@ -145,7 +158,7 @@ iScroll.prototype = {
                this.scrollStartX = this.x;
 
                this.touchStartY = e.touches[0].pageY;
-               this.scrollStartY = this.y;                     
+               this.scrollStartY = this.y;
 
                this.scrollStartTime = e.timeStamp;
                this.moved = false;
@@ -155,16 +168,20 @@ iScroll.prototype = {
                if (e.targetTouches.length != 1) {
                        return false;
                }
+
                e.preventDefault();
-               var leftDelta = this.scrollX === true ? e.touches[0].pageX - this.touchStartX : 0;
-               var topDelta = this.scrollY === true ? e.touches[0].pageY - this.touchStartY : 0;
 
-               if (this.x > 0 || this.x < this.maxScrollX) { 
-                       leftDelta = Math.round(leftDelta / 4);          // Slow down if outside of the boundaries
-               }
+               var leftDelta = this.scrollX === true ? e.touches[0].pageX - this.touchStartX : 0,
+                       topDelta = this.scrollY === true ? e.touches[0].pageY - this.touchStartY : 0,
+                       newX = this.x + leftDelta,
+                       newY = this.y + topDelta;
 
-               if (this.y > 0 || this.y < this.maxScrollY) { 
-                       topDelta = Math.round(topDelta / 4);            // Slow down if outside of the boundaries
+               // Slow down if outside of the boundaries
+               if (newX > 0 || newX < this.maxScrollX) { 
+                       newX = this.options.bounce ? Math.round(this.x + leftDelta / 4) : this.x;
+               }
+               if (newY > 0 || newY < this.maxScrollY) { 
+                       newY = this.options.bounce ? Math.round(this.y + topDelta / 4) : this.y;
                }
 
                if (this.scrollBarX && !this.scrollBarX.visible) {
@@ -174,7 +191,7 @@ iScroll.prototype = {
                        this.scrollBarY.show();
                }
 
-               this.setPosition(this.x + leftDelta, this.y + topDelta);
+               this.setPosition(newX, newY);
 
                this.touchStartX = e.touches[0].pageX;
                this.touchStartY = e.touches[0].pageY;
@@ -194,9 +211,18 @@ iScroll.prototype = {
                }
 
                if (!this.moved) {
+                       // Find the last touched element
+                       var theTarget = e.changedTouches[0].target;
+                       if (theTarget.nodeType == 3) {
+                               theTarget = theTarget.parentNode;
+                       }
+                       // Create the fake event
                        var theEvent = document.createEvent('MouseEvents');
-                       theEvent.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
-                       e.changedTouches[0].target.dispatchEvent(theEvent);             
+                       theEvent.initMouseEvent("click", true, true, document.defaultView,
+                                                                       e.detail, e.screenX, e.screenY, e.clientX, e.clientY,
+                                                                       e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
+                                                                       e.button, e.relatedTarget);
+                       theTarget.dispatchEvent(theEvent);
                        return false;
                }
                
@@ -205,23 +231,23 @@ iScroll.prototype = {
                var momentumX = this.scrollX === true
                        ? this.momentum(this.x - this.scrollStartX,
                                                        time,
-                                                       -this.x + 50,
-                                                       this.x + this.element.offsetWidth - this.scrollWidth + 50)
+                                                       this.options.bounce ? -this.x + this.scrollWidth/4 : -this.x,
+                                                       this.options.bounce ? this.x + this.element.offsetWidth - this.scrollWidth + this.scrollWidth/4 : this.x + this.element.offsetWidth - this.scrollWidth)
                        : { dist: 0, time: 0 };
 
                var momentumY = this.scrollY === true
                        ? this.momentum(this.y - this.scrollStartY,
                                                        time,
-                                                        -this.y + /*this.scrollHeight/3*/ 50,
-                                                       this.y + this.element.offsetHeight - this.scrollHeight + /*this.scrollHeight/3*/ 50)
+                                                       this.options.bounce ? -this.y + this.scrollHeight/4 : -this.y,
+                                                       this.options.bounce ? this.y + this.element.offsetHeight - this.scrollHeight + this.scrollHeight/4 : this.y + this.element.offsetHeight - this.scrollHeight)
                        : { dist: 0, time: 0 };
 
                if (!momentumX.dist && !momentumY.dist) {
-                       this.onTransitionEnd(); // I know, I know... This is lame
+                       this.resetPosition();
                        return false;
                }
 
-               var newDuration = Math.max(momentumX.time, momentumY.time);
+               var newDuration = Math.max(Math.max(momentumX.time, momentumY.time), 1);                // The minimum animation length must be 1ms
                var newPositionX = this.x + momentumX.dist;
                var newPositionY = this.y + momentumY.dist;
 
@@ -241,36 +267,42 @@ iScroll.prototype = {
        onTransitionEnd: function () {
                this.element.removeEventListener('webkitTransitionEnd', this);
                this.resetPosition();
-
-               // Hide the scrollbars
-               if (this.scrollBarX) {
-                       this.scrollBarX.hide();
-               }
-               if (this.scrollBarY) {
-                       this.scrollBarY.hide();
-               }
        },
 
        resetPosition: function () {
-               var resetX = resetY = null;
-               if (this.x > 0 || this.x < this.maxScrollX) {
-                       resetX = this.x >= 0 ? 0 : this.maxScrollX;
+               var resetX = this.x,
+                       resetY = this.y;
+               
+               if (this.x >= 0) {
+                       resetX = 0;
+               } else if (this.x < this.maxScrollX) {
+                       resetX = this.maxScrollX;
                }
 
-               if (this.y > 0 || this.y < this.maxScrollY) {
-                       resetY = this.y >= 0 ? 0 : this.maxScrollY;
+               if (this.y >= 0) {
+                       resetY = 0;
+               } else if (this.y < this.maxScrollY) {
+                       resetY = this.maxScrollY;
                }
 
-               if (resetX !== null || resetY !== null) {
+               if (resetX != this.x || resetY != this.y) {
                        this.scrollTo(resetX, resetY, '500ms');
 
-                       if (this.scrollBarX) {
-                               this.scrollBarX.scrollTo(this.scrollBarX.maxScroll / this.maxScrollX * (resetX || this.x), '500ms');
+                       if (this.scrollBarX && resetX != this.x) {
+                               this.scrollBarX.scrollTo(this.scrollBarX.maxScroll / this.maxScrollX * resetX, '500ms');
                        }                       
-                       if (this.scrollBarY) {
-                               this.scrollBarY.scrollTo(this.scrollBarY.maxScroll / this.maxScrollY * (resetY || this.y), '500ms');
+                       if (this.scrollBarY && resetY != this.y) {
+                               this.scrollBarY.scrollTo(this.scrollBarY.maxScroll / this.maxScrollY * resetY, '500ms');
                        }
                }
+               
+               // Hide the scrollbars
+               if (this.scrollBarX) {
+                       this.scrollBarX.hide();
+               }
+               if (this.scrollBarY) {
+                       this.scrollBarY.hide();
+               }
        },
 
        scrollTo: function (destX, destY, runtime) {
@@ -278,29 +310,25 @@ iScroll.prototype = {
                this.setPosition(destX, destY);
        },
 
-       momentum: function (dist, time, maxDist1, maxDist2) {
-               friction = 0.1;
-               deceleration = 1.5;
-
-               var speed = Math.abs(dist) / time * 1000;
-               var newDist = speed * speed / (20 * friction) / 1000;
+       momentum: function (dist, time, maxDistUpper, maxDistLower) {
+               var friction = 0.1,
+                       deceleration = 1.5,
+                       speed = Math.abs(dist) / time * 1000,
+                       newDist = speed * speed / (20 * friction) / 1000;
 
                // Proportinally reduce speed if we are outside of the boundaries 
-               if (dist > 0 && maxDist1 !== undefined && newDist > maxDist1) {
-                       speed = speed * maxDist1 / newDist;
-                       newDist = maxDist1;
+               if (dist > 0 && newDist > maxDistUpper) {
+                       speed = speed * maxDistUpper / newDist;
+                       newDist = maxDistUpper;
                }
-               if (dist < 0 && maxDist2 !== undefined && newDist > maxDist2) {
-                       speed = speed * maxDist2 / newDist;
-                       newDist = maxDist2;
+               if (dist < 0 && newDist > maxDistLower) {
+                       speed = speed * maxDistLower / newDist;
+                       newDist = maxDistLower;
                }
                
                newDist = newDist * (dist < 0 ? -1 : 1);
                
-               var newTime = -speed / -deceleration;
-               if (newTime < 1) {      // We can't go back in time
-                       newTime = 1;
-               }
+               var newTime = speed / deceleration;
 
                return { dist: Math.round(newDist), time: Math.round(newTime) };
        }
@@ -313,7 +341,7 @@ var scrollbar = function (dir, wrapper) {
        this.bar.style.webkitTransitionTimingFunction = 'cubic-bezier(0,0,0.25,1)';
        this.bar.style.webkitTransform = 'translate3d(0,0,0)';
        this.bar.style.webkitTransitionProperty = '-webkit-transform,opacity';
-       this.bar.style.webkitTransitionDuration = '0,250ms';
+       this.bar.style.webkitTransitionDuration = '0,300ms';
        this.bar.style.pointerEvents = 'none';
        this.bar.style.opacity = '0';
 
@@ -346,7 +374,7 @@ scrollbar.prototype = {
        },
        
        scrollTo: function (pos, runtime) {
-               this.bar.style.webkitTransitionDuration = (runtime || '400ms') + ',250ms';
+               this.bar.style.webkitTransitionDuration = (runtime || '400ms') + ',300ms';
                this.setPosition(pos);
        },
        
@@ -365,3 +393,7 @@ scrollbar.prototype = {
                return null;
        }
 };
+
+// Expose iScroll to the world
+window.iScroll = iScroll;
+})();