Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

* Simple bottom of list pull-to-refresh

* onScroll event emitted
  • Loading branch information...
commit 0f98e7d82a8cad078108e2f5568614e980b1ff6e 1 parent 5776718
authored June 19, 2011
2  scrollability-min.js
... ...
@@ -1 +1 @@
1  
-/* See LICENSE for terms of usage */(function(){function O(b){var c=b.parentNode;return{node:b,scrollbar:L(b),min:-c.scrollHeight+c.offsetHeight,max:0,viewport:c.offsetHeight,bounce:c.offsetHeight*e,constrained:!0,delegate:b.scrollDelegate,filter:function(a,b){return b},disable:function(b,c,d,e){var f=Math.abs(b-d),g=Math.abs(c-e);if(f>g&&f>a)return!0},update:function(a,b){K(a,a.scrollable_horizontal||0,b)}}}function N(b){var c=b.parentNode;return{node:b,min:-c.scrollWidth+c.offsetWidth,max:0,viewport:c.offsetWidth,bounce:c.offsetWidth*e,constrained:!0,delegate:b.scrollDelegate,filter:function(a,b){return a},disable:function(b,c,d,e){var f=Math.abs(b-d),g=Math.abs(c-e);if(g>f&&g>a)return!0},update:function(a,b){K(a,b,a.scrollable_vertical||0)}}}function M(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b}function L(a){if(!a.scrollableScrollbar){var b=a.scrollableScrollbar=document.createElement("div");b.className="scrollableScrollbar",b.style.cssText=["position: absolute","top: 0","right: 2px","width: 5px","min-height: 4px","background: rgba(40, 40, 40, 0.6)","border: 1px solid rgba(255, 255, 255, 0.075)","opacity: 0","-webkit-border-radius: 4px 5px","-webkit-transform: translate3d(0,0,0)","-webkit-box-sizing: border-box","z-index: 2147483647"].join(";")}return a.scrollableScrollbar}function K(a,b,c){l?a.style.webkitTransform="translate3d("+(b?b+"px":"0")+","+(c?c+"px":"0")+","+"0)":m&&(a.style.MozTransform="translate("+(b?b+"px":"0")+","+(c?c+"px":"0")+")")}function J(){if(v){clearInterval(v),v=0;for(var a=0;a<w.length;++a){var b=w[a];b.terminator()}w=[]}}function I(a){for(var b=0;b<a.length;++b){var c=a[b];c.className=c.className.replace("touched","")}}function H(a){var b=[];for(var c=a;c;c=c.parentNode)c.nodeType==1&&(c.className=(c.className?c.className+" ":"")+"touched",b.push(c));return b}function G(a,b,c,d){var e=a.className.split(" ");for(var f=0;f<e.length;++f){var g=e[f];if(x[g]){var h=x[g](a);h.key="scrollable_"+g,h.paginated=e.indexOf("paginated")!=-1,h.key in a||(a[h.key]=h.initial?h.initial(a):0);return h}}}function F(a,b,c,d,e){while(a){if(a.nodeType==1){var f=G(a,c,d,e);if(f){var g=!1;for(var h=0;h<b.length;++h)if(b[h].node==a){g=!0;break}g||(f=C(f,c,d,e),f&&b.push(f))}}a=a.parentNode}}function E(a,b,c,d){var e=[];F(a,e,b,c,d);var f=document.querySelectorAll(".scrollable.global");for(var g=0;g<f.length;++g)F(f[g],e,b,c,d);return e}function D(){var a=(new Date).getTime();for(var b=0;b<w.length;++b){var c=w[b],d=c.filter(q,r);c.animator(d,a)||(c.terminator(),w.splice(b--,1))}w.length||J()}function C(e,k,l,m){function U(){if(p){var a=Math.round(u/q);T(a*(q+z))}else u>w&&o?T(w):u<v&&o&&T(v);r&&(r.style.opacity="0",r.style.webkitTransition="opacity 0.33s linear"),n&&n.onEndScroll&&n.onEndScroll()}function T(a,b){u=a,e.node[e.key]=u,e.update(e.node,u),n&&n.onScroll&&n.onScroll(u);var c=-v-w;if(r&&q<c){var d=q-j*2,f=d/c*d,g=0;u>w?(f=Math.max(f-(u-w),5),g=0):u<v?(f=Math.max(f-(v-u),5),g=d-f):g=Math.round(Math.abs(u)/c*(d-f)),g+=j,r.style.height=Math.round(f)+"px",K(r,0,Math.round(g)),t&&(r.style.webkitTransition="none",r.style.opacity="1")}return b}function S(h,j){var k=1/(j-H);H=j;var l=!0;if(s){var m=(h-G)*b;if(!m){I||(I=j);if(j-I<J)return!0}else I=0;!N&&Math.abs(h-startTouch)>a&&(N=!0,n&&n.onLockScroll&&n.onLockScroll(e.key)),G=h,A=m/k;if(u>w&&o){var r=u-w;A*=1-r/E}else if(u<v&&o){var r=v-u;A*=1-r/E}}else{if(p&&!L){L=!0;if(Math.abs(u-w)>F||Math.abs(A)>i)if(u>w){if(w!=y){w+=q+z,v+=q+z;if(n&&n.onScrollPage){var t=v%q,K=-Math.round((u+q-t)/q);n.onScrollPage(K,-1)}}}else if(v!=x){w-=q+z,v-=q+z;if(n&&n.onScrollPage){var t=v%q,K=-Math.round((u-q-t)/q);n.onScrollPage(K,1)}}}if(u>w&&o){if(!(A>0)){B||(C=u,D=w-u),u=M(B,C,D,g);return T(u,++B<=g&&Math.floor(u)>w)}var r=u-w,O=1-r/E;A=Math.max(A-f*k,0)*O,B=0}else if(u<v&&o){if(!(A<0)){B||(C=u,D=v-u),u=M(B,C,D,g);return T(u,++B<=g&&Math.ceil(u)<v)}var r=v-u,O=1-r/E;A=Math.min(A+f*k,0)*O,B=0}else{B||(A<0&&A<-c?A=-c:A>0&&A>c&&(A=c),C=A),A=M(B,C,-C,d);if(++B>d||Math.floor(A)==0)l=!1}}u+=A*k;return T(u,l)}var n=e.delegate,o=e.constrained,p=e.paginated,q=e.viewport||0,r=e.scrollbar,u=e.node[e.key],v=e.min,w=e.max,x=v,y=Math.round(w/q)*q,z=0,A=0,B=0,C,D,E=e.bounce,F=q*h,G=startTouch=e.filter(k,l),H=m,I=0,J=20,L=!1,N=!1;if(p){var O=Math.round(Math.abs(x)%q),P=(Math.abs(x)-O)/q+1,z=O/P,Q=Math.round(u)%q,R=Math.round((u-Q)/q)*q;v=w=Math.round(R+y)+Q,x+=z}if(n&&n.onStartScroll&&!n.onStartScroll())return null;r&&e.node.parentNode.appendChild(r),e.updater=T,e.animator=S,e.terminator=U;return e}function B(a){function i(a){f&&(clearTimeout(f),f=0);if(d){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,1),d[0].dispatchEvent(b),I(d)}g.removeEventListener("touchmove",h,!1),g.removeEventListener("touchend",i,!1),s=!1}function h(a){a.preventDefault(),t=!0,f&&(clearTimeout(f),f=0),d&&(I(d),d=null);var b=a.touches[0];q=b.clientX,r=b.clientY;if(w.length>1)for(var c=0;c<w.length;++c){var e=w[c];if(e.disable&&e.disable(q,r,o,p)){e.terminator(),w.splice(c,1);break}}}J();var b=a.target,c=a.touches[0],d=null,e=(new Date).getTime();q=o=c.clientX,r=p=c.clientY,s=!0,t=!1,w=E(a.target,q,r,e);if(!w.length&&!scrollability.globalScrolling)return!0;var f=setTimeout(function(){f=0,d=H(b)},50),g=document;g.addEventListener("touchmove",h,!1),g.addEventListener("touchend",i,!1),v=setInterval(D,0)}function A(a){u=!0}function z(a){setTimeout(function(){if(u)u=!1;else if(n){var a=document.getElementsByClassName("scrollable");if(a.length){var b=a[0];b.className.indexOf("vertical")!=-1&&scrollability.scrollTo(b,0,0,k)}}})}function y(){scrollability.flashIndicators()}var a=10,b=1,c=720/(window.devicePixelRatio||1),d=350,e=.5,f=600,g=90,h=.3,i=50,j=2,k=12,l="webkitTransform"in document.documentElement.style,m="MozTransform"in document.documentElement.style,n="ontouchstart"in window,o,p,q,r,s,t,u,v=0,w=[],x={horizontal:N,vertical:O};window.scrollability={globalScrolling:!1,scrollers:x,flashIndicators:function(){var a=document.querySelectorAll(".scrollable.vertical");for(var b=0;b<a.length;++b)scrollability.scrollTo(a[b],0,0,20,!0)},scrollTo:function(a,b,c,d,e){var f=0;J();var g=G(a);if(g){e&&(g.delegate=null),g=C(g),w=[g],t=!0;if(d){var h=a[g.key],i=g.filter(b,c);v=setInterval(function(){g.updater(h+(i-h)*(f/d)),++f>d&&(clearInterval(v),setTimeout(J,200))},20)}else g.updater(c),J()}}},document.addEventListener("touchstart",B,!1),document.addEventListener("scroll",z,!1),document.addEventListener("orientationchange",A,!1),window.addEventListener("load",y,!1)})()
  1
+(function(){var O=10;var d=1;var r=720/(window.devicePixelRatio||1);var y=350;var C=0.5;var L=600;var u=90;var A=0.3;var D=50;var w=2;var h=200;var i="webkitTransform" in document.documentElement.style;var f="MozTransform" in document.documentElement.style;var q="ontouchstart" in window;var z,x,o,m,k,t,e,B;var I=0;var l=[];var P={horizontal:g,vertical:j};window.scrollability={globalScrolling:false,scrollers:P,flashIndicators:function(){var Q=document.querySelectorAll(".scrollable.vertical");for(var R=0;R<Q.length;++R){scrollability.scrollTo(Q[R],0,0,20,true)}},scrollToTop:function(){var Q=document.getElementsByClassName("scrollable");if(Q.length){var R=Q[0];if(R.className.indexOf("vertical")!=-1){scrollability.scrollTo(R,0,0,h)}}},scrollTo:function(S,X,W,V,U){n();var T=J(S);if(T){if(U){T.delegate=null}T=G(T);l=[T];t=true;if(V){var Y=S[T.key];var Z=T.filter(X,W);var R=Z-Y;var Q=new Date().getTime();I=setInterval(function(){var aa=new Date().getTime()-Q;var ab=Y+((Z-Y)*(aa/V));if((R<0&&ab<Z)||(R>0&&ab>Z)){ab=Z}T.updater(ab);if(ab==Z){clearInterval(I);setTimeout(n,200)}},20)}else{T.updater(W);n()}}}};function K(){scrollability.flashIndicators()}function s(Q){setTimeout(function(){if(B){B=false}else{if(q){scrollability.scrollToTop()}}})}function p(Q){B=true}function M(R){n();var U=R.target;var V=R.touches[0];var S=null;var T=new Date().getTime();o=z=V.clientX;m=x=V.clientY;k=true;t=false;l=N(R.target,o,m,T);if(!l.length&&!scrollability.globalScrolling){return true}var W=setTimeout(function(){W=0;S=b(U)},50);var X=document;X.addEventListener("touchmove",Q,false);X.addEventListener("touchend",Y,false);I=setInterval(E,0);function Q(aa){aa.preventDefault();t=true;if(W){clearTimeout(W);W=0}if(S){v(S);S=null}var ad=aa.touches[0];o=ad.clientX;m=ad.clientY;if(l.length>1){for(var Z=0;Z<l.length;++Z){var ac=l[Z];if(ac.disable&&ac.disable(o,m,z,x)){ac.terminator();l.splice(Z,1);break}}}try{l[0].pullToRefresh()}catch(ab){}}function Y(aa){if(W){clearTimeout(W);W=0}if(S){var Z=document.createEvent("MouseEvents");Z.initMouseEvent("click",true,true,window,1);S[0].dispatchEvent(Z);v(S)}else{try{l[0].pullToRefreshRelease()}catch(ab){}}X.removeEventListener("touchmove",Q,false);X.removeEventListener("touchend",Y,false);k=false}}function G(Q,ah,ag,V){var ab=Q.delegate;var U=Q.constrained;var S=Q.paginated;var ar=Q.viewport||0;var ax=Q.scrollbar;var aq=Q.node[Q.key];var ay=Q.min;var ai=Q.max;var W=ay;var an=Math.round(ai/ar)*ar;var au=0;var Y=0;var T=0;var ac,R;var av=Q.bounce;var aw=ar*A;var af=startTouch=Q.filter(ah,ag);var aA=V;var Z=0;var at=20;var al=false;var am=false;var ap=0;if(S){var aj=Math.round(Math.abs(W)%ar);var aa=((Math.abs(W)-aj)/ar)+1;var au=aj/aa;var az=Math.round(aq)%ar;var ad=Math.round((aq-az)/ar)*ar;ay=ai=Math.round(ad+an)+az;W+=au}if(ab&&ab.onStartScroll){if(!ab.onStartScroll()){return null}}if(ax){Q.node.parentNode.appendChild(ax)}function X(aD,aC){var aF=1/(aC-aA);aA=aC;var aE=true;if(k){var aI=(aD-af)*d;if(!aI){if(!Z){Z=aC}if(aC-Z<at){return true}}else{Z=0}if(!am&&Math.abs(aD-startTouch)>O){am=true;if(ab&&ab.onLockScroll){ab.onLockScroll(Q.key)}}af=aD;Y=aI/aF;if(aq>ai&&U){var aH=aq-ai;Y*=(1-aH/av)}else{if(aq<ay&&U){var aH=ay-aq;Y*=(1-aH/av)}}}else{if(S&&!al){al=true;if(Math.abs(aq-ai)>aw||Math.abs(Y)>D){if(aq>ai){if(ai!=an){ai+=ar+au;ay+=ar+au;if(ab&&ab.onScrollPage){var aB=ay%ar;var aG=-Math.round((aq+ar-aB)/ar);ab.onScrollPage(aG,-1)}}}else{if(ay!=W){ai-=ar+au;ay-=ar+au;if(ab&&ab.onScrollPage){var aB=ay%ar;var aG=-Math.round((aq-ar-aB)/ar);ab.onScrollPage(aG,1)}}}}}if(aq>ai&&U){if(Y>0){var aH=aq-ai;var aJ=(1-aH/av);Y=Math.max(Y-L*aF,0)*aJ;T=0}else{if(!T){ac=aq;R=ai-aq}aq=H(T,ac,R,u);return ao(aq,++T<=u&&Math.floor(aq)>ai)}}else{if(aq<ay&&U){if(Y<0){var aH=ay-aq;var aJ=(1-aH/av);Y=Math.min(Y+L*aF,0)*aJ;T=0}else{if(!T){ac=aq;R=ay-aq}aq=H(T,ac,R,u);return ao(aq,++T<=u&&Math.ceil(aq)<ay)}}else{if(!T){if(Y<0&&Y<-r){Y=-r}else{if(Y>0&&Y>r){Y=r}}ac=Y}Y=H(T,ac,-ac,y);if(++T>y||Math.floor(Y)==0){aE=false}}}}aq+=Y*aF;return ao(aq,aE)}function ao(aG,aF){aq=aG;Q.node[Q.key]=aq;Q.update(Q.node,aq);if(ab&&ab.onScroll){ab.onScroll(aq)}var aE=-ay-ai;if(ax&&(aE+ar)>ar){var aC=ar-w*2;var aB=(aC/(aE+ar))*aC;var aD=0;if(aq>ai){aB=Math.max(aB-(aq-ai),5);aD=0}else{if(aq<ay){aB=Math.max(aB-(ay-aq),5);aD=(aC-aB)}else{aD=Math.round((Math.abs(aq)/aE)*(aC-aB))}}aD+=w;ax.style.height=Math.round(aB)+"px";a(ax,0,Math.round(aD));if(t){ax.style.webkitTransition="none";ax.style.opacity="1"}}return aF}function ae(){if(S){var aB=Math.round(aq/ar);ao(aB*(ar+au))}else{if(aq>ai&&U){ao(ai)}else{if(aq<ay&&U){ao(ay)}}}if(ax){ax.style.opacity="0";ax.style.webkitTransition="opacity 0.33s linear"}if(ab&&ab.onEndScroll){ab.onEndScroll()}}function ak(aB){return function(){if(Q.pullUpToRefresh){var aE=ay-(Q.pullUpToRefresh.offsetHeight/2),aD;if(!aB&&((aq<aE&&ap)||(aq>aE&&!ap))){return}if(aB&&aq<aE){aD="pulledUp";ap=0}else{if(ap&&aq>aE){aD="pullCancel";ap=0}else{if(aq<aE){aD="pullingUp";ap=1}}}var aC=document.createEvent("Event");aC.initEvent(aD,true,false);Q.node.dispatchEvent(aC)}}}Q.updater=ao;Q.animator=X;Q.terminator=ae;Q.pullToRefresh=ak(false);Q.pullToRefreshRelease=ak(true);return Q}function E(){var S=new Date().getTime();for(var Q=0;Q<l.length;++Q){var R=l[Q];var T=R.filter(o,m);if(!R.animator(T,S)){R.terminator();l.splice(Q--,1)}}if(!l.length){n()}}function N(V,S,Q,U){var R=[];F(V,R,S,Q,U);var W=document.querySelectorAll(".scrollable.global");for(var T=0;T<W.length;++T){F(W[T],R,S,Q,U)}return R}function F(U,S,R,Q,V){while(U){if(U.nodeType==1){var X=J(U,R,Q,V);if(X){var W=false;for(var T=0;T<S.length;++T){if(S[T].node==U){W=true;break}}if(!W){X=G(X,R,Q,V);if(X){S.push(X)}}}}U=U.parentNode}}function J(V,R,Q,W){var U=V.className.split(" ");for(var T=0;T<U.length;++T){var S=U[T];if(P[S]){var X=P[S](V);X.key="scrollable_"+S;X.paginated=U.indexOf("paginated")!=-1;if(!(X.key in V)){V[X.key]=X.initial?X.initial(V):0}return X}}}function b(R){var Q=[];for(var S=R;S;S=S.parentNode){if(S.nodeType==1){S.className=(S.className?S.className+" ":"")+"touched";Q.push(S)}}return Q}function v(Q){for(var R=0;R<Q.length;++R){var S=Q[R];S.className=S.className.replace("touched","")}}function n(){if(I){clearInterval(I);I=0;for(var Q=0;Q<l.length;++Q){var R=l[Q];R.terminator()}l=[]}}function a(R,Q,S){if(i){R.style.webkitTransform="translate3d("+(Q?(Q+"px"):"0")+","+(S?(S+"px"):"0")+",0)"}else{if(f){R.style.MozTransform="translate3d("+(Q?(Q+"px"):"0")+","+(S?(S+"px"):"0")+")"}}if(!e){e=setTimeout(function(){var T=document.createEvent("Event");T.initEvent("scroll",false,false);T.x=-Q||0;T.y=-S||0;R.dispatchEvent(T);e=false},20)}}function c(Q){if(!Q.scrollableScrollbar){var R=Q.scrollableScrollbar=document.createElement("div");R.className="scrollableScrollbar";R.style.cssText=["position: absolute","top: 0","right: 2px","width: 5px","min-height: 4px","background: rgba(40, 40, 40, 0.6)","border: 1px solid rgba(235, 235, 235, 0.1)","opacity: 0","-webkit-border-radius: 4px 5px","-webkit-transform: translate3d(0,0,0)","-webkit-box-sizing: border-box","z-index: 2147483647"].join(";")}return Q.scrollableScrollbar}function H(R,Q,T,S){return(R==S)?Q+T:T*(-Math.pow(2,-10*R/S)+1)+Q}function g(Q){var R=Q.parentNode;return{node:Q,min:-R.scrollWidth+R.offsetWidth,max:0,viewport:R.offsetWidth,bounce:R.offsetWidth*C,constrained:true,delegate:Q.scrollDelegate,filter:function(S,T){return S},disable:function(T,X,V,S){var W=Math.abs(T-V);var U=Math.abs(X-S);if(U>W&&U>O){return true}},update:function(T,S){a(T,S,T.scrollable_vertical||0)}}}function j(R){var S=R.parentNode,Q=S.getElementsByClassName("pull-to-refresh")[0];return{node:R,scrollbar:c(R),min:-S.scrollHeight+S.offsetHeight+(Q?Q.offsetHeight/2:0),max:0,viewport:S.offsetHeight,bounce:S.offsetHeight*C,pullUpToRefresh:Q?Q:false,constrained:true,delegate:R.scrollDelegate,filter:function(T,U){return U},disable:function(U,Y,W,T){var X=Math.abs(U-W);var V=Math.abs(Y-T);if(X>52&&X>O){return true}},update:function(U,T){a(U,U.scrollable_horizontal||0,T)}}}document.addEventListener("touchstart",M,false);document.addEventListener("scroll",s,false);document.addEventListener("orientationchange",p,false);window.addEventListener("load",K,false)})();
142  scrollability.js
@@ -40,7 +40,7 @@ var isTouch = "ontouchstart" in window;
40 40
 
41 41
 // ===============================================================================================
42 42
 
43  
-var startX, startY, touchX, touchY, touchDown, touchMoved, justChangedOrientation;
  43
+var startX, startY, touchX, touchY, touchDown, touchMoved, onScrollEvt, justChangedOrientation;
44 44
 var animationInterval = 0;
45 45
 var touchTargets = [];
46 46
 
@@ -57,9 +57,9 @@ window.scrollability = {
57 57
         var scrollables = document.querySelectorAll('.scrollable.vertical');
58 58
         for (var i = 0; i < scrollables.length; ++i) {
59 59
             scrollability.scrollTo(scrollables[i], 0, 0, 20, true);
60  
-        }            
  60
+        }
61 61
     },
62  
-
  62
+    
63 63
     scrollToTop: function() {
64 64
         var scrollables = document.getElementsByClassName('scrollable');
65 65
         if (scrollables.length) {
@@ -68,9 +68,8 @@ window.scrollability = {
68 68
                 scrollability.scrollTo(scrollable, 0, 0, kScrollToTopTime);
69 69
             }
70 70
         }
71  
-    
72 71
     },
73  
-    
  72
+
74 73
     scrollTo: function(element, x, y, animationTime, muteDelegate) {
75 74
         stopAnimation();
76 75
 
@@ -87,6 +86,7 @@ window.scrollability = {
87 86
                 var dest = target.filter(x, y);
88 87
                 var dir = dest - orig;
89 88
                 var startTime = new Date().getTime();
  89
+
90 90
                 animationInterval = setInterval(function() {
91 91
                     var d = new Date().getTime() - startTime;
92 92
                     var pos = orig + ((dest-orig) * (d/animationTime));
@@ -117,7 +117,7 @@ function onScroll(event) {
117 117
             justChangedOrientation = false;
118 118
         } else if (isTouch) {
119 119
             scrollability.scrollToTop();
120  
-        }        
  120
+        }
121 121
     });
122 122
 }
123 123
 
@@ -130,6 +130,7 @@ function onTouchStart(event) {
130 130
 
131 131
     var touchCandidate = event.target;
132 132
     var touch = event.touches[0];
  133
+
133 134
     var touched = null;
134 135
     var startTime = new Date().getTime();
135 136
 
@@ -142,22 +143,22 @@ function onTouchStart(event) {
142 143
     if (!touchTargets.length && !scrollability.globalScrolling) {
143 144
         return true;
144 145
     }
145  
-    
  146
+
146 147
     var holdTimeout = setTimeout(function() {
147 148
         holdTimeout = 0;
148 149
         touched = setTouched(touchCandidate);
149 150
     }, 50);
150  
-        
  151
+
151 152
     var d = document;
152 153
     d.addEventListener('touchmove', onTouchMove, false);
153 154
     d.addEventListener('touchend', onTouchEnd, false);
154 155
 
155  
-    animationInterval = setInterval(touchAnimation, 0);    
  156
+    animationInterval = setInterval(touchAnimation, 0);
156 157
 
157 158
     function onTouchMove(event) {
158 159
         event.preventDefault();
159 160
         touchMoved = true;
160  
-        
  161
+
161 162
         if (holdTimeout) {
162 163
             clearTimeout(holdTimeout);
163 164
             holdTimeout = 0;
@@ -181,6 +182,10 @@ function onTouchStart(event) {
181 182
                 }
182 183
             }
183 184
         }
  185
+
  186
+        try {
  187
+            touchTargets[0].pullToRefresh();
  188
+        } catch(e) {}
184 189
     }
185 190
 
186 191
     function onTouchEnd(event) {
@@ -191,12 +196,16 @@ function onTouchStart(event) {
191 196
 
192 197
         // Simulate a click event when releasing the finger
193 198
         if (touched) {
194  
-            var evt = document.createEvent('MouseEvents'); 
  199
+            var evt = document.createEvent('MouseEvents');
195 200
             evt.initMouseEvent('click', true, true, window, 1);
196  
-            touched[0].dispatchEvent(evt); 
  201
+            touched[0].dispatchEvent(evt);
197 202
             releaseTouched(touched);
  203
+        } else {
  204
+            try {
  205
+                touchTargets[0].pullToRefreshRelease();
  206
+            } catch(e) {}
198 207
         }
199  
-        
  208
+
200 209
         d.removeEventListener('touchmove', onTouchMove, false);
201 210
         d.removeEventListener('touchend', onTouchEnd, false);
202 211
         touchDown = false;
@@ -226,6 +235,7 @@ function wrapTarget(target, startX, startY, startTime) {
226 235
     var stillThreshold = 20;
227 236
     var snapped = false;
228 237
     var locked = false;
  238
+    var pullState = 0;
229 239
 
230 240
     if (paginated) {
231 241
         var excess = Math.round(Math.abs(absMin) % viewport);
@@ -247,11 +257,11 @@ function wrapTarget(target, startX, startY, startTime) {
247 257
     if (scrollbar) {
248 258
         target.node.parentNode.appendChild(scrollbar);
249 259
     }
250  
-    
  260
+
251 261
     function animator(touch, time) {
252 262
         var deltaTime = 1 / (time - lastTime);
253 263
         lastTime = time;
254  
-        
  264
+
255 265
         var continues = true;
256 266
         if (touchDown) {
257 267
             var delta = (touch - lastTouch) * kTouchMultiplier;
@@ -275,10 +285,10 @@ function wrapTarget(target, startX, startY, startTime) {
275 285
                     delegate.onLockScroll(target.key);
276 286
                 }
277 287
             }
278  
-            
  288
+
279 289
             lastTouch = touch;
280 290
             velocity = delta / deltaTime;
281  
-            
  291
+
282 292
             // Apply resistance along the edges
283 293
             if (position > max && constrained) {
284 294
                 var excess = position - max;
@@ -368,7 +378,7 @@ function wrapTarget(target, startX, startY, startTime) {
368 378
                 }
369 379
             }
370 380
         }
371  
-        
  381
+
372 382
         position += velocity * deltaTime;
373 383
         return update(position, continues);
374 384
     }
@@ -385,9 +395,9 @@ function wrapTarget(target, startX, startY, startTime) {
385 395
 
386 396
         // Update the scrollbar
387 397
         var range = -min - max;
388  
-        if (scrollbar && viewport < range) {
  398
+        if (scrollbar && (range + viewport) > viewport) {
389 399
             var viewable = viewport - kScrollbarMargin*2;
390  
-            var height = (viewable/range) * viewable;
  400
+            var height = (viewable/(range+viewport)) * viewable;
391 401
             var scrollPosition = 0;
392 402
             if (position > max) {
393 403
                 height = Math.max(height - (position-max), 5);
@@ -402,16 +412,16 @@ function wrapTarget(target, startX, startY, startTime) {
402 412
             scrollbar.style.height = Math.round(height) + 'px';
403 413
 
404 414
             moveElement(scrollbar, 0, Math.round(scrollPosition));
405  
-            
  415
+
406 416
             if (touchMoved) {
407 417
                 scrollbar.style.webkitTransition = 'none';
408 418
                 scrollbar.style.opacity = '1';
409 419
             }
410  
-        }    
  420
+        }
411 421
 
412 422
         return continues;
413 423
     }
414  
-    
  424
+
415 425
     function terminator() {
416 426
         // Snap to the integer endpoint, since position may be a subpixel value while animating
417 427
         if (paginated) {
@@ -432,16 +442,45 @@ function wrapTarget(target, startX, startY, startTime) {
432 442
             delegate.onEndScroll();
433 443
         }
434 444
     }
435  
-    
  445
+
  446
+    function pullToRefresh(released) {
  447
+        return function() {
  448
+            if(target.pullUpToRefresh) {
  449
+                var pullMin = min - (target.pullUpToRefresh.offsetHeight / 2),
  450
+                    state;
  451
+
  452
+                if(!released && ((position < pullMin && pullState) || (position > pullMin && !pullState)))
  453
+                    return;
  454
+
  455
+                if(released && position < pullMin) {
  456
+                    state = 'pulledUp';
  457
+                    pullState = 0;
  458
+                } else if(pullState && position > pullMin) {
  459
+                    state = 'pullCancel';
  460
+                    pullState = 0;
  461
+                } else if(position < pullMin) {
  462
+                    state = 'pullingUp';
  463
+                    pullState = 1;
  464
+                }
  465
+
  466
+                var evt = document.createEvent('Event');
  467
+                evt.initEvent(state, true, false);
  468
+                target.node.dispatchEvent(evt);
  469
+            }
  470
+        }
  471
+    }
  472
+
436 473
     target.updater = update;
437 474
     target.animator = animator;
438 475
     target.terminator = terminator;
  476
+    target.pullToRefresh = pullToRefresh(false);
  477
+    target.pullToRefreshRelease = pullToRefresh(true);
439 478
     return target;
440 479
 }
441 480
 
442 481
 function touchAnimation() {
443 482
     var time = new Date().getTime();
444  
-    
  483
+
445 484
     // Animate each of the targets
446 485
     for (var i = 0; i < touchTargets.length; ++i) {
447 486
         var target = touchTargets[i];
@@ -453,7 +492,7 @@ function touchAnimation() {
453 492
             touchTargets.splice(i--, 1);
454 493
         }
455 494
     }
456  
-    
  495
+
457 496
     if (!touchTargets.length) {
458 497
         stopAnimation();
459 498
     }
@@ -466,7 +505,7 @@ function getTouchTargets(node, touchX, touchY, startTime) {
466 505
     findTargets(node, targets, touchX, touchY, startTime);
467 506
 
468 507
     var candidates = document.querySelectorAll('.scrollable.global');
469  
-    for (var j = 0; j < candidates.length; ++j) {
  508
+    for(var j = 0; j < candidates.length; ++j) {
470 509
         findTargets(candidates[j], targets, touchX, touchY, startTime);
471 510
     }
472 511
     return targets;
@@ -488,12 +527,12 @@ function findTargets(element, targets, touchX, touchY, startTime) {
488 527
                 if (!exists) {
489 528
                     target = wrapTarget(target, touchX, touchY, startTime);
490 529
                     if (target) {
491  
-                        targets.push(target);                            
  530
+                        targets.push(target);
492 531
                     }
493 532
                 }
494 533
             }
495 534
         }
496  
-       element = element.parentNode;
  535
+        element = element.parentNode;
497 536
     }
498 537
 }
499 538
 
@@ -547,13 +586,25 @@ function stopAnimation() {
547 586
 function moveElement(element, x, y) {
548 587
     if (isWebkit) {
549 588
         element.style.webkitTransform = 'translate3d('
550  
-        +(x ? (x+'px') : '0')+','
551  
-        +(y ? (y+'px') : '0')+','
552  
-        +'0)';      
  589
+            +(x ? (x+'px') : '0')+','
  590
+            +(y ? (y+'px') : '0')+','
  591
+            +'0)';
553 592
     } else if (isFirefox) {
554  
-        element.style.MozTransform = 'translate('
555  
-        +(x ? (x+'px') : '0')+','
556  
-        +(y ? (y+'px') : '0')+')';      
  593
+        element.style.MozTransform = 'translate3d('
  594
+            +(x ? (x+'px') : '0')+','
  595
+            +(y ? (y+'px') : '0')+')';
  596
+    }
  597
+
  598
+    if(!onScrollEvt) {
  599
+        onScrollEvt = setTimeout(function() {
  600
+            var evt = document.createEvent('Event');
  601
+            // Don't want this to bubble because of scrollToTop
  602
+            evt.initEvent('scroll', false, false);
  603
+            evt.x = -x || 0;
  604
+            evt.y = -y || 0;
  605
+            element.dispatchEvent(evt);
  606
+            onScrollEvt = false;
  607
+        }, 20);
557 608
     }
558 609
 }
559 610
 
@@ -575,7 +626,7 @@ function initScrollbar(element) {
575 626
             '-webkit-border-radius: 4px 5px',
576 627
             '-webkit-transform: translate3d(0,0,0)',
577 628
             '-webkit-box-sizing: border-box',
578  
-            'z-index: 2147483647',
  629
+            'z-index: 2147483647'
579 630
         ].join(';');
580 631
     }
581 632
     return element.scrollableScrollbar;
@@ -597,9 +648,9 @@ function createXTarget(element) {
597 648
         bounce: parent.offsetWidth * kBounceLimit,
598 649
         constrained: true,
599 650
         delegate: element.scrollDelegate,
600  
-        
  651
+
601 652
         filter: function(x, y) {
602  
-            return x; 
  653
+            return x;
603 654
         },
604 655
 
605 656
         disable: function (x, y, startX, startY) {
@@ -617,21 +668,24 @@ function createXTarget(element) {
617 668
 }
618 669
 
619 670
 function createYTarget(element) {
620  
-    var parent = element.parentNode;
  671
+    var parent = element.parentNode,
  672
+        pullUpToRefresh = parent.getElementsByClassName('pull-to-refresh')[0];
621 673
     return {
622 674
         node: element,
623 675
         scrollbar: initScrollbar(element),
624  
-        min: -parent.scrollHeight + parent.offsetHeight,
  676
+        min: -parent.scrollHeight + parent.offsetHeight
  677
+             + (pullUpToRefresh ? pullUpToRefresh.offsetHeight / 2 : 0),
625 678
         max: 0,
626 679
         viewport: parent.offsetHeight,
627 680
         bounce: parent.offsetHeight * kBounceLimit,
  681
+        pullUpToRefresh: pullUpToRefresh ? pullUpToRefresh : false,
628 682
         constrained: true,
629 683
         delegate: element.scrollDelegate,
630  
-        
  684
+
631 685
         filter: function(x, y) {
632 686
             return y;
633 687
         },
634  
-        
  688
+
635 689
         disable: function(x, y, startX, startY) {
636 690
             var dx = Math.abs(x - startX);
637 691
             var dy = Math.abs(y - startY);
@@ -639,11 +693,11 @@ function createYTarget(element) {
639 693
                 return true;
640 694
             }
641 695
         },
642  
-        
  696
+
643 697
         update: function(element, position) {
644 698
             moveElement(element, element.scrollable_horizontal||0, position);
645 699
         }
646  
-    };    
  700
+    };
647 701
 }
648 702
 
649 703
 document.addEventListener('touchstart', onTouchStart, false);

0 notes on commit 0f98e7d

Please sign in to comment.
Something went wrong with that request. Please try again.