From d77982b9b47b8b17051000cfcf3db1a8945d6279 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 5 Aug 2009 17:09:19 -0400 Subject: [PATCH] added Infinite Scroll plugin --- .../InfiniteScroll/InfiniteScrollPlugin.php | 66 +++++ plugins/InfiniteScroll/ajax-loader.gif | Bin 0 -> 10819 bytes .../InfiniteScroll/jquery.infinitescroll.js | 251 ++++++++++++++++++ .../jquery.infinitescroll.min.js | 8 + plugins/InfiniteScroll/readme.txt | 6 + 5 files changed, 331 insertions(+) create mode 100644 plugins/InfiniteScroll/InfiniteScrollPlugin.php create mode 100644 plugins/InfiniteScroll/ajax-loader.gif create mode 100644 plugins/InfiniteScroll/jquery.infinitescroll.js create mode 100644 plugins/InfiniteScroll/jquery.infinitescroll.min.js create mode 100644 plugins/InfiniteScroll/readme.txt diff --git a/plugins/InfiniteScroll/InfiniteScrollPlugin.php b/plugins/InfiniteScroll/InfiniteScrollPlugin.php new file mode 100644 index 0000000000..6738dc7608 --- /dev/null +++ b/plugins/InfiniteScroll/InfiniteScrollPlugin.php @@ -0,0 +1,66 @@ +. + * + * @category Plugin + * @package Laconica + * @author Craig Andrews + * @copyright 2009 Craig Andrews http://candrews.integralblue.com + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +class InfiniteScrollPlugin extends Plugin +{ + function __construct() + { + parent::__construct(); + } + + function onEndShowScripts($action) + { + $action->element('script', + array('type' => 'text/javascript', + 'src' => common_path('plugins/InfiniteScroll/jquery.infinitescroll.min.js')), + ''); + + $loading_image = common_path('plugins/InfiniteScroll/ajax-loader.gif'); + $js_string = << +jQuery(document).ready(function($){ + $('notices_primary').infinitescroll({ + nextSelector : "li.nav_next a", + loadingImg : "$loading_image", + text : "Loading the next set of posts...", + donetext : "Congratulations, you\'ve reached the end of the Internet.", + navSelector : "div.pagination", + contentSelector : "#notices_primary", + itemSelector : "ol.notices" + }); +}); + +EOT; + $action->raw($js_string); + } +} diff --git a/plugins/InfiniteScroll/ajax-loader.gif b/plugins/InfiniteScroll/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..a576ecd5e1e9aefbb8dea6b59126dd75224e6045 GIT binary patch literal 10819 zcmb`NXHZk?{cyXWhpZDuInOQTL^<}MDvz}{R_x*d+HSZ{0HJJi%0=@tM$H&LAcZ<6E zS6{!Sm)1_d>sfx=x%hE(b7o<;Z)kmzzB9kHx3v0Yb>nMe`(nq3)s3xh+q(yY?0Kab%067*C z3OBb-#}t*>Z8YIzKDgM=;>)(Zw~uL=I1Mlpl#=VzWp^#3zrf{gsebubiQ6@{DlmlH zx^s@qm|E#MHC;Q~@g@1E#@IHp4!@0A_=NHH^7Zp1QSemTK=)v>tDlE+L==)pf`$^p zlOp|NT+o&fV`(FE4sKpJJi82p%;kT@^qL82j&pcfT@9wmPr}snic@#FK?{hhUq z(FkHbfdSTi9e+Vsl?-6t^6KnQZzXX>hnxldSu4Ra%GZdiA6}@Z9Z{s76!m64jk(!YKUnm! zKtJDUcrDK6S%NeZN*AEIBCC&kte1Fiw1wn`v+63nzVBe%$bImwEyex9^S6GdM%4_J zD$wnY0%ycgdKE_9Ra}Gqsd{^+Jp|cVwc=Z{WF{_|9htkfI-kkdSsW&5{+}GE$X=gg5=0Zm8uOB~`+@2e)-~&K-E?j%?q-DiLKr)EMjh=~R z*Xq>wXEoKx0{3br3J3J+>BdrdNW7_me?%!|2Q}zn=rFn}AO<^h`RU+eK9@w3uyM&a zGw18SFoqFI>-dEyx1`j~qQ?ZRIb((^+jC-g?{{^Fh_h%jgAe)-W`V}gf}sSHk!Rw* z=)0PE$)*m&dAe9*?v-blqu4$;`cgkUjxq4gBFX3GHwg++tKG_m8Xvf76#$>WWJ{l~ zAJ06{xHgs(Dz#ql-~~PC9U_x@@;5i$MvB{rD{H-|q&{rle0v3rjB$||tK1XnRl26?70S4~sBm75=Ca-wYQJv>>xk-mXMGWIkBH6X|) z)ZNR+IVQ~CCp831i4XK4;={ZG{RkvGk8nt8v>UlJA|b~%0|)(kAqb*=uY`7fBox95 zvckOQXBrsn!u0tz3{JqH&Q@cr6N6JOeedT7hWngXRu_?@U306$F20}U7dJk9KAavY z*s(5V#F1%^$8?Ac0njQ3X3%A0(lG&&p=|Q!&*9LCl!!BD&^;PX&142{m1A+HtI?uh zC{>yCMrgp|PNMXUhf(ov4y} z+H$w_Mvgqhiya6I61*ZKbTvyh!?Z2egsmd8)To9dbS*AEbBn^_ezer+M&*$a&Y=&v$wuzn3bTETJLZihpRO(w*meKX``cN&>;8%y;1^VzKG`;Txr`MJ!_GS4S=^9lUD3$zmt#dkMY?N6qNLnt!d~a4_)Hkt&n1F@j7m%Xzn$TGfPPMC`aph|joKTI#K{G2+CkCCpTcw`uhmBiwx5^E7)|p8QOgt-9%K zdAEZ2v~E7nX=wP2B+(=PFoBS8jv#62#6nX~1W8LKm=@k5S*E)2yJ<^>>=zczdyyem zGa<$NO#1i=w@8$$4FBi9f`wmtrWtpfmA18x{xo4*)_?W;=CM`#U9>Ir)p=?WxbyV) z!aq%Ju8LH3cxx<$(Vv?P`LGl+s$n;GxRM!g{)m4y_wh$H_JaJfqxF)St)q>K zj`QC)t44iqG5r%4p#L5h0gTporYo2)gasV$#3xnZ2hVFx;cJwmR6cW}?C@kL11r+U znt;QSsXjr0#IR7WC>s>kA)M9EJ28wx4NNB_Ik@{ng3|3$vePoGiRCF?xf!;x_9(&A z=#x*UEegU5@8pM{AOmFO0%2tu8iF(R_DA*(4iEPtttJO%hG9@lKgMEdi0Xu{Vq4o~kAchE9Ic#UV;&=UrOfAZCVJU;vKhxo!K@IF{LXBN>2AXVmSdir~?IyK2D8=%l3)Ms|`gG zY?c|cWXXKon{);AByu1&D)dl@%PR6!db zjBIPsbN)*3j2!t_)f}Lb08^+Y4$R&U1W1`V_m_F zypWcPS%}1=ocrOIqOF?Iqf=v}(6iA>xnUQ&Yt4dg=pb^!Wp44MU)It|N)8KX4ipWO zv7{{pXhkcU`b)CWh+uY%QW`|OF;LfQxlJ+)<1%BB@7et({!A(dL1Gok(pi&ixuX}b zLVhXixs*-avYxe=(zJRMu^}7z+`}!sHZ&s&Duuy$fZ*v7a8d15GA3Jvz`#<~HBGAe z$T=N+{mwxa^r9YMIhe)eU`qY~0^2n2R_+ii6VYcYaUG?&*)n3G8`j4r;uk|UUj1Pz zO|0&45Kk|!y%o55n;T>6V3IFuQ1&WD&5Kv9)@gJd24<6zj;+_rQHd9IkUTFBV3rhz zcDs0p#^Gf>?#mlL;xo^I-8&Quxs9Q0>CSg-=VgcL`=RF)z2xk5 zvs3Bs_c*5H?e>%90GHWBF+eCIy57Kp3X=VDGkM_9xj)|ruKVJi`c;V>4)D)xs2`tH z+Q*-H2UQ*h3Z;UD+RycMTOynEUUwIY%jTxvuc20r{PpUdTP{y2pk194Qw!)~d#EeL zKydFW20K7Er(1toCg4fU@`AEzL5lYdF18A8EtkNQ?eN19_jsU88q;SMr0%UCCGA~GXCH9j#Z67T7mP)ewZ#i1-%tz?Ycu@HF2 z30O|Zf(beS%ODecu-7lr`s2`aFUB`&YI+ok{NT5+I2JuQFf_unIkz>v3tOJBfo?Az zxPCu!ZDrJot|u<{znD`mGgSS9b?S+V905Xn%u16Z&?*;5AV$$Zl*gPZIb4wWIPks@ z(Sj5$@z*Wg9dz!4M0u;51^qAc!Kw1r6NWG@F>*4uVX(}4<#K<5xU*m!%~^CP@tprR z^FxKAo*d=6^Iwy{s&>Y4RA0mp2n4m$5DpEpT$aN$i_Ah>s}P!K)PNU5r6926*|)Br z+jHXSJF_%$sh&cpQYF1@_(+E;GoDOs;**lDX5_zU<>!0*SRjmrXgL@h_w@TF?+ylA zC|ql#DwIX(=3Er+rHa5<3`SV0V!;Vq{4j8^5INnrRa>C!5dXC{t)NSM)+BAzS06 zzKV1V|Jlr$B6*vYqOjrI3DulQ0fn)0n(?Zwe77Lk_Em1OO~i5K%f3QDl+Z9_Wa37^kF9)_ zX0dMmEOW~4S97;-98lR-x3zN?=6~F@7KN4{G3SN~JV8C|kQu<(TX8(^oUfN)kz+R+ zTMKRm+D(j&<|?izKQNnBb9b(d64d_;z7e1_)yFDsUkSP|68r^tTc6XlSAgZl(uX_D z4=&3`Up$o$xxMk?{?K^bgTCRVIDxWq?2(nKnl!<20GxfEhD~AmK`E>dnoMMQYGkT( zrjuV#S1G$&_;e+hkxS5SLAXVVSTKIbuQaB3!Pt1=qZZ<-y6+gVZ1ZxCh`v4jiqsD0 z^2fDLwdRp#zht2o9=%ds_k+i=d=1_Xul(L#XHJqI4T`oCONDv%7mxUC7vw7p1(8}>4f;wgvIcvASo)^Aqyyik~ zbA||{et7A|2yLv{ zkDU((G+?e}G-5pS7dg?LrC*W%YL|w#1sAinZ~^Ox%fID1Dh6`g@vUjG#z5A z|LQ)-AXpI?oBXM5IcZ*R@{&X*r~U+lcyH*uew+&}3C|oYOIPv{BfwclS)*IgCC4{IE}Hnj$rkGy&yZ zwO$Bp>I(!$32o_~zZID1YC z@NGZ8Qh5%rxM8ckW6MjDnLz_h0Qu~Fmmt~e!DceTUZ+m=-~L4wdL z7gEKNu`Q4i4NV(4ce*ADYDI=hu-Z8p(LX@6Gd%1owv z$mF4Q#D=CyZR@KE*`fmJ_x}{D&iu|DGe^Ry4`$@BG6&8-=gW;QE9bwZ^Vu$+wS}l{X1C=1__k))@&4 z3WkxrJ)wa?F=6;fN))SWXuQ8SLvl)7qW9@cH=EG#Tr0oOB2;=}G{G&L>g614r;h&z zN}S28Wxr9<)5C=9iVcEvGmVV)XNADJMrXzgW2R?D`sWIV7MDJT*mS|y`x{(`b{40y z3Xp5N(3C;eAz_+?Y>JAr-Dao=qt;^}0|&H1h)$d!GZO^=;V6v19Ys>rOg+L+^jK8L zqj^!2iA6Bf@amo_IYI7mQSP|Y!u!Otz#u!1&r9mbqW2ItU{A#ECET~z%1xq)_vL7+ z>Hm~;UFk3V>$dpBA%XTMn)hM>cLka>S;M(m&`LvWO~!qDGyEEY~0A+%~vSiSBkBv?Durz^=?}o)ma_KR)3m}o{tYQ^g{tk)kG z%9hvZY1Qpc=TEjBM6Fq}v#R1395h#tM z8@zTZMpm(vI*Al-i;8B`US3N&HP>P!5$k4+iBMqrQ)vz?;DQqZEj8okf+L9d2Oc8V ztj@ZH*hi{Tk*50sR0mh>9LpP)^b9z_SWd{7C9*Ty03W2Qg&7KR5h4DyCl+ljFCRk# z?FFrjB=lZV5D!CSCM~NN9f_yMk7U*oEgJcf^j*%q6q^lBZ|+P6|D~h2g1HE<7suMS zBXSb$dsikCqT6&wqa^|7h9MJ`W2PZ2TnT8mA)g7=0%2q4sr<+K1gXTAPiaN2zP4a}uf{=_G!=it(f)>w=`P4l@$7`p-&Ri$EE2q3Os82CcDu=wA2x<0Njo(P29?Qos8hFB~ z*tDZ=^^$u3xz6MWm1wA4LqAnrF0}Y^53;#gT%)o^hDC@7U_9t5kL5r`W(HEkM^~-t zFKRDmaH4U9w$Q@+Y2LE;bjAo}57?@#5gftJ@i{jz$=w1!t~!^%L-oWBuT2I3F-~^{ zs+#>}ZJxa!FbZ;ZHCM3fHAZMufp|FzREa~~LF*-MwH!4SAO>+90P^W)3MQDlN49VV zazT7x>WzO9n_t zJ(5>vfvy7aC2ngvLh(MSG(BF@f$LFvobO z(|+zD*%1i=`N6@s;@rTj=t^orz5`O-0%c+>&5)hSO7MWP@}D%X?~z@kf!}g6I>rS1 z__}L+Y?3fw2O61W>UYarTUqT2wqN=*=@2~p85&ZsztVs7ZMjJ`MKo--2DdTx)ft^n z0K!h%S2>H#TY@my{{aeD5}ni@E(kmh6SZ~{xqAW>v|-Th;`>Bi&XS%nx>%3dHLK*! z!#$A)X|g`;EO#HZXlIOH5FtVX!u-NN# zD0nAS4~VHFDX43CdzSYNkDVl}u&i4UnB_Az-U`)RQy1=e{Y1GbQnecgiNQD$P`5Yl zm~=hEAoc399Xy&f|9qOu@?y)1+uL+r<=xMmiHfZ{#&yPPZ-rC*W`9iBoSIm2s7cpz zb=#lUt4=nrD^xjoGEV^G#}**2_EDnbe7|~iDikZYJRiof_&P0vI@4i^ZwsRIW+4~VP#Fl?p+#nVw!~W2hx~rk#5yo68uwQ9meS9-)sZ|tSy>dC_+v|8jD*lHjJuKg+prw zG>oJ8SQ@6OSGH1e>W{0()@jvcwiy9eC%TIxUrdk6g>2pptiZLx#pfEq8^|p)sc_pC z00$FJ1%h8PSZzwW2sO&fQELF?wODups0`xz&bb^VZeqSxk5(oLQEP@0JxaFKDvaKq z($)sglCQinmNRqPGIJj2Q3wiJ(|p}KI>uZ5-r2`<+EhXPgeAOBaWvos^=Hr9#=6@K zX@A^1VaeOz#)=v5L3h{ME=c&yG=uLm;+&fV8;;_?KP?3%Ois9XhMz&z(Z3Zz50;#s z-w?XEL^Z1~n&mb9lL%-o344e5XZz}K{daZpPoVrqO#V}yF#h)xA+^%^a45{Bx(e$C zMawT&Z{S6@4&IGNUOBkohQyOlC~q4-qC3fxYG!@f6-ElhQGFw$L-CdYX1>uLl*puD zvR8mFG}$ApD5KadB*d#ClNAesv0D6Q2n>oo{gMn}<>zPW?nbu8#=tt6hDVrM>OEM8 zMu%Hs?N7X9JkEY`v?a!2fpuoK|J8@>osId}wUPZ0($VfF=-2I?`;#d|PdIPn@5aQ0 zgE|+b@>k368IFzN4qc@U%yr=;-t4NX!Gy$)1K(+IfEZ#Vq{HpHE{e6qDrh#{hrP7Y z3S)tLD<3K>yw4I2xmCdT_{Bixne9w(eVS!koNNOBJr&x?EJEO7pc)}-f(qdrC`!Y1 zB$I5=AIs7rvq~pzK#P5^nR$q$H_n5kCn||0dX2V>wnB#SLi1IwVs9)$_bbt`5yZ38 zsPXN^R^qt0c15C`3C(#Uyqaoqas74C#U}+qSsQQ=qnoC$t^I8XGbe$$1Ih|)qahHY z=g!Z$@4W6#dZr<*jQ`SLo?i^PDeP%7^Rf>6tgoTMab>>YLix9!c=X<8LK>?;;}_FY zTZ63tGelJ~m;nxTA|8vF|EQn+k9LWvhm^6MSWrtX&Nn%QuJG|_M{ z*JEJNo*0b~VymaZj)mI@Em3TY__9a_eHJgw#iHYBpfx=?%b;F68XzG-lDuGQ1-Ft= z+lyNjkNZ%n7iJmmm~V;0-&$i~7>22{hx;WT(l+ntmf)9Un&^#R^>FN5iO;Tx*0%LI2;;QB3TmvqDsmh1 z10uDmfDel=zOUv8R1mdIa zmx9`9#h*y|Mq}lVPML!kwRZ$NdlK6#XPqS_aGe}qrfqO6cDPzP2iq@fnMgH{$NMlw zjk5SCR{m7T7!wM8eLlL_0v|OVS7teLBV}DNHwQG64tQI2!jsySe`v{Xp8UHy`L~w* zhbK(`3!Z52u%Iwi&2y4=Gdm(37av}SMo@e+=tCV)A|B~Q@$n;)SgE1DW^V2wFlvl1 zG4dqwFa##xy(!4>NNAEj%*vKvo97*G8}z~>#y`9=*wGWhVE#8wKpd>6ld&g2VdC%Y zMMATxkXfHa>25t3 zlM+{^$})t7mn}E!+~0MH!u^+dbbe|zZXx)M&VI_|8|;d{LCOx+xDI)?=tT(64mgVc zY~Jf{w2GNiOri#Z{k#?Q&e3ZdahbK{ppQ5SweSMoui!e4O_CP+uyl%_1;!gI>QQ65dMwPS6gJfP246`S$VyT50`9GD6qv~Mav6%^hW53qe- zQLT#ij6*y(NAjP0_UDh`%O=q9u)sNaiD0~NQ172yXVD^_9ibqkn~Is~nZ3&kCOq;n zCYH!wR)$dJmI58nxu#)axQ6Mfng3tD1q70$Tw*}<2osIqfk0RB`Hk0peU3h5i7-oA zen5y)FdtY>b;P#t@fllDlPoEzN!C-&4)s=6R(|Vs;{>O(?x`AbSIC5fN!bay{H^#y zROSagu+Y4*u+-^@Hc`ixuvu((Q{0JjE=v0bw9+ zZ6==brakV>vTNU@3@v*~>({~E$%rVmK9282$EHJ1znfRN$lf+`>=Rs-E}1Otwtt?T zt^yF`K=<EZ>mt*sjKR@S%FZ7*^8wVjTG^C@L8+HXmLNJnCdKb*{oJ$mR} zS$*YB!3xFKF7!y|b*vczgF^Y-*1#&voie#2M*3BjyN5p{h7?|1`I=B#&F|`obnz^N zn6WZRIuX|GMtu|mK7B*)U;ZsAAC+bO@6^N37(wP`9GY!S|5Wt_&j#8<0vHf!4d;s8 z0gyYV)3;~B9@5qqj32(QrL}+6$KC3TetceOrMz45>b&h=-G>Mojlz9mTz3~mda&XLm zhao*EC?7vxBH5oD;A%&tgux>02&C8uKQm}ZC=TY55S$bf7iepp;Tc|-nC}@7M8JYP zERZJ+?1`g*PIj8S^`f9b{N3G5Oh_o@Bc-8txc7r+($Gln+pL&+(9|@PJUh3*G&2C} zTx*=Bl%3Z0kB$a!U|rxe}jwNY03EfMz|=8$5o!QxS-aViig9WFDsJ=+~}u|_S_ zbIam&rkZ=WmtM;lH~6#+L9Thc0nRA{=9%$oRe~Uv^o7c{6z67Osmu~5BjYdqcK(oA z+i91DMaP7W*E7|QigZfXIousgkkz~_{~ZNqBX)udfweI$TUbxqy21_*Y8+_GYSMA6H4FS~WfE$23*kBhT} zrB!kLrjwz05{u%xkU;wporp3=-iG6b?gLNG|+&CTxX_MvBum9oNY5p^aW`McjY zqL!}&mX*6`R+xq%57xIMc;w%RhoeB=Tam0Mg%&fzyDv1kVo2VYlcPEM=yAd-Pj2f8p3BfN*lC4R4ny7g7j60XQ?lTyQ4P7br zHy`Nk@^1#}VB7oQXbSkH8U0kg^uW0Nb;GwTJ-m4uT)7E@HZASF(^D=Y?u6+fJs#fa zbq%)ta^LcrbUDZ3Ln$bc=(aIq+p)jz-3dEi6Z}P0s{oP*jW@r=rCnnvy|N*^1Gs<| jscie#Rue5X9<`z0E$lxv') : $('
'); + + box + .attr('id','infscr-page-'+props.currPage) + .addClass('infscr-pages') + .appendTo( opts.contentSelector ) + .load( path.join( props.currPage ) + ' ' + opts.itemSelector,null,function(){ + + // if we've hit the last page... + if (props.isDone){ + showDoneMsg(); + return false; + + } else { + + // if it didn't return anything + if (box.children().length == 0){ + // fake an ajaxError so we can quit. + $.event.trigger( "ajaxError", [{status:404}] ); + } + + // fadeout currently makes the 'd text ugly in IE6 + props.loadingMsg.fadeOut('normal' ); + + // smooth scroll to ease in the new content + if (opts.animate){ + var scrollTo = $(window).scrollTop() + $('#infscr-loading').height() + opts.extraScrollPx + 'px'; + $('html,body').animate({scrollTop: scrollTo}, 800,function(){ props.isDuringAjax = false; }); + } + + // pass in the new DOM element as context for the callback + callback.call( box[0] ); + + if (!opts.animate) props.isDuringAjax = false; // once the call is done, we can allow it again. + } + }); // end of load() + + + } // end of infscrSetup() + + + + + // lets get started. + + var opts = $.extend({}, $.infinitescroll.defaults, options); + var props = $.infinitescroll; // shorthand + callback = callback || function(){}; + + if (!areSelectorsValid(opts)){ return false; } + + // we doing this on an overflow:auto div? + props.container = opts.localMode ? this : document.documentElement; + + // contentSelector we'll use for our .load() + opts.contentSelector = opts.contentSelector || this; + + + // get the relative URL - everything past the domain name. + var relurl = /(.*?\/\/).*?(\/.*)/; + var path = $(opts.nextSelector).attr('href'); + + + if (!path) { debug('Navigation selector not found'); return; } + + // set the path to be a relative URL from root. + path = determinePath(path); + + + // reset scrollTop in case of page refresh: + if (opts.localMode) $(props.container)[0].scrollTop = 0; + + // distance from nav links to bottom + // computed as: height of the document + top offset of container - top offset of nav link + props.pixelsFromNavToBottom = getDocumentHeight() + + $(props.container).offset().top - + $(opts.navSelector).offset().top; + + // define loading msg + props.loadingMsg = $('
Loading...
'+opts.loadingText+'
'); + // preload the image + (new Image()).src = opts.loadingImg; + + + + // set up our bindings + $(document).ajaxError(function(e,xhr,opt){ + debug('Page not found. Self-destructing...'); + + // die if we're out of pages. + if (xhr.status == 404){ + showDoneMsg(); + props.isDone = true; + $(opts.localMode ? this : window).unbind('scroll.infscr'); + } + }); + + // bind scroll handler to element (if its a local scroll) or window + $(opts.localMode ? this : window) + .bind('scroll.infscr', function(){ infscrSetup(path,opts,props,callback); } ) + .trigger('scroll.infscr'); // trigger the event, in case it's a short page + + + return this; + + } // end of $.fn.infinitescroll() + + + + // options and read-only properties object + + $.infinitescroll = { + defaults : { + debug : false, + preload : false, + nextSelector : "div.navigation a:first", + loadingImg : "http://www.infinite-scroll.com/loading.gif", + loadingText : "Loading the next set of posts...", + donetext : "Congratulations, you've reached the end of the internet.", + navSelector : "div.navigation", + contentSelector : null, // not really a selector. :) it's whatever the method was called on.. + extraScrollPx : 150, + itemSelector : "div.post", + animate : false, + localMode : false, + bufferPx : 40, + errorCallback : function(){} + }, + loadingImg : undefined, + loadingMsg : undefined, + container : undefined, + currPage : 1, + currDOMChunk : null, // defined in setup()'s load() + isDuringAjax : false, + isInvalidPage : false, + isDone : false // for when it goes all the way through the archive. + }; + + + +})(jQuery); diff --git a/plugins/InfiniteScroll/jquery.infinitescroll.min.js b/plugins/InfiniteScroll/jquery.infinitescroll.min.js new file mode 100644 index 0000000000..04c75c4566 --- /dev/null +++ b/plugins/InfiniteScroll/jquery.infinitescroll.min.js @@ -0,0 +1,8 @@ +/* +// Infinite Scroll jQuery plugin +// copyright Paul Irish, licensed GPL & MIT +// version 1.2.090804 + +// home and docs: http://www.infinite-scroll.com +*/ +(function(A){A.fn.infinitescroll=function(N,L){function E(){if(B.debug){window.console&&console.log.call(console,arguments)}}function G(P){for(var O in P){if(O.indexOf&&O.indexOf("Selector")&&A(P[O]).length===0){E("Your "+O+" found no elements.");return false}return true}}function K(O){O.match(C)?O.match(C)[2]:O;if(O.match(/^(.*?)\b2\b(.*?$)/)){O=O.match(/^(.*?)\b2\b(.*?$)/).slice(1)}else{if(O.match(/^(.*?)2(.*?$)/)){E("Trying backup next selector parse technique. Treacherous waters here, matey.");O=O.match(/^(.*?)2(.*?$)/).slice(1)}else{E("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.");H.isInvalidPage=true}}return O}function I(){return B.localMode?(A(H.container)[0].scrollHeight&&A(H.container)[0].scrollHeight):A(document).height()}function F(Q,P){var O=I()-(Q.localMode?A(P.container).scrollTop():(A(P.container).scrollTop()||A(P.container.ownerDocument.body).scrollTop()))-A(Q.localMode?P.container:window).height();E("math:",O,P.pixelsFromNavToBottom);return(O-Q.bufferPx"):A("
");P.attr("id","infscr-page-"+O.currPage).addClass("infscr-pages").appendTo(Q.contentSelector).load(R.join(O.currPage)+" "+Q.itemSelector,null,function(){if(O.isDone){J();return false}else{if(P.children().length==0){A.event.trigger("ajaxError",[{status:404}])}O.loadingMsg.fadeOut("normal");if(Q.animate){var T=A(window).scrollTop()+A("#infscr-loading").height()+Q.extraScrollPx+"px";A("html,body").animate({scrollTop:T},800,function(){O.isDuringAjax=false})}S.call(P[0]);if(!Q.animate){O.isDuringAjax=false}}})}var B=A.extend({},A.infinitescroll.defaults,N);var H=A.infinitescroll;L=L||function(){};if(!G(B)){return false}H.container=B.localMode?this:document.documentElement;B.contentSelector=B.contentSelector||this;var C=/(.*?\/\/).*?(\/.*)/;var M=A(B.nextSelector).attr("href");if(!M){E("Navigation selector not found");return }M=K(M);if(B.localMode){A(H.container)[0].scrollTop=0}H.pixelsFromNavToBottom=I()+A(H.container).offset().top-A(B.navSelector).offset().top;H.loadingMsg=A('
Loading...
'+B.loadingText+"
");(new Image()).src=B.loadingImg;A(document).ajaxError(function(P,Q,O){E("Page not found. Self-destructing...");if(Q.status==404){J();H.isDone=true;A(B.localMode?this:window).unbind("scroll.infscr")}});A(B.localMode?this:window).bind("scroll.infscr",function(){D(M,B,H,L)}).trigger("scroll.infscr");return this};A.infinitescroll={defaults:{debug:false,preload:false,nextSelector:"div.navigation a:first",loadingImg:"http://www.infinite-scroll.com/loading.gif",loadingText:"Loading the next set of posts...",donetext:"Congratulations, you've reached the end of the internet.",navSelector:"div.navigation",contentSelector:null,extraScrollPx:150,itemSelector:"div.post",animate:false,localMode:false,bufferPx:40,errorCallback:function(){}},loadingImg:undefined,loadingMsg:undefined,container:undefined,currPage:1,currDOMChunk:null,isDuringAjax:false,isInvalidPage:false,isDone:false}})(jQuery); \ No newline at end of file diff --git a/plugins/InfiniteScroll/readme.txt b/plugins/InfiniteScroll/readme.txt new file mode 100644 index 0000000000..3ce3b7fd23 --- /dev/null +++ b/plugins/InfiniteScroll/readme.txt @@ -0,0 +1,6 @@ +Infinite Scroll adds the following functionality to your Laconica installation: When a user scrolls towards the bottom of the page, the next page of notices is automatically retrieved and appended. This means they never need to click "Next Page", which dramatically increases stickiness. + +Installation +============ +Add "addPlugin('InfiniteScroll');" to the bottom of your config.php +That's it!