From 2895be35871618bd4efd79eb2338612d77d3c28f Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 6 Mar 2009 12:27:40 -0600 Subject: [PATCH] Add custom PDoc HTML template to source tree. --- templates/html/assets/images/alias.png | Bin 0 -> 671 bytes templates/html/assets/images/class.png | Bin 0 -> 1562 bytes .../html/assets/images/class_deprecated.png | Bin 0 -> 1245 bytes templates/html/assets/images/constant.png | Bin 0 -> 981 bytes templates/html/assets/images/constructor.png | Bin 0 -> 584 bytes templates/html/assets/images/description.png | Bin 0 -> 786 bytes templates/html/assets/images/grid.png | Bin 0 -> 125 bytes .../html/assets/images/header-logo-small.png | Bin 0 -> 4123 bytes templates/html/assets/images/header-logo.png | Bin 0 -> 18451 bytes .../assets/images/header-stripe-small.png | Bin 0 -> 1645 bytes .../html/assets/images/header-stripe.png | Bin 0 -> 4022 bytes templates/html/assets/images/information.png | Bin 0 -> 778 bytes templates/html/assets/images/logo.png | Bin 0 -> 6835 bytes templates/html/assets/images/method.png | Bin 0 -> 1680 bytes .../html/assets/images/method_deprecated.png | Bin 0 -> 1342 bytes templates/html/assets/images/mixin.png | Bin 0 -> 1130 bytes templates/html/assets/images/namespace.png | Bin 0 -> 970 bytes templates/html/assets/images/property.png | Bin 0 -> 599 bytes templates/html/assets/images/related_to.png | Bin 0 -> 343 bytes templates/html/assets/images/section.png | Bin 0 -> 946 bytes templates/html/assets/images/tagline.png | Bin 0 -> 1962 bytes templates/html/assets/images/utility.png | Bin 0 -> 630 bytes .../html/assets/javascripts/application.js | 282 + .../assets/javascripts/code_highlighter.js | 251 + templates/html/assets/javascripts/controls.js | 963 ++++ templates/html/assets/javascripts/effects.js | 1120 ++++ .../html/assets/javascripts/prototype.js | 4706 +++++++++++++++++ templates/html/assets/stylesheets/api.css | 402 ++ templates/html/assets/stylesheets/core.css | 416 ++ templates/html/assets/stylesheets/grid.css | 13 + .../html/assets/stylesheets/highlighter.css | 116 + templates/html/assets/stylesheets/main.css | 443 ++ templates/html/assets/stylesheets/screen.css | 244 + templates/html/helpers.rb | 150 + templates/html/index.erb | 25 + templates/html/item_index.js.erb | 6 + templates/html/layout.erb | 65 + templates/html/namespace.erb | 157 + templates/html/partials/breadcrumbs.erb | 6 + templates/html/partials/short_description.erb | 50 + templates/html/section.erb | 90 + templates/html/utility.erb | 21 + 42 files changed, 9526 insertions(+) create mode 100755 templates/html/assets/images/alias.png create mode 100644 templates/html/assets/images/class.png create mode 100644 templates/html/assets/images/class_deprecated.png create mode 100644 templates/html/assets/images/constant.png create mode 100755 templates/html/assets/images/constructor.png create mode 100755 templates/html/assets/images/description.png create mode 100644 templates/html/assets/images/grid.png create mode 100644 templates/html/assets/images/header-logo-small.png create mode 100644 templates/html/assets/images/header-logo.png create mode 100644 templates/html/assets/images/header-stripe-small.png create mode 100644 templates/html/assets/images/header-stripe.png create mode 100755 templates/html/assets/images/information.png create mode 100644 templates/html/assets/images/logo.png create mode 100644 templates/html/assets/images/method.png create mode 100644 templates/html/assets/images/method_deprecated.png create mode 100644 templates/html/assets/images/mixin.png create mode 100644 templates/html/assets/images/namespace.png create mode 100755 templates/html/assets/images/property.png create mode 100755 templates/html/assets/images/related_to.png create mode 100644 templates/html/assets/images/section.png create mode 100644 templates/html/assets/images/tagline.png create mode 100755 templates/html/assets/images/utility.png create mode 100644 templates/html/assets/javascripts/application.js create mode 100644 templates/html/assets/javascripts/code_highlighter.js create mode 100644 templates/html/assets/javascripts/controls.js create mode 100644 templates/html/assets/javascripts/effects.js create mode 100644 templates/html/assets/javascripts/prototype.js create mode 100644 templates/html/assets/stylesheets/api.css create mode 100644 templates/html/assets/stylesheets/core.css create mode 100644 templates/html/assets/stylesheets/grid.css create mode 100644 templates/html/assets/stylesheets/highlighter.css create mode 100644 templates/html/assets/stylesheets/main.css create mode 100644 templates/html/assets/stylesheets/screen.css create mode 100644 templates/html/helpers.rb create mode 100644 templates/html/index.erb create mode 100644 templates/html/item_index.js.erb create mode 100644 templates/html/layout.erb create mode 100644 templates/html/namespace.erb create mode 100644 templates/html/partials/breadcrumbs.erb create mode 100644 templates/html/partials/short_description.erb create mode 100644 templates/html/section.erb create mode 100644 templates/html/utility.erb diff --git a/templates/html/assets/images/alias.png b/templates/html/assets/images/alias.png new file mode 100755 index 0000000000000000000000000000000000000000..f135248f82e3d0b87d29d1628057f62dc51ec6c6 GIT binary patch literal 671 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 Hu0mjfmT^=9 literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/constant.png b/templates/html/assets/images/constant.png new file mode 100644 index 0000000000000000000000000000000000000000..c4295ec0df9bb1921471c5f6625f77eb2084cea3 GIT binary patch literal 981 zcmV;`11kK9P)X+uL$Nkc;*P;zf(X>4Tx0C=30k-tkDVHn3h?`a7X&C=7>f^dVF3{iqv zA{4=7u%bg61d|NHzBK!xR*f>o*3ti&0;^aFtHL~^=Rn&-~=^Bn>3ZOoR^ zKWe3pe-FLg{jxN+dAf6Tes>)JePN|q17QMYLvtE1>zZEx=4&Mth!S8rE4B;51v246 zxd>t#NH#R@0?E4O10cEXG!%$7kPX~s0OA*rcfH5~BMm4=h6;@Lz(}Q9v-D_c4yJ~o z=cMb^BG~&3Pe;36`WXx?!eOrKbzUI=F?bR!=OzFUeFb=Q8ONPbNW6pV?KuAXF^;c4 zLC*!W17|H<|92N*Ou~Iy@20i>0qDNBv)&(oEPQwgi;rP$3wC}$Y9F3_g;GB(Ok(7J z{!e`?0G=0ZzgZ7$<+)aQreGCYek+Wm?RfV*`k|q`HwvKGk{e;Ov7)SLDSag{~ z6ul2f=m2>zm_P#JUodfUV{_B6b|Qu_bZY9*fs}!z1I2~MXh}#qt8q{k8Jl2YQW)w~ z6&ur}3B&;J-FxoG=Yqz@J_bGOIp4YWp6_0w|AZ4p42Q$##+WhyQq|*PvABDiE)r&- zs$~EN01iZ?9Hxtf5dg>-^Fvh$K$tAtfSIAH#{dYxb(rq23Ak+3cZFLn3l2BBZMCLT9-RCnqPi+wIy-n$Qf0h?sd} zfWHm;{r(O!?*TX}l}g?(Qbb5ZZak>fYC8b-035YiEibmN)ZU73k>f<#ys_qjxbpGj_f*`mavW#-^4lei$D>!)+Gjx! zTql!BpD5&*8jZ#y08d1uxIU)$0A6-Fowpmmg}f4o)2%U3C;eEDoiEh?94d(rV57VIF#8VqzW$HrDC|#U`x@QDbgi zVl)t9GGz&YY#D?gc%>hISA+_EBpnXt#pnC`p6@xw0$8TCbULjhlgVx(kuc)%xbgqq zR5+DNDFRN0!y)7Gm}oT0i39}h4h928qY?Rho^UvPGJ#kuW|-Amtrn`Pmd&+bFo@sp z$LI4IQw7BG?|#2ewOS<<3VjL$0=lMY^m;wqZujv5kx1l%Sl;V&Iy4#$ip3&@LV2!7vhhN=PCz%^9v24`qb(+m4W?!q-&~=?ssf5GfnAmJKV;3bvpDm0(NhahZ=&^sqo6Odj6>)Dq_3p~4~ zvb`d3Mydwjt&Df^hVmLtI2x=U&h9(JVYX-!y~z3zi;1>=LY;o(bL$(Yf$lf)dMf0-u^0HrpTG Wk@)HE*94aU0000$XgYMs^AIOw1Qr{*Wn)N-{9ma}x2(<~`9Go1=*>YR!KZvrBS zCd!u}@M0og%Ev@_;Z?Kk>Wwv=%h_57zmt2<_1msz_niYE=YRNPpd%02TK9oK1z z>ooPno}v^sikz_|1XHFx_L%~;ljh7i(jiay5F0x*+(9aXXFCl?AdQj5XlQ65%sEv+ ztfe?|YcjPN*@yYtE~ImQh{l|#A6Z8iu>pf43Rj52CzU_dMQm|S2xR62YjQOn+z8WH zaK=!}ggOZi{4pB7SQ=xC0n|vXP_Bkx_a)FeNd}w8U97BNbSWxa^QW-li9BZ#M1!_xE*?wzt^GcoeoL*JGLSe_+l-JT2#2tz!z&^ z_s5anq&^nBklIMwRvcoP3%qs%%Ea?1c{_*V*Xj&~uLu-2Dp1fUN4<0zMo$EH>*U83 zm_9;Vt%-bE{_J_!If!1y=c+`QVZ>0_BPy z+%^pgnv`f8H)Z%0&Tp8&u*MCIC4igNW5MeWM_DHpDNi)Zxz|9XboOnitwFq$ETN=X zj-tkCJnz**Y4k#6_Ty^B=hWo~L!47r`HoP=x&3T1)JLr2t2+#fH+_yahq&N#aB8wRqxP?KOkzv*x380|9 zr;B5VM`tn*FRy8u#Il61udb$FJUWBzkRmguo2|{AgDcwGttGyGC}3YKC-;tlVcujG VkEr%q3Ebi3?(gu~f+|<{`v5`)AW|R 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 ZzyQC?_H;||rKJD>002ovPDHLkV1nUx@F@TQ literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/header-logo.png b/templates/html/assets/images/header-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4f6c7c18615bb6e0ba033f681a7ef90f2009e312 GIT binary patch literal 18451 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 literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/header-stripe.png b/templates/html/assets/images/header-stripe.png new file mode 100644 index 0000000000000000000000000000000000000000..2254f7c83ac38960f30066a8c68bee5bae95692d GIT binary patch literal 4022 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 literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/information.png b/templates/html/assets/images/information.png new file mode 100755 index 0000000000000000000000000000000000000000..12cd1aef900803abba99b26920337ec01ad5c267 GIT binary patch literal 778 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 literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/method.png b/templates/html/assets/images/method.png new file mode 100644 index 0000000000000000000000000000000000000000..35efa75949d7c79947a61c38a1b54381b122fd90 GIT binary patch literal 1680 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 AS^xk5 literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/mixin.png b/templates/html/assets/images/mixin.png new file mode 100644 index 0000000000000000000000000000000000000000..11a7f8fed4227c4902f8acb9d3a1f4089d37ccbe GIT binary patch literal 1130 zcmV-w1eN=VP)X+uL$Nkc;*P;zf(X>4Tx0C=30k-tkDVHn3h?`a7X&C=7>f^dVF3{iqv zA{4=7u%bg61d|NHzBK!xR*f>o*3ti&0;^aFtHL~^=Rn&-~=^Bn>3ZOoR^ zKWe3pe-FLg{jxN+dAf6Tes>)JePN|q17QMYLvtE1>zZEx=4&Mth!S8rE4B;51v246 zxd>t#NH#R@0?E4O10cEXG!%$7kPX~s0OA*rcfH5~BMm4=h6;@Lz(}Q9v-D_c4yJ~o z=cMb^BG~&3Pe;36`WXx?!eOrKbzUI=F?bR!=OzFUeFb=Q8ONPbNW6pV?KuAXF^;c4 zLC*!W17|H<|92N*Ou~Iy@20i>0qDNBv)&(oEPQwgi;rP$3wC}$Y9F3_g;GB(Ok(7J z{!e`?0G=0ZzgZ7$<+)aQreGCYek+Wm?RfV*`k|q`HwvKGk{e;Ov7)SLDSawM1loO7=O*nQ&43XAEwK?B@I!!QHP$iXIDB@)Zw z_Yba~=>VtzXpDz(uCw0V&d|3Xn2jevhAE~n{Np!c-cYKGXG*WyU0=GU208CZUXij|ray9|S)-$fu9z z=~#Z7`t~7qovNSyy9G0nDA7lJl-!OOL6jtlj14e<-fPx$t!KfkW%Rwe!K0TC&#pV# zHnSL?K}t#t84!{(7KIQ6pOn#`_gLMz3MqtDZ95Sc*-+mEj$=hupoAnOpYTyBqY$HJ z`Ce%J`byPJXHVC008Z|>#FDu^IB1!efrueN@G*NC6W%K!DBnjKy!t%Ixw{7eICtkD z?}naZ;PX2$gQ8&V`X0n|iiz^F=Q;S7G4UeK0OMfUO5ETsAnA wf8IauAA{zZ*89-%6kNdI7iPVWd%v9e1Ax=SeX(cYBme*a07*qoM6N<$f*KS8aR2}S literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/namespace.png b/templates/html/assets/images/namespace.png new file mode 100644 index 0000000000000000000000000000000000000000..f2f7b73ddb76a58b4ee1378396b9de776b6617a7 GIT binary patch literal 970 zcmV;*12z1KP)X+uL$Nkc;*P;zf(X>4Tx0C=30k-tkDVHn3h?`a7X&C=7>f^dVF3{iqv zA{4=7u%bg61d|NHzBK!xR*f>o*3ti&0;^aFtHL~^=Rn&-~=^Bn>3ZOoR^ zKWe3pe-FLg{jxN+dAf6Tes>)JePN|q17QMYLvtE1>zZEx=4&Mth!S8rE4B;51v246 zxd>t#NH#R@0?E4O10cEXG!%$7kPX~s0OA*rcfH5~BMm4=h6;@Lz(}Q9v-D_c4yJ~o z=cMb^BG~&3Pe;36`WXx?!eOrKbzUI=F?bR!=OzFUeFb=Q8ONPbNW6pV?KuAXF^;c4 zLC*!W17|H<|92N*Ou~Iy@20i>0qDNBv)&(oEPQwgi;rP$3wC}$Y9F3_g;GB(Ok(7J z{!e`?0G=0ZzgZ7$<+)aQreGCYek+Wm?RfV*`k|q`HwvKGk{e;Ov7)SLDSaP!CJ7jvau0F&`N9+R7es0 zfrNmXd+(XO*Rq(C7$jB}4s6cM=B&Lwm^JXfR|9bW=IQZfu=Bu;E}~}4fDOXfVAro~ zZ2vIayY*;e4WM~=eQ~N&`*CXS_~i855;P6;BAI<x$%k3Z|iqfAAi2xb~^NG zdSPjDdVZNN?_W|zKT$#&QYHjpBS8r>F?)iE*=0hku3h0wYnWL%cb?bJo-p{nRmHt1 zWHKRSNd*KVNE5Gzn5&Lkso6cmBV?mkfo#*WVM z=7ni(aEQV7JJju<5GtxeN)kn=WM4w14jVtRhzxDoq=ZY7!>kUGs7o@0x?bG(6e6Sc z?4Cd+(J07Kpc3SsTlQz+vMcQAA}fKZjT{!rupEe+ML31JKxv$nWRJj|h*6M(@)ulH z$Ebsxu4QOtSC>JM!|q_*6iVR`-c44Y($!-#=Tuqg?a7ZyD3vy*mFC snhVmtytAA8Ki>hkDlx|5`9HtLU+ISQ!ulZ{g#Z8m07*qoM6N<$f^1^Gh5!Hn literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/property.png b/templates/html/assets/images/property.png new file mode 100755 index 0000000000000000000000000000000000000000..ebaf0e8743fc33cf152cb7694b865e8d8adbfa90 GIT binary patch literal 599 zcmV-d0;v6oP)GWQRM3$+Tx>2G~D3qqtDdzLJ$P+M| z%_5OV?1V_vbzR8Cf4JqIVHo)K^%pXcv3TotyGW%{h{xkw5Q#dkEiV=ekof!9z?%~d z=g(E7!z)Oq(;*j#L?RmyiObN>-n-ERY$OQs{fC-WE z`TR3JBO8xbMN0KSbiO^m!^f-pEr_bBgH6ZV(+;jrKl87%5H3QY5S&iu(~XVt z`Q%tE#s-6d3Aucs;QCb?w-;^voEneC7ITEh5sgOWa5&8962;=`54d^#1;35CDRwv< z7ITTajw2Wh%6`9}(Iu`wF^PG8L%bJ2;q&>deAA2$Oi`4b;)4JRkH=$mxm=9IcDvoO l^OXPhyYjA9E`GA_{V$1@FaBct0}KEF002ovPDHLkV1kGx8r%Q? literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/related_to.png b/templates/html/assets/images/related_to.png new file mode 100755 index 0000000000000000000000000000000000000000..25eacb7c2524142262d68bf729c5e2b61adfd6d4 GIT binary patch literal 343 zcmV-d0jU0oP)$`dXYaZs9=SbAto%g@>T~?_bH&lTUn@`uo|1bXE{eSR(AO)ESb=V4`uk}mK|39Px&03WLbv~pzk+s7D@lK^ zn+aB+sp)&Y_x-B3>;6ywU--WQNUr<8>TU0P-|L#1U&;A)67w(+> pDf@fM7q9#F25QXo3rUI;002ro52U44e~JJA002ovPDHLkV1l;_q@Mr) literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/section.png b/templates/html/assets/images/section.png new file mode 100644 index 0000000000000000000000000000000000000000..d9d598569175e9d73005163366a19ab960f7d0b3 GIT binary patch literal 946 zcmV;j15NyiP)X+uL$Nkc;*P;zf(X>4Tx0C=30k-tkDVHn3h?`a7X&C=7>f^dVF3{iqv zA{4=7u%bg61d|NHzBK!xR*f>o*3ti&0;^aFtHL~^=Rn&-~=^Bn>3ZOoR^ zKWe3pe-FLg{jxN+dAf6Tes>)JePN|q17QMYLvtE1>zZEx=4&Mth!S8rE4B;51v246 zxd>t#NH#R@0?E4O10cEXG!%$7kPX~s0OA*rcfH5~BMm4=h6;@Lz(}Q9v-D_c4yJ~o z=cMb^BG~&3Pe;36`WXx?!eOrKbzUI=F?bR!=OzFUeFb=Q8ONPbNW6pV?KuAXF^;c4 zLC*!W17|H<|92N*Ou~Iy@20i>0qDNBv)&(oEPQwgi;rP$3wC}$Y9F3_g;GB(Ok(7J z{!e`?0G=0ZzgZ7$<+)aQreGCYek+Wm?RfV*`k|q`HwvKGk{e;Ov7)SLDSaF&>9#@#i!P_UA2s_XmJS4G2r9|rL8)wTC|cWcWmS$PuG;M1&07*qoM6N<$g085ny8r+H literal 0 HcmV?d00001 diff --git a/templates/html/assets/images/tagline.png b/templates/html/assets/images/tagline.png new file mode 100644 index 0000000000000000000000000000000000000000..85b366caabcc0f5751848242f79a6dd9c23252a6 GIT binary patch literal 1962 zcmV;b2UYlqP)MV*mgE5Oh*bQ~&?}|NsC0|NsC0 z|NsC00N^8C82|tV^hrcPRCwC#TG@8PC=A6Lcme$Xe>-Ra1jd=faXX!J%tO)|v|TPj z;HbUbCgc5R_s`nuyZxIskKV6eY3RM%f1~}DoqN%Fuc?#gff3#hA1dp-|Hc;$Hv4Zh zSpOv{|CpV7(fN!L#`k4P2#jiM-&B!Rd^FsJb#e2>mYlnCp|k3UEW z{Z_`gn-XM|9=Tf=*i9S9(WyT}iD~phY8F{S-TTM<#m>CG3{AP9EzH z!xnUe7k*NWeypUyfwPXMY8Zv^M3Jn~`IB%$5?`Q0C12>Y5D`bNY zZYwE>Ezd1LJg_t=j~yLvRm3}+cUF|ChmAfj51~4{(6f_f7jChzrARt<{w$p2j!P@j zF%CE_u<1`6B-DSUom9-)^sPr8Jf*-uqor`Vlxs>PBU}v;U!zk7G)a-d`ZY>ua7TG@ z)SexX%Q%5vHCD9(_N}2 z7aXmg1!M!1mWF3xOOYsY{xlpNJNk6sTln0!5nDGz-$BI7UfF3-!o=_z!?Sdr^L*vBfa4gBGg6swSEk3WA<>tajo_ijizD!Wn2ixU?!36kWOM4uQ>z z79He@xw6xsM30-D?s`nLj%c+cxr!1ANrs>)azKY$(DwND%InS2JgcaCB}>y=8ZXHFDX$EbH!yzR&9w2IA4_9JH%*`!UZMH!wF$5 zwyNbE?}sy1-=Iu!0x^}H1|^pCJXNB>Pi?)ZiyBB01Z|NL9VY{-tO)BDDKV1*n{#-i zM4UI^psgv9|A}aUKiN55Q6k0;4BtusB_$5S^s&y@(uHW9DM6P%Gi3Cd66fLUMR7?M zI{0v)2bC@Hln&Xnw9}x(oc6mpPET0CLz3IuND>5Xk&-RC2&fbh)-O`RFylMPU^H#w zd;#n)DPg16nORds2^~8ytW!#~hh+$p>Jv(Ad*xTA#CbTeXvydB1^ts0K zm7NA9cGXicmC8P>e9C2aMv1maq=bMVqf>|o>(?k@g|^{92`w|&IVCi|_VRfF*&`*) zo>K2CN;HN=jpm4DlM?!b5+~tcbvt^IZ{b|NgnR|GfPF(!Vyx`6C=nK}!Q;v8lrZ}d z_?i;Q`ZY>8p=~KCu||vn9#iy29|Bn;m%`Gb16#E@B1}`fARTg2Z&0E=EUpZp`h*gF zt_5mJoQIR_r(zNIFBm@I_e%8}x4E(-->8Vxx@(YBa1!7)y+?_*NJK|KkOC@2g!OBb z2<0j3TExbUK+fy{*0FJ}aC@zbvwly2qORvOR?GvQnNxeA1bjYtU^ZM(xEG zLWx|p(qXHhgpNCk;Uo~ZmogCLM{!)0%lsFA%GG26~%OAe& z=V|8>Zc%$>Cz7bkH97%8-L^|t|8G*FDN>?i>VSlZwBCJwg{hQyLCc#EU1{^*CUS8 zhyJ#urGa0u53TTp9r-ps{R%*d?)-cxY{)PqTuqSz9aRLR&aKJP)!DK;9Y=n` ztyZT|d*HtN4z^AtY@ehNsx1Av5@058(+4Yyzw@m$wtszqQ04yGbJhSW-PK+Sn9kpy z6c5&sKH5aCB||O zo)n!;Re(Lq>NlD(Y>~Mm^&rNjF{+zqQYLCFW%O8ObHbFoO{oHG8H;vpFN|zULKkF} znE;czLyw9^s&5nLicTfoh(h`)V!g47a4i6T`6XNhM{_uCpf3fOH)+aUm{Pd%0$HCQ zD`b=e=_a}-!2e?bhS(t8*Bx}jxG|(Bs-8zXGwpDVhfpKF$YwKX2WZW0hO6n{GpNkbaQ6*W`Eo;3}_R5=XK< z0YsI0n43^|QWPahLjCo*dA`zf@Kp|7fal9I=-yn{U+4i*ot*tN)m|#kBeuVS2r=(P z$&2x{rKt;Dqx=3$7Mb}P++9YHsIwW%;gx^mfN*2lS#X?@Zq5b--LhKUKO1nouBZGU QkpKVy07*qoM6N<$f-OlOxc~qF literal 0 HcmV?d00001 diff --git a/templates/html/assets/javascripts/application.js b/templates/html/assets/javascripts/application.js new file mode 100644 index 0000000..1948b08 --- /dev/null +++ b/templates/html/assets/javascripts/application.js @@ -0,0 +1,282 @@ +if (typeof PDoc === "undefined") window.PDoc = {}; + +// Poor-man's history manager. Polls for changes to the hash. +(function() { + var PREVIOUS_HASH = null; + + document.observe("dom:loaded", function() { + var hash = window.location.hash; + if (hash && hash !== PREVIOUS_HASH) { + document.fire("hash:changed", + { previous: PREVIOUS_HASH, current: hash }); + PREVIOUS_HASH = hash; + } + + window.setTimeout(arguments.callee, 100); + }); +})(); + +// Place a "frame" around the element described by the hash. +// Update the frame when the hash changes. +PDoc.highlightSelected = function() { + if (!window.location.hash) return; + element = $(window.location.hash.substr(1)); + if (element) PDoc.highlight(element.up('li, div')); +}; + +document.observe("hash:changed", PDoc.highlightSelected); + +PDoc.highlight = function(element) { + var self = arguments.callee; + if (!self.frame) { + self.frame = new Element('div', { 'class': 'highlighter' }); + document.body.appendChild(self.frame); + } + + var frame = self.frame; + + element.getOffsetParent().appendChild(frame); + + var offset = element.positionedOffset(); + var w = parseFloat(element.getStyle('width')), + h = parseFloat(element.getStyle('height')); + + frame.setStyle({ + position: 'absolute', + top: (offset.top - 5) + 'px', + left: (offset.left - 5) + 'px', + width: (w + 5) + 'px', + height: (h + 10) + 'px' + }); + + // Defer this call because Safari hasn't yet scrolled the viewport. + (function() { + var frameOffset = frame.viewportOffset(frame); + if (frameOffset.top < 0) { + window.scrollBy(0, frameOffset.top - 10); + } + }).defer(); + +}; + +// Live API search. +var Filterer = Class.create({ + initialize: function(element, options) { + this.element = $(element); + this.options = Object.extend({ + interval: 0.1, + resultsElement: '.search-results' + }, options || {}); + + this.element.writeAttribute("autocomplete", "off"); + this.element.up('form').observe("submit", Event.stop); + + // // The Safari-only "search" input type is prettier + // if (Prototype.Browser.WebKit) + // this.element.type = "search"; + + this.menu = this.options.menu; + this.links = this.menu.select('a'); + + this.resultsElement = this.options.resultsElement; + this.resultsElement.setStyle({ + overflowX: 'hidden' + }); + + this.events = { + filter: this.filter.bind(this), + keydown: this.keydown.bind(this) + }; + + this.menu.setStyle({ opacity: 0.9 }); + this.addObservers(); + + this.element.value = ''; + }, + + addObservers: function() { + this.element.observe('keyup', this.events.filter); + }, + + filter: function(event) { + if (this._timer) window.clearTimeout(this._timer); + + // Clear the text box on ESC + if (event.keyCode && event.keyCode === Event.KEY_ESC) { + this.element.value = ''; + } + + if ([Event.KEY_UP, Event.KEY_DOWN, Event.KEY_RETURN].include(event.keyCode)) + return; + + var value = $F(this.element).strip().toLowerCase(); + if (value === "") { + this.onEmpty(); + return; + } + + var urls = this.findURLs(value); + this.buildResults(urls); + }, + + keydown: function(event) { + if (![Event.KEY_UP, Event.KEY_DOWN, Event.KEY_RETURN].include(event.keyCode)) + return; + + // ignore if any modifier keys are present + if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) + return; + + event.stop(); + + var highlighted = this.resultsElement.down('.highlighted'); + if (event.keyCode === Event.KEY_RETURN) { + // Follow the highlighted item. + if (!highlighted) return; + window.location.href = highlighted.down('a').href; + } else { + var direction = (Event.KEY_DOWN === event.keyCode) ? 1 : -1; + highlighted = this.moveHighlight(direction); + } + + + if ([Event.KEY_UP, Event.KEY_DOWN].include(event.keyCode) && + !Prototype.Browser.WebKit) { + // If up/down key is held down, list should keep scrolling. + // Safari does this automatically because it fires the keydown + // event over and over. + this._timer = window.setTimeout(this.scrollList.bind(this, direction), 1000); + } + }, + + moveHighlight: function(direction) { + var highlighted = this.resultsElement.down('.highlighted'); + // move the focus + if (!highlighted) { + // if there is none, highlight the first result + var highlighted = this.resultsElement.down('li').addClassName('highlighted'); + } else { + var method = (direction === 1) ? 'next' : 'previous'; + highlighted.removeClassName('highlighted'); + var adjacent = highlighted[method]('li'); + if (!adjacent) { + adjacent = method == 'next' ? this.resultsElement.down('li') : + this.resultsElement.down('li:last-of-type'); + } + adjacent.addClassName('highlighted'); + highlighted = adjacent; + } + + // Adjust the scroll offset of the container so that the highlighted + // item is always in view. + var distanceToBottom = highlighted.offsetTop + highlighted.offsetHeight; + if (distanceToBottom > this.resultsElement.offsetHeight + this.resultsElement.scrollTop) { + // item is too low + this.resultsElement.scrollTop = distanceToBottom - this.resultsElement.offsetHeight; + } else if (highlighted.offsetTop < this.resultsElement.scrollTop) { + // item is too high + this.resultsElement.scrollTop = highlighted.offsetTop; + } + + return highlighted; + }, + + scrollList: function(direction) { + this.moveHighlight(direction); + this._timer = window.setTimeout(this.scrollList.bind(this, direction), 100); + }, + + buildResults: function(urls) { + this.resultsElement.update(); + var ul = this.resultsElement; + urls.each( function(url) { + var a = new Element('a', { + 'class': url.type.gsub(/\s/, '_'), + href: PDoc.pathPrefix + url.path + }).update(url.name); + var li = new Element('li', { 'class': 'menu-item' }); + li.appendChild(a); + ul.appendChild(li); + }); + this.showResults(); + }, + + + findURLs: function(str) { + var results = []; + for (var i in PDoc.elements) { + if (i.toLowerCase().include(str)) results.push(PDoc.elements[i]); + } + return results; + }, + + onEmpty: function() { + this.hideResults(); + }, + + showResults: function() { + this.resultsElement.show(); + document.stopObserving("keydown", this.events.keydown); + document.observe("keydown", this.events.keydown); + }, + + hideResults: function() { + this.resultsElement.hide(); + document.stopObserving("keydown", this.events.keydown); + } +}); + +document.observe('dom:loaded', function() { + new Filterer($('search'), { + menu: $('api_menu'), + resultsElement: $('search_results') + }); +}); + + +Event.observe(window, 'load', function() { + var menu = $('menu'); + var OFFSET = menu.viewportOffset().top; + + Event.observe(window, 'scroll', function() { + var sOffset = document.viewport.getScrollOffsets(); + if (sOffset.top > OFFSET) { + menu.addClassName('fixed'); + } else menu.removeClassName('fixed'); + }); +}); + +(function() { + function menuButtonMouseOver(event) { + var menuButton = $('api_menu_button'); + var target = event.element(); + if (target === menuButton || target.descendantOf(menuButton)) { + $('api_menu').show(); + } + } + + function menuButtonMouseOut(event) { + var menuButton = $('api_menu_button'); + var menu = $('api_menu'); + var target = event.element(), related = event.relatedTarget; + + if (related === menu || related.descendantOf(menu)) return; + menu.hide(); + } + + function menuMouseOut(event) { + var menu = $('api_menu'), related = event.relatedTarget; + if (related && !related.descendantOf(menu)) { + arguments.callee.timer = Element.hide.delay(0.5, menu); + } else { + window.clearTimeout(arguments.callee.timer) + } + } + + document.observe('dom:loaded', function() { + $('api_menu_button').observe('mouseover', menuButtonMouseOver); + $('api_menu_button').observe('mouseout', menuButtonMouseOut); + + $('api_menu').observe('mouseout', menuMouseOut); + }); +})(); \ No newline at end of file diff --git a/templates/html/assets/javascripts/code_highlighter.js b/templates/html/assets/javascripts/code_highlighter.js new file mode 100644 index 0000000..e3550ce --- /dev/null +++ b/templates/html/assets/javascripts/code_highlighter.js @@ -0,0 +1,251 @@ +/* Unobtrustive Code Highlighter By Dan Webb 11/2005 + Version: 0.4 + + Usage: + Add a script tag for this script and any stylesets you need to use + to the page in question, add correct class names to CODE elements, + define CSS styles for elements. That's it! + + Known to work on: + IE 5.5+ PC + Firefox/Mozilla PC/Mac + Opera 7.23 + PC + Safari 2 + + Known to degrade gracefully on: + IE5.0 PC + + Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors + in older browsers use expressions that use lookahead in string format when defining stylesets. + + This script is inspired by star-light by entirely cunning Dean Edwards + http://dean.edwards.name/star-light/. +*/ + +// replace callback support for safari. +if ("a".replace(/a/, function() {return "b"}) != "b") (function(){ + var default_replace = String.prototype.replace; + String.prototype.replace = function(search,replace){ + // replace is not function + if(typeof replace != "function"){ + return default_replace.apply(this,arguments) + } + var str = "" + this; + var callback = replace; + // search string is not RegExp + if(!(search instanceof RegExp)){ + var idx = str.indexOf(search); + return ( + idx == -1 ? str : + default_replace.apply(str,[search,callback(search, idx, str)]) + ) + } + var reg = search; + var result = []; + var lastidx = reg.lastIndex; + var re; + while((re = reg.exec(str)) != null){ + var idx = re.index; + var args = re.concat(idx, str); + result.push( + str.slice(lastidx,idx), + callback.apply(null,args).toString() + ); + if(!reg.global){ + lastidx += RegExp.lastMatch.length; + break + }else{ + lastidx = reg.lastIndex; + } + } + result.push(str.slice(lastidx)); + return result.join("") + } +})(); + +var CodeHighlighter = { styleSets : new Array }; + +CodeHighlighter.addStyle = function(name, rules) { + // using push test to disallow older browsers from adding styleSets + if ([].push) this.styleSets.push({ + name : name, + rules : rules, + ignoreCase : arguments[2] || false + }) + + function setEvent() { + // set highlighter to run on load (use LowPro if present) + if (typeof Event != 'undefined' && typeof Event.onReady == 'function') + return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter)); + + var old = window.onload; + + if (typeof window.onload != 'function') { + window.onload = function() { CodeHighlighter.init() }; + } else { + window.onload = function() { + old(); + CodeHighlighter.init(); + } + } + } + + // only set the event when the first style is added + if (this.styleSets.length==1) setEvent(); +} + +CodeHighlighter.init = function() { + if (!document.getElementsByTagName) return; + if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function + // throw out older browsers + + var codeEls = document.getElementsByTagName("CODE"); + // collect array of all pre elements + codeEls.filter = function(f) { + var a = new Array; + for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i]; + return a; + } + + var rules = new Array; + rules.toString = function() { + // joins regexes into one big parallel regex + var exps = new Array; + for (var i = 0; i < this.length; i++) exps.push(this[i].exp); + return exps.join("|"); + } + + function addRule(className, rule) { + // add a replace rule + var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp; + // converts regex rules to strings and chops of the slashes + rules.push({ + className : className, + exp : "(" + exp + ")", + length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule + replacement : rule.replacement || null + }); + } + + function parse(text, ignoreCase) { + // main text parsing and replacement + return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() { + var i = 0, j = 1, rule; + while (rule = rules[i++]) { + if (arguments[j]) { + // if no custom replacement defined do the simple replacement + if (!rule.replacement) return "" + arguments[0] + ""; + else { + // replace $0 with the className then do normal replaces + var str = rule.replacement.replace("$0", rule.className); + for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]); + return str; + } + } else j+= rule.length; + } + }); + } + + function highlightCode(styleSet) { + // clear rules array + var parsed; + rules.length = 0; + + // get stylable elements by filtering out all code elements without the correct className + var stylableEls = codeEls.filter(function(item) {return (item.className.indexOf(styleSet.name)>=0)}); + + // add style rules to parser + for (var className in styleSet.rules) addRule(className, styleSet.rules[className]); + + + // replace for all elements + for (var i = 0; i < stylableEls.length; i++) { + // EVIL hack to fix IE whitespace badness if it's inside a
+			if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
+				stylableEls[i] = stylableEls[i].parentNode;
+				
+				parsed = stylableEls[i].innerHTML.replace(/(]*>)([^<]*)<\/code>/i, function() {
+					return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + ""
+				});
+				parsed = parsed.replace(/\n( *)/g, function() { 
+					var spaces = "";
+					for (var i = 0; i < arguments[1].length; i++) spaces+= " ";
+					return "\n" + spaces;  
+				});
+				parsed = parsed.replace(/\t/g, "    ");
+				parsed = parsed.replace(/\n(<\/\w+>)?/g, "
$1").replace(/
[\n\r\s]*
/g, "


"); + + } else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase); + + stylableEls[i].innerHTML = parsed; + } + } + + // run highlighter on all stylesets + for (var i=0; i < this.styleSets.length; i++) { + highlightCode(this.styleSets[i]); + } +}; + +CodeHighlighter.addStyle("css", { + comment : { + exp : /\/\*[^*]*\*+([^\/][^*]*\*+)*\// + }, + keywords : { + exp : /@\w[\w\s]*/ + }, + selectors : { + exp : "([\\w-:\\[.#][^{};>]*)(?={)" + }, + properties : { + exp : "([\\w-]+)(?=\\s*:)" + }, + units : { + exp : /([0-9])(em|en|px|%|pt)\b/, + replacement : "$1$2" + }, + urls : { + exp : /url\([^\)]*\)/ + } +}); + +CodeHighlighter.addStyle("html", { + comment : { + exp: /<!\s*(--([^-]|[\r\n]|-[^-])*--\s*)>/ + }, + tag : { + exp: /(<\/?)([a-zA-Z]+\s?)/, + replacement: "$1$2" + }, + string : { + exp : /'[^']*'|"[^"]*"/ + }, + attribute : { + exp: /\b([a-zA-Z-:]+)(=)/, + replacement: "$1$2" + }, + doctype : { + exp: /<!DOCTYPE([^&]|&[^g]|&g[^t])*>/ + } +}); + +CodeHighlighter.addStyle("javascript",{ + comment : { + exp : /(\/\/[^\n]*(\n|$))|(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/ + }, + brackets : { + exp : /\(|\)/ + }, + regex : { + exp : /\/(.*?)[g|s|m]?\/[;|\n]/ + }, + string : { + exp : /'(?:\.|(\\\')|[^\''])*'|"(?:\.|(\\\")|[^\""])*"/ + }, + keywords : { + exp : /\b(arguments|break|case|continue|default|delete|do|else|false|for|function|if|in|instanceof|new|null|return|switch|this|true|typeof|var|void|while|with)\b/ + }, + global : { + exp : /\b(toString|valueOf|window|element|prototype|constructor|document|escape|unescape|parseInt|parseFloat|setTimeout|clearTimeout|setInterval|clearInterval|NaN|isNaN|Infinity|alert|prompt|confirm)\b/ + } +}); diff --git a/templates/html/assets/javascripts/controls.js b/templates/html/assets/javascripts/controls.js new file mode 100644 index 0000000..fbc4418 --- /dev/null +++ b/templates/html/assets/javascripts/controls.js @@ -0,0 +1,963 @@ +// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = { } +Autocompleter.Base = Class.create({ + baseInitialize: function(element, update, options) { + element = $(element) + this.element = element; + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + this.oldElementValue = this.element.value; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || { }; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + // Force carriage returns as token delimiters anyway + if (!this.options.tokens.include('\n')) + this.options.tokens.push('\n'); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (Prototype.Browser.IE) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index-- + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++ + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = $(selectedElement).select('.' + this.options.select) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var bounds = this.getTokenBounds(); + if (bounds[0] != -1) { + var newValue = this.element.value.substr(0, bounds[0]); + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value + this.element.value.substr(bounds[1]); + } else { + this.element.value = value; + } + this.oldElementValue = this.element.value; + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + this.tokenBounds = null; + if(this.getToken().length>=this.options.minChars) { + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + this.oldElementValue = this.element.value; + }, + + getToken: function() { + var bounds = this.getTokenBounds(); + return this.element.value.substring(bounds[0], bounds[1]).strip(); + }, + + getTokenBounds: function() { + if (null != this.tokenBounds) return this.tokenBounds; + var value = this.element.value; + if (value.strip().empty()) return [-1, 0]; + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); + var offset = (diff == this.oldElementValue.length ? 1 : 0); + var prevTokenPos = -1, nextTokenPos = value.length; + var tp; + for (var index = 0, l = this.options.tokens.length; index < l; ++index) { + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); + if (tp > prevTokenPos) prevTokenPos = tp; + tp = value.indexOf(this.options.tokens[index], diff + offset); + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; + } + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); + } +}); + +Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { + var boundary = Math.min(newS.length, oldS.length); + for (var index = 0; index < boundary; ++index) + if (newS[index] != oldS[index]) + return index; + return boundary; +}; + +Ajax.Autocompleter = Class.create(Autocompleter.Base, { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + this.startIndicator(); + + var entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "
      " + ret.join('') + "
    "; + } + }, options || { }); + } +}); + +// AJAX in-place editor and collection editor +// Full rewrite by Christophe Porteneuve (April 2007). + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +} + +Ajax.InPlaceEditor = Class.create({ + initialize: function(element, url, options) { + this.url = url; + this.element = element = $(element); + this.prepareOptions(); + this._controls = { }; + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! + Object.extend(this.options, options || { }); + if (!this.options.formId && this.element.id) { + this.options.formId = this.element.id + '-inplaceeditor'; + if ($(this.options.formId)) + this.options.formId = ''; + } + if (this.options.externalControl) + this.options.externalControl = $(this.options.externalControl); + if (!this.options.externalControl) + this.options.externalControlOnly = false; + this._originalBackground = this.element.getStyle('background-color') || 'transparent'; + this.element.title = this.options.clickToEditText; + this._boundCancelHandler = this.handleFormCancellation.bind(this); + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); + this._boundFailureHandler = this.handleAJAXFailure.bind(this); + this._boundSubmitHandler = this.handleFormSubmission.bind(this); + this._boundWrapperHandler = this.wrapUp.bind(this); + this.registerListeners(); + }, + checkForEscapeOrReturn: function(e) { + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; + if (Event.KEY_ESC == e.keyCode) + this.handleFormCancellation(e); + else if (Event.KEY_RETURN == e.keyCode) + this.handleFormSubmission(e); + }, + createControl: function(mode, handler, extraClasses) { + var control = this.options[mode + 'Control']; + var text = this.options[mode + 'Text']; + if ('button' == control) { + var btn = document.createElement('input'); + btn.type = 'submit'; + btn.value = text; + btn.className = 'editor_' + mode + '_button'; + if ('cancel' == mode) + btn.onclick = this._boundCancelHandler; + this._form.appendChild(btn); + this._controls[mode] = btn; + } else if ('link' == control) { + var link = document.createElement('a'); + link.href = '#'; + link.appendChild(document.createTextNode(text)); + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; + link.className = 'editor_' + mode + '_link'; + if (extraClasses) + link.className += ' ' + extraClasses; + this._form.appendChild(link); + this._controls[mode] = link; + } + }, + createEditField: function() { + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); + var fld; + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { + fld = document.createElement('input'); + fld.type = 'text'; + var size = this.options.size || this.options.cols || 0; + if (0 < size) fld.size = size; + } else { + fld = document.createElement('textarea'); + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); + fld.cols = this.options.cols || 40; + } + fld.name = this.options.paramName; + fld.value = text; // No HTML breaks conversion anymore + fld.className = 'editor_field'; + if (this.options.submitOnBlur) + fld.onblur = this._boundSubmitHandler; + this._controls.editor = fld; + if (this.options.loadTextURL) + this.loadExternalText(); + this._form.appendChild(this._controls.editor); + }, + createForm: function() { + var ipe = this; + function addText(mode, condition) { + var text = ipe.options['text' + mode + 'Controls']; + if (!text || condition === false) return; + ipe._form.appendChild(document.createTextNode(text)); + }; + this._form = $(document.createElement('form')); + this._form.id = this.options.formId; + this._form.addClassName(this.options.formClassName); + this._form.onsubmit = this._boundSubmitHandler; + this.createEditField(); + if ('textarea' == this._controls.editor.tagName.toLowerCase()) + this._form.appendChild(document.createElement('br')); + if (this.options.onFormCustomization) + this.options.onFormCustomization(this, this._form); + addText('Before', this.options.okControl || this.options.cancelControl); + this.createControl('ok', this._boundSubmitHandler); + addText('Between', this.options.okControl && this.options.cancelControl); + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); + addText('After', this.options.okControl || this.options.cancelControl); + }, + destroy: function() { + if (this._oldInnerHTML) + this.element.innerHTML = this._oldInnerHTML; + this.leaveEditMode(); + this.unregisterListeners(); + }, + enterEditMode: function(e) { + if (this._saving || this._editing) return; + this._editing = true; + this.triggerCallback('onEnterEditMode'); + if (this.options.externalControl) + this.options.externalControl.hide(); + this.element.hide(); + this.createForm(); + this.element.parentNode.insertBefore(this._form, this.element); + if (!this.options.loadTextURL) + this.postProcessEditField(); + if (e) Event.stop(e); + }, + enterHover: function(e) { + if (this.options.hoverClassName) + this.element.addClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onEnterHover'); + }, + getText: function() { + return this.element.innerHTML; + }, + handleAJAXFailure: function(transport) { + this.triggerCallback('onFailure', transport); + if (this._oldInnerHTML) { + this.element.innerHTML = this._oldInnerHTML; + this._oldInnerHTML = null; + } + }, + handleFormCancellation: function(e) { + this.wrapUp(); + if (e) Event.stop(e); + }, + handleFormSubmission: function(e) { + var form = this._form; + var value = $F(this._controls.editor); + this.prepareSubmission(); + var params = this.options.callback(form, value) || ''; + if (Object.isString(params)) + params = params.toQueryParams(); + params.editorId = this.element.id; + if (this.options.htmlResponse) { + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Updater({ success: this.element }, this.url, options); + } else { + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.url, options); + } + if (e) Event.stop(e); + }, + leaveEditMode: function() { + this.element.removeClassName(this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + if (this.options.externalControl) + this.options.externalControl.show(); + this._saving = false; + this._editing = false; + this._oldInnerHTML = null; + this.triggerCallback('onLeaveEditMode'); + }, + leaveHover: function(e) { + if (this.options.hoverClassName) + this.element.removeClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onLeaveHover'); + }, + loadExternalText: function() { + this._form.addClassName(this.options.loadingClassName); + this._controls.editor.disabled = true; + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._form.removeClassName(this.options.loadingClassName); + var text = transport.responseText; + if (this.options.stripLoadedTextTags) + text = text.stripTags(); + this._controls.editor.value = text; + this._controls.editor.disabled = false; + this.postProcessEditField(); + }.bind(this), + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + postProcessEditField: function() { + var fpc = this.options.fieldPostCreation; + if (fpc) + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); + }, + prepareOptions: function() { + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); + [this._extraDefaultOptions].flatten().compact().each(function(defs) { + Object.extend(this.options, defs); + }.bind(this)); + }, + prepareSubmission: function() { + this._saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + registerListeners: function() { + this._listeners = { }; + var listener; + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { + listener = this[pair.value].bind(this); + this._listeners[pair.key] = listener; + if (!this.options.externalControlOnly) + this.element.observe(pair.key, listener); + if (this.options.externalControl) + this.options.externalControl.observe(pair.key, listener); + }.bind(this)); + }, + removeForm: function() { + if (!this._form) return; + this._form.remove(); + this._form = null; + this._controls = { }; + }, + showSaving: function() { + this._oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + this.element.addClassName(this.options.savingClassName); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + }, + triggerCallback: function(cbName, arg) { + if ('function' == typeof this.options[cbName]) { + this.options[cbName](this, arg); + } + }, + unregisterListeners: function() { + $H(this._listeners).each(function(pair) { + if (!this.options.externalControlOnly) + this.element.stopObserving(pair.key, pair.value); + if (this.options.externalControl) + this.options.externalControl.stopObserving(pair.key, pair.value); + }.bind(this)); + }, + wrapUp: function(transport) { + this.leaveEditMode(); + // Can't use triggerCallback due to backward compatibility: requires + // binding + direct element + this._boundComplete(transport, this.element); + } +}); + +Object.extend(Ajax.InPlaceEditor.prototype, { + dispose: Ajax.InPlaceEditor.prototype.destroy +}); + +Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { + initialize: function($super, element, url, options) { + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; + $super(element, url, options); + }, + + createEditField: function() { + var list = document.createElement('select'); + list.name = this.options.paramName; + list.size = 1; + this._controls.editor = list; + this._collection = this.options.collection || []; + if (this.options.loadCollectionURL) + this.loadCollection(); + else + this.checkForExternalText(); + this._form.appendChild(this._controls.editor); + }, + + loadCollection: function() { + this._form.addClassName(this.options.loadingClassName); + this.showLoadingText(this.options.loadingCollectionText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + var js = transport.responseText.strip(); + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check + throw 'Server returned an invalid collection representation.'; + this._collection = eval(js); + this.checkForExternalText(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadCollectionURL, options); + }, + + showLoadingText: function(text) { + this._controls.editor.disabled = true; + var tempOption = this._controls.editor.firstChild; + if (!tempOption) { + tempOption = document.createElement('option'); + tempOption.value = ''; + this._controls.editor.appendChild(tempOption); + tempOption.selected = true; + } + tempOption.update((text || '').stripScripts().stripTags()); + }, + + checkForExternalText: function() { + this._text = this.getText(); + if (this.options.loadTextURL) + this.loadExternalText(); + else + this.buildOptionList(); + }, + + loadExternalText: function() { + this.showLoadingText(this.options.loadingText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._text = transport.responseText.strip(); + this.buildOptionList(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + + buildOptionList: function() { + this._form.removeClassName(this.options.loadingClassName); + this._collection = this._collection.map(function(entry) { + return 2 === entry.length ? entry : [entry, entry].flatten(); + }); + var marker = ('value' in this.options) ? this.options.value : this._text; + var textFound = this._collection.any(function(entry) { + return entry[0] == marker; + }.bind(this)); + this._controls.editor.update(''); + var option; + this._collection.each(function(entry, index) { + option = document.createElement('option'); + option.value = entry[0]; + option.selected = textFound ? entry[0] == marker : 0 == index; + option.appendChild(document.createTextNode(entry[1])); + this._controls.editor.appendChild(option); + }.bind(this)); + this._controls.editor.disabled = false; + Field.scrollFreeActivate(this._controls.editor); + } +}); + +//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** +//**** This only exists for a while, in order to let **** +//**** users adapt to the new API. Read up on the new **** +//**** API and convert your code to it ASAP! **** + +Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { + if (!options) return; + function fallback(name, expr) { + if (name in options || expr === undefined) return; + options[name] = expr; + }; + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : + options.cancelLink == options.cancelButton == false ? false : undefined))); + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : + options.okLink == options.okButton == false ? false : undefined))); + fallback('highlightColor', options.highlightcolor); + fallback('highlightEndColor', options.highlightendcolor); +}; + +Object.extend(Ajax.InPlaceEditor, { + DefaultOptions: { + ajaxOptions: { }, + autoRows: 3, // Use when multi-line w/ rows == 1 + cancelControl: 'link', // 'link'|'button'|false + cancelText: 'cancel', + clickToEditText: 'Click to edit', + externalControl: null, // id|elt + externalControlOnly: false, + fieldPostCreation: 'activate', // 'activate'|'focus'|false + formClassName: 'inplaceeditor-form', + formId: null, // id|elt + highlightColor: '#ffff99', + highlightEndColor: '#ffffff', + hoverClassName: '', + htmlResponse: true, + loadingClassName: 'inplaceeditor-loading', + loadingText: 'Loading...', + okControl: 'button', // 'link'|'button'|false + okText: 'ok', + paramName: 'value', + rows: 1, // If 1 and multi-line, uses autoRows + savingClassName: 'inplaceeditor-saving', + savingText: 'Saving...', + size: 0, + stripLoadedTextTags: false, + submitOnBlur: false, + textAfterControls: '', + textBeforeControls: '', + textBetweenControls: '' + }, + DefaultCallbacks: { + callback: function(form) { + return Form.serialize(form); + }, + onComplete: function(transport, element) { + // For backward compatibility, this one is bound to the IPE, and passes + // the element directly. It was too often customized, so we don't break it. + new Effect.Highlight(element, { + startcolor: this.options.highlightColor, keepBackgroundImage: true }); + }, + onEnterEditMode: null, + onEnterHover: function(ipe) { + ipe.element.style.backgroundColor = ipe.options.highlightColor; + if (ipe._effect) + ipe._effect.cancel(); + }, + onFailure: function(transport, ipe) { + alert('Error communication with the server: ' + transport.responseText.stripTags()); + }, + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. + onLeaveEditMode: null, + onLeaveHover: function(ipe) { + ipe._effect = new Effect.Highlight(ipe.element, { + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, + restorecolor: ipe._originalBackground, keepBackgroundImage: true + }); + } + }, + Listeners: { + click: 'enterEditMode', + keydown: 'checkForEscapeOrReturn', + mouseover: 'enterHover', + mouseout: 'leaveHover' + } +}); + +Ajax.InPlaceCollectionEditor.DefaultOptions = { + loadingCollectionText: 'Loading options...' +}; + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create({ + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}); diff --git a/templates/html/assets/javascripts/effects.js b/templates/html/assets/javascripts/effects.js new file mode 100644 index 0000000..718a88d --- /dev/null +++ b/templates/html/assets/javascripts/effects.js @@ -0,0 +1,1120 @@ +// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if (this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if (this.slice(0,1) == '#') { + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if (this.length==7) color = this.toLowerCase(); + } + } + return (color.length==7 ? color : (arguments[0] || this)); +}; + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +}; + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +}; + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if (Prototype.Browser.WebKit) window.scrollBy(0,0); + return element; +}; + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +}; + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + Transitions: { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; + return pos > 1 ? 1 : pos; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; + }, + pulse: function(pos, pulses) { + pulses = pulses || 5; + return ( + ((pos % (1/pulses)) * pulses).round() == 0 ? + ((pos * pulses * 2) - (pos * pulses * 2).floor()) : + 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor()) + ); + }, + spring: function(pos) { + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } + }, + DefaultOptions: { + duration: 1.0, // seconds + fps: 100, // 100= assume 66fps max. + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' + }, + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if (child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + new Element('span', {style: tagifyStyle}).update( + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if (((typeof element == 'object') || + Object.isFunction(element)) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || { }); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || { }); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(Enumerable, { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = Object.isString(effect.options.queue) ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if (!this.interval) + this.interval = setInterval(this.loop.bind(this), 15); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if (this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + for(var i=0, len=this.effects.length;i= this.startOn) { + if (timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if (this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / this.totalTime, + frame = (pos * this.totalFrames).round(); + if (frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + cancel: function() { + if (!this.options.sync) + Effect.Queues.get(Object.isString(this.options.queue) ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if (this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if (!Object.isFunction(this[property])) data.set(property, this[property]); + return '#'; + } +}); + +Effect.Parallel = Class.create(Effect.Base, { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if (effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Tween = Class.create(Effect.Base, { + initialize: function(object, from, to) { + object = Object.isString(object) ? $(object) : object; + var args = $A(arguments), method = args.last(), + options = args.length == 5 ? args[3] : null; + this.method = Object.isFunction(method) ? method.bind(object) : + Object.isFunction(object[method]) ? object[method].bind(object) : + function(value) { object[method] = value }; + this.start(Object.extend({ from: from, to: to }, options || { })); + }, + update: function(position) { + this.method(position); + } +}); + +Effect.Event = Class.create(Effect.Base, { + initialize: function() { + this.start(Object.extend({ duration: 0 }, arguments[0] || { })); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || { }); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if (this.options.mode == 'absolute') { + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: (this.options.x * position + this.originalLeft).round() + 'px', + top: (this.options.y * position + this.originalTop).round() + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); +}; + +Effect.Scale = Class.create(Effect.Base, { + initialize: function(element, percent) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or { } with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || { }); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = { }; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if (fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if (this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if (/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if (!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if (this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = { }; + if (this.options.scaleX) d.width = width.round() + 'px'; + if (this.options.scaleY) d.height = height.round() + 'px'; + if (this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if (this.elementPositioning == 'absolute') { + if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if (this.options.scaleY) d.top = -topd + 'px'; + if (this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if (this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { }; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if (!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if (!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = function(element) { + var options = arguments[1] || { }, + scrollOffsets = document.viewport.getScrollOffsets(), + elementOffsets = $(element).cumulativeOffset(), + max = document.viewport.getScrollOffsets[0] - document.viewport.getHeight(); + + if (options.offset) elementOffsets[1] += options.offset; + + return new Effect.Tween(null, + scrollOffsets.top, + elementOffsets[1] > max ? max : elementOffsets[1], + options, + function(p){ scrollTo(scrollOffsets.left, p.round()) } + ); +}; + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if (effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + } + }, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element) + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || { }) + ); +}; + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || { }) + ); +}; + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || { })); +}; + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || { })); +}; + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || { })); +}; + +Effect.Shake = function(element) { + element = $(element); + var options = Object.extend({ + distance: 20, + duration: 0.5 + }, arguments[1] || {}); + var distance = parseFloat(options.distance); + var split = parseFloat(options.duration) / 10.0; + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +}; + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || { }) + ); +}; + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); + } + }, arguments[1] || { }) + ); +}; + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +}; + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ) + } + }); +}; + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +}; + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || { }; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +}; + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || { })); +}; + +Effect.Morph = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: { } + }, arguments[1] || { }); + + if (!Object.isString(options.style)) this.style = $H(options.style); + else { + if (options.style.include(':')) + this.style = options.style.parseStyle(); + else { + this.element.addClassName(options.style); + this.style = $H(this.element.getStyles()); + this.element.removeClassName(options.style); + var css = this.element.getStyles(); + this.style = this.style.reject(function(style) { + return style.value == css[style.key]; + }); + options.afterFinishInternal = function(effect) { + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + effect.element.style[transform.style] = ''; + }); + } + } + } + this.start(options); + }, + + setup: function(){ + function parseColor(color){ + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ) + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0], value = pair[1], unit = null; + + if (value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if (property == 'opacity') { + value = parseFloat(value); + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if (Element.CSS_LENGTH.test(value)) { + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); + value = parseFloat(components[1]); + unit = (components.length == 3) ? components[2] : null; + } + + var originalValue = this.element.getStyle(property); + return { + style: property.camelize(), + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }; + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ) + }); + }, + update: function(position) { + var style = { }, transform, i = this.transforms.length; + while(i--) + style[(transform = this.transforms[i]).style] = + transform.unit=='color' ? '#'+ + (Math.round(transform.originalValue[0]+ + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + + (Math.round(transform.originalValue[1]+ + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + + (Math.round(transform.originalValue[2]+ + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : + (transform.originalValue + + (transform.targetValue - transform.originalValue) * position).toFixed(3) + + (transform.unit === null ? '' : transform.unit); + this.element.setStyle(style, true); + } +}); + +Effect.Transform = Class.create({ + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || { }; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + track = $H(track); + var data = track.values().first(); + this.tracks.push($H({ + ids: track.keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); + var elements = [$(ids) || $$(ids)].flatten(); + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.__parseStyleElement = document.createElement('div'); +String.prototype.parseStyle = function(){ + var style, styleRules = $H(); + if (Prototype.Browser.WebKit) + style = new Element('div',{style:this}).style; + else { + String.__parseStyleElement.innerHTML = '
    '; + style = String.__parseStyleElement.childNodes[0].style; + } + + Element.CSS_PROPERTIES.each(function(property){ + if (style[property]) styleRules.set(property, style[property]); + }); + + if (Prototype.Browser.IE && this.include('opacity')) + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); + + return styleRules; +}; + +if (document.defaultView && document.defaultView.getComputedStyle) { + Element.getStyles = function(element) { + var css = document.defaultView.getComputedStyle($(element), null); + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { + styles[property] = css[property]; + return styles; + }); + }; +} else { + Element.getStyles = function(element) { + element = $(element); + var css = element.currentStyle, styles; + styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { + results[property] = css[property]; + return results; + }); + if (!styles.opacity) styles.opacity = element.getOpacity(); + return styles; + }; +}; + +Effect.Methods = { + morph: function(element, style) { + element = $(element); + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); + return element; + }, + visualEffect: function(element, effect, options) { + element = $(element) + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[klass](element, options); + return element; + }, + highlight: function(element, options) { + element = $(element); + new Effect.Highlight(element, options); + return element; + } +}; + +$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ + 'pulsate shake puff squish switchOff dropOut').each( + function(effect) { + Effect.Methods[effect] = function(element, options){ + element = $(element); + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); + return element; + } + } +); + +$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( + function(f) { Effect.Methods[f] = Element[f]; } +); + +Element.addMethods(Effect.Methods); diff --git a/templates/html/assets/javascripts/prototype.js b/templates/html/assets/javascripts/prototype.js new file mode 100644 index 0000000..a0114e0 --- /dev/null +++ b/templates/html/assets/javascripts/prototype.js @@ -0,0 +1,4706 @@ +/* Prototype JavaScript framework, version 1.6.0.3 + * (c) 2005-2009 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.0.4_rc0', + + Browser: { + IE: !!(window.attachEvent && + navigator.userAgent.indexOf('Opera') === -1), + Opera: navigator.userAgent.indexOf('Opera') > -1, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && + navigator.userAgent.indexOf('KHTML') === -1, + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + SelectorsAPI: !!document.querySelector, + ElementExtensions: (function() { + if (window.HTMLElement && window.HTMLElement.prototype) + return true; + if (window.Element && window.Element.prototype) + return true; + })(), + SpecificElementExtensions: (function() { + if (typeof window.HTMLDivElement !== 'undefined') + return true; + + var div = document.createElement('div'); + if (div['__proto__'] && div['__proto__'] !== + document.createElement('form')['__proto__']) { + return true; + } + + return false; + })() + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +var Abstract = { }; + + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +/* Based on Alex Arnell's inheritance implementation. */ + +var Class = (function() { + function create() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + var subclass = function() {}; + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); +(function() { + + function getClass(object) { + return Object.prototype.toString.call(object) + .match(/^\[object\s(.*)\]$/)[1]; + } + + function extend(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; + } + + function inspect(object) { + try { + if (isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + } + + function toJSON(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (isElement(object)) return; + + var results = []; + for (var property in object) { + var value = toJSON(object[property]); + if (!isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + } + + function toQueryString(object) { + return $H(object).toQueryString(); + } + + function toHTML(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + } + + function keys(object) { + var results = []; + for (var property in object) + results.push(property); + return results; + } + + function values(object) { + var results = []; + for (var property in object) + results.push(object[property]); + return results; + } + + function clone(object) { + return extend({ }, object); + } + + function isElement(object) { + return !!(object && object.nodeType == 1); + } + + function isArray(object) { + return getClass(object) === "Array"; + } + + + function isHash(object) { + return object instanceof Hash; + } + + function isFunction(object) { + return typeof object === "function"; + } + + function isString(object) { + return getClass(object) === "String"; + } + + function isNumber(object) { + return getClass(object) === "Number"; + } + + function isUndefined(object) { + return typeof object === "undefined"; + } + + extend(Object, { + extend: extend, + inspect: inspect, + toJSON: toJSON, + toQueryString: toQueryString, + toHTML: toHTML, + keys: keys, + values: values, + clone: clone, + isElement: isElement, + isArray: isArray, + isHash: isHash, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isUndefined: isUndefined + }); +})(); +Object.extend(Function.prototype, (function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + } + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + } + + function argumentNames() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + } + + function bind(context) { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + + function bindAsEventListener(context) { + var __method = this, args = slice.call(arguments, 1); + return function(event) { + var a = update([event || window.event], args); + return __method.apply(context, a); + } + } + + function curry() { + if (!arguments.length) return this; + var __method = this, args = slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } + + function delay(timeout) { + var __method = this, args = slice.call(arguments, 1); + timeout = timeout * 1000 + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + } + + function defer() { + var args = update([0.01], arguments); + return this.delay.apply(this, args); + } + + function wrap(wrapper) { + var __method = this; + return function() { + var a = update([__method.bind(this)], arguments); + return wrapper.apply(this, a); + } + } + + function methodize() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + var a = update([this], arguments); + return __method.apply(null, a); + }; + } + + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})()); + + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + } finally { + this.currentlyExecuting = false; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, (function() { + + function prepareReplacement(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; + } + + function gsub(pattern, replacement) { + var result = '', source = this, match; + replacement = prepareReplacement(replacement); + + if (Object.isString(pattern)) + pattern = RegExp.escape(pattern); + + if (!(pattern.length || pattern.source)) { + replacement = replacement(''); + return replacement + source.split('').join(replacement) + replacement; + } + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + } + + function sub(pattern, replacement, count) { + replacement = prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + } + + function scan(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + } + + function truncate(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + } + + function strip() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + function stripTags() { + return this.replace(/<\/?[^>]+>/gi, ''); + } + + function stripScripts() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + } + + function extractScripts() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + } + + function evalScripts() { + return this.extractScripts().map(function(script) { return eval(script) }); + } + + function escapeHTML() { + escapeHTML.text.data = this; + return escapeHTML.div.innerHTML; + } + + function unescapeHTML() { + var div = new Element('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + } + + function toQueryParams(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + } + + function toArray() { + return this.split(''); + } + + function succ() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + } + + function times(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + } + + function camelize() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + } + + function capitalize() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + } + + function underscore() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + } + + function dasherize() { + return this.gsub(/_/,'-'); + } + + function inspect(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } + + function toJSON() { + return this.inspect(true); + } + + function unfilterJSON(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + } + + function isJSON() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + } + + function evalJSON(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + } + + function include(pattern) { + return this.indexOf(pattern) > -1; + } + + function startsWith(pattern) { + return this.indexOf(pattern) === 0; + } + + function endsWith(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + } + + function empty() { + return this == ''; + } + + function blank() { + return /^\s*$/.test(this); + } + + function interpolate(object, pattern) { + return new Template(this, pattern).evaluate(object); + } + + return { + gsub: gsub, + sub: sub, + scan: scan, + truncate: truncate, + strip: strip, + stripTags: stripTags, + stripScripts: stripScripts, + extractScripts: extractScripts, + evalScripts: evalScripts, + escapeHTML: escapeHTML, + unescapeHTML: unescapeHTML, + toQueryParams: toQueryParams, + parseQuery: toQueryParams, + toArray: toArray, + succ: succ, + times: times, + camelize: camelize, + capitalize: capitalize, + underscore: underscore, + dasherize: dasherize, + inspect: inspect, + toJSON: toJSON, + unfilterJSON: unfilterJSON, + isJSON: isJSON, + evalJSON: evalJSON, + include: include, + startsWith: startsWith, + endsWith: endsWith, + empty: empty, + blank: blank, + interpolate: interpolate + }; +})()); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(//g,'>'); + }, + unescapeHTML: function() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + } +}); + +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return ''; + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = (function() { + function each(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + } + + function eachSlice(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + } + + function all(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + } + + function any(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + } + + function collect(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function detect(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + } + + function findAll(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function grep(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(RegExp.escape(filter)); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function include(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + } + + function inGroupsOf(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + } + + function inject(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + } + + function invoke(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + } + + function max(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + } + + function min(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + } + + function partition(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + } + + function pluck(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + } + + function reject(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function sortBy(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + } + + function toArray() { + return this.map(); + } + + function zip() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + } + + function size() { + return this.toArray().length; + } + + function inspect() { + return '#'; + } + + return { + each: each, + eachSlice: eachSlice, + all: all, + every: all, + any: any, + some: any, + collect: collect, + map: collect, + detect: detect, + findAll: findAll, + select: findAll, + filter: findAll, + grep: grep, + include: include, + member: include, + inGroupsOf: inGroupsOf, + inject: inject, + invoke: invoke, + max: max, + min: min, + partition: partition, + pluck: pluck, + reject: reject, + sortBy: sortBy, + toArray: toArray, + entries: toArray, + zip: zip, + size: size, + inspect: inspect, + find: detect + }; +})(); +function $A(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +if (Prototype.Browser.WebKit) { + $A = function(iterable) { + if (!iterable) return []; + if (!(typeof iterable === 'function' && typeof iterable.length === + 'number' && typeof iterable.item === 'function') && iterable.toArray) + return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; + }; +} + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +Array.from = $A; + +(function() { + var arrayProto = Array.prototype, + slice = arrayProto.slice, + _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available + + function each(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + } + if (!_each) _each = each; + + function clear() { + this.length = 0; + return this; + } + + function first() { + return this[0]; + } + + function last() { + return this[this.length - 1]; + } + + function compact() { + return this.select(function(value) { + return value != null; + }); + } + + function flatten() { + return this.inject([], function(array, value) { + if (Object.isArray(value)) + return array.concat(value.flatten()); + array.push(value); + return array; + }); + } + + function without() { + var values = slice.call(arguments, 0); + return this.select(function(value) { + return !values.include(value); + }); + } + + function reverse(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + } + + function reduce() { + return this.length > 1 ? this : this[0]; + } + + function uniq(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + } + + function intersect(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + } + + function clone() { + return slice.call(this, 0); + } + + function size() { + return this.length; + } + + function inspect() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } + + function toJSON() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } + + function indexOf(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; + } + + function lastIndexOf(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; + } + + function concat() { + var array = slice.call(this, 0), item; + for (var i = 0, length = arguments.length; i < length; i++) { + item = arguments[i]; + if (Object.isArray(item) && !('callee' in item)) { + for (var j = 0, arrayLength = item.length; j < arrayLength; j++) + array.push(item[j]); + } else { + array.push(item); + } + } + return array; + } + + Object.extend(arrayProto, Enumerable); + + if (!arrayProto._reverse) + arrayProto._reverse = arrayProto.reverse; + + Object.extend(arrayProto, { + _each: _each, + clear: clear, + first: first, + last: last, + compact: compact, + flatten: flatten, + without: without, + reverse: reverse, + reduce: reduce, + uniq: uniq, + intersect: intersect, + clone: clone, + toArray: clone, + size: size, + inspect: inspect, + toJSON: toJSON + }); + + var CONCAT_ARGUMENTS_BUGGY = (function() { + return [].concat(arguments)[0][0] !== 1; + })(1,2) + + if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; + + if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; + if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})(); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + function initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + } + + function _each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + + function set(key, value) { + return this._object[key] = value; + } + + function get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + } + + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + } + + function toObject() { + return Object.clone(this._object); + } + + function keys() { + return this.pluck('key'); + } + + function values() { + return this.pluck('value'); + } + + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + } + + function merge(object) { + return this.clone().update(object); + } + + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + function toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return results.concat(values.map(toQueryPair.curry(key))); + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + } + + function inspect() { + return '#'; + } + + function toJSON() { + return Object.toJSON(this.toObject()); + } + + function clone() { + return new Hash(this); + } + + return { + initialize: initialize, + _each: _each, + set: set, + get: get, + unset: unset, + toObject: toObject, + toTemplateReplacements: toObject, + keys: keys, + values: values, + index: index, + merge: merge, + update: update, + toQueryString: toQueryString, + inspect: inspect, + toJSON: toJSON, + clone: clone + }; +})()); + +Hash.from = $H; +Object.extend(Number.prototype, (function() { + function toColorPart() { + return this.toPaddedString(2, 16); + } + + function succ() { + return this + 1; + } + + function times(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + } + + function toPaddedString(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + } + + function toJSON() { + return isFinite(this) ? this.toString() : 'null'; + } + + function abs() { + return Math.abs(this); + } + + function round() { + return Math.round(this); + } + + function ceil() { + return Math.ceil(this); + } + + function floor() { + return Math.floor(this); + } + + return { + toColorPart: toColorPart, + succ: succ, + times: times, + toPaddedString: toPaddedString, + toJSON: toJSON, + abs: abs, + round: round, + ceil: ceil, + floor: floor + }; +})()); + +function $R(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { + function initialize(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + } + + function _each(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + } + + function include(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } + + return { + initialize: initialize, + _each: _each, + include: include + }; +})()); + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); + + + +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + + +(function(global) { + var element = global.Element; + global.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (Prototype.Browser.IE && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(global.Element, element || { }); + if (element) global.Element.prototype = element.prototype; +})(this); + +Element.cache = { }; +Element.idCounter = 1; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + content = Object.toHTML(content); + element.innerHTML = content.stripScripts(); + content.evalScripts.bind(content).defer(); + return element; + }, + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return Element.select(element, "*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return Object.isNumber(expression) ? ancestors[expression] : + Selector.findElement(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? element.descendants()[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return Object.isNumber(expression) ? previousSiblings[expression] : + Selector.findElement(previousSiblings, expression, index); + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return Object.isNumber(expression) ? nextSiblings[expression] : + Selector.findElement(nextSiblings, expression, index); + }, + + + select: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + adjacent: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = element.readAttribute('id'); + if (id) return id; + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + element.writeAttribute('id', id); + return id; + }, + + readAttribute: (function(){ + + var iframeGetAttributeThrowsError = (function(){ + var el = document.createElement('iframe'), + isBuggy = false; + + document.documentElement.appendChild(el); + try { + el.getAttribute('type', 2); + } catch(e) { + isBuggy = true; + } + document.documentElement.removeChild(el); + el = null; + return isBuggy; + })(); + + return function(element, name) { + element = $(element); + if (iframeGetAttributeThrowsError && + name === 'type' && + element.tagName.toUpperCase() == 'IFRAME') { + return element.getAttribute('type'); + } + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + } + })(), + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!element.hasClassName(className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return element[element.hasClassName(className) ? + 'removeClassName' : 'addClassName'](className); + }, + + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = element.cumulativeOffset(); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = element.getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName.toUpperCase() == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (element.getStyle('position') == 'absolute') return element; + + var offsets = element.positionedOffset(); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (element.getStyle('position') == 'relative') return element; + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + source = $(source); + var p = source.viewportOffset(); + + element = $(element); + var delta = [0, 0]; + var parent = null; + if (Element.getStyle(element, 'position') == 'absolute') { + parent = element.getOffsetParent(); + delta = parent.viewportOffset(); + } + + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + if (!Element.visible(element)) return null; + + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return $(document.body) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + offsetParent.setStyle({ zoom: 1 }); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( + function(proceed, element) { + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + return proceed(element); + } + ); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = { + read: { + names: { + 'class': 'className', + 'for': 'htmlFor' + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: function(element, attribute) { + attribute = element.getAttribute(attribute); + + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + }; + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr, + src: v._getAttr, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if (Prototype.Browser.IE || Prototype.Browser.Opera) { + Element.Methods.update = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + + content = Object.toHTML(content); + var tagName = element.tagName.toUpperCase(); + + if (tagName in Element._insertionTranslations.tags) { + $A(element.childNodes).each(function(node) { element.removeChild(node) }); + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { element.appendChild(node) }); + } + else element.innerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +if ('outerHTML' in document.createElement('div')) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + } else div.innerHTML = html; + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
    ', 1], + TBODY: ['', '
    ', 2], + TR: ['', '
    ', 3], + TD: ['
    ', '
    ', 4], + SELECT: ['', 1] + } +}; + +(function() { + Object.extend(this.tags, { + THEAD: this.tags.TBODY, + TFOOT: this.tags.TBODY, + TH: this.tags.TD + }); +}).call(Element._insertionTranslations); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')) + +Element.extend = (function() { + if (Prototype.BrowserFeatures.SpecificElementExtensions) + return Prototype.K; + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || typeof element._extendedByPrototype != 'undefined' || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(), property, value; + + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + for (property in methods) { + value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + var element = document.createElement(tagName); + var proto = element['__proto__'] || element.constructor.prototype; + element = null; + return proto; + } + + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + + if (F.ElementExtensions) { + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + + +document.viewport = { + + getDimensions: function() { + return { width: this.getWidth(), height: this.getHeight() }; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; + +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; + + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; + } else { + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = [Element.Storage.UID++]; + uid = element._prototypeUID[0]; + } + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + + if (arguments.length === 2) { + element.getStorage().update(key); + } else { + element.getStorage().set(key, value); + } + + return element; + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + } +}); +/* Portions of the Selector class are derived from Jack Slocum's DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + + if (this.shouldUseSelectorsAPI()) { + this.mode = 'selectorsAPI'; + } else if (this.shouldUseXPath()) { + this.mode = 'xpath'; + this.compileXPathMatcher(); + } else { + this.mode = "normal"; + this.compileMatcher(); + } + + }, + + shouldUseXPath: (function() { + + var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ + var isBuggy = false; + if (document.evaluate && window.XPathResult) { + var el = document.createElement('div'); + el.innerHTML = '
    '; + + var xpath = ".//*[local-name()='ul' or local-name()='UL']" + + "//*[local-name()='li' or local-name()='LI']"; + + var result = document.evaluate(xpath, el, null, + XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + + isBuggy = (result.snapshotLength !== 2); + el = null; + } + return isBuggy; + })(); + + return function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + if ((/(\[[\w-]*?:|:checked)/).test(e)) + return false; + + if (IS_DESCENDANT_SELECTOR_BUGGY) return false; + + return true; + } + + })(), + + shouldUseSelectorsAPI: function() { + if (!Prototype.BrowserFeatures.SelectorsAPI) return false; + + if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; + + if (!Selector._div) Selector._div = new Element('div'); + + try { + Selector._div.querySelector(this.expression); + } catch(e) { + return false; + } + + return true; + }, + + compileMatcher: function() { + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m, len = ps.length, name; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i = 0; i"; + } +}); + +if (Prototype.BrowserFeatures.SelectorsAPI && + document.compatMode === 'BackCompat') { + Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ + var div = document.createElement('div'), + span = document.createElement('span'); + + div.id = "prototype_test_id"; + span.className = 'Test'; + div.appendChild(span); + var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); + div = span = null; + return isIgnored; + })(); +} + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, + attr: function(m) { + m[1] = m[1].toLowerCase(); + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0)]", + 'checked': "[@checked]", + 'disabled': "[(@disabled) and (@type!='hidden')]", + 'enabled': "[not(@disabled) and (@type!='hidden')]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, v, len = p.length, name; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i = 0; i= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: [ + { name: 'laterSibling', re: /^\s*~\s*/ }, + { name: 'child', re: /^\s*>\s*/ }, + { name: 'adjacent', re: /^\s*\+\s*/ }, + { name: 'descendant', re: /^\s/ }, + + { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, + { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, + { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, + { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, + { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, + { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } + ], + + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + } + }, + + handlers: { + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + mark: function(nodes) { + var _true = Prototype.emptyFunction; + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = _true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = undefined; + return nodes; + }, + + index: function(parentNode, reverse, ofType) { + parentNode._countedByPrototype = Prototype.emptyFunction; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + }, + + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { + n._countedByPrototype = Prototype.emptyFunction; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + tagName: function(nodes, root, tagName, combinator) { + var uTagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() === uTagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + + if (root == document) { + if (!targetNode) return []; + if (!nodes) return [targetNode]; + } else { + if (!root.sourceIndex || root.sourceIndex < 1) { + var nodes = root.getElementsByTagName('*'); + for (var j = 0, node; node = nodes[j]; j++) { + if (node.id === id) return [node]; + } + } + } + + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._countedByPrototype) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (node.tagName == '!' || node.firstChild) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._countedByPrototype) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled && (!node.type || node.type !== 'hidden')) + results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, + '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, + '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + + '-').include('-' + (v || "").toUpperCase() + '-'); } + }, + + split: function(expression) { + var expressions = []; + expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + return expressions; + }, + + matchElements: function(elements, expression) { + var matches = $$(expression), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._countedByPrototype) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + expressions = Selector.split(expressions.join(',')); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +if (Prototype.Browser.IE) { + Object.extend(Selector.handlers, { + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + if (node.tagName !== "!") a.push(node); + return a; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node.removeAttribute('_countedByPrototype'); + return nodes; + } + }); +} + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} + +var Form = { + reset: function(form) { + form = $(form); + form.reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; + +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, value) { + if (Object.isUndefined(value)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +(function() { + + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: {} + }; + + var _isButton; + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + _isButton = function(event, code) { + return event.button === buttonMap[code]; + }; + } else if (Prototype.Browser.WebKit) { + _isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + } else { + _isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + if (!expression) return element; + var elements = [element].concat(element.ancestors()); + return Selector.findElement(elements, expression, 0); + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop + }; + + + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } + + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return '[object Event]' } + }); + + Event.extend = function(event, element) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + + Object.extend(event, { + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + + return Object.extend(event, methods); + }; + } else { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; + Object.extend(Event.prototype, methods); + Event.extend = Prototype.K; + } + + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } + + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined()) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } + + if (respondersForEvent.pluck('handler').include(handler)) return false; + + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) + return false; + + if (event.eventName !== eventName) + return false; + + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!Prototype.Browser.IE && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); + + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } + + if (parent === element) return; + + handler.call(element, event); + }; + } + } else { + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; + } + } + + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } + + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } + + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K; + + if (!Prototype.Browser.IE) { + _getDOMEventName = function(eventName) { + var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + return eventName in translations ? translations[eventName] : eventName; + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onfilterchange", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) return element; + + if (eventName && !handler) { + var responders = registry.get(eventName); + + if (Object.isUndefined(responders)) return element; + + responders.each( function(r) { + Element.stopObserving(element, eventName, r.handler); + }); + return element; + } else if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key, responders = pair.value; + + responders.each( function(r) { + Element.stopObserving(element, eventName, r.handler); + }); + }); + return element; + } + + var responders = registry.get(eventName); + + if (!responders) return; + + var responder = responders.find( function(r) { return r.handler === handler; }); + if (!responder) return element; + + var actualEventName = _getDOMEventName(eventName); + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onfilterchange", responder); + } + } else { + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', true, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearTimeout(timer); + document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); + } else { + document.observe('readystatechange', checkReadyState); + if (window == top) + timer = pollDoScroll.defer(); + } + + Event.observe(window, 'load', fireContentLoadedEvent); +})(); + +Element.addMethods(); + +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +var Position = { + includeScrollOffsets: false, + + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ diff --git a/templates/html/assets/stylesheets/api.css b/templates/html/assets/stylesheets/api.css new file mode 100644 index 0000000..55c88f5 --- /dev/null +++ b/templates/html/assets/stylesheets/api.css @@ -0,0 +1,402 @@ +/* + * API STYLES + */ + + +/* tag styles */ +h1, h2, h3, h4, h5, h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 0; + padding: 0; +} + +pre { + padding: 0; +} + +code { + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", monospace; + font-size: 13px; +} + + +/* masthead */ +div#masthead { + background: url(../images/header-stripe-small.png) repeat-x top left; + height: 76px; +} + + div#masthead div#masthead_content { + margin: 0 auto; + width: 835px; + position: relative; + } + + div#masthead h1#logo { + background: url(../images/header-logo-small.png) no-repeat 0 1px; + width: 118px; + height: 76px; + position: relative; + left: 60px; + } + +/* footer */ +div#footer { + width: 960px; + margin: 0 auto; +} + + div.about { + margin-top: 20px; + padding-top: 20px; + width: 835px; + margin-left: 120px; + border-top: 1px solid #aaa; + color: #aaa; + } + + div.about a, + div.about a:link { + color: #aaa; + text-decoration: underline; + border: 0; + } + + +.page-title span.type { + display: block; + text-transform: uppercase; + font-size: 14px; + color: #aaa; + letter-spacing: 0; +} + +h2.page-title { + margin-top: 0; + line-height: 100%; +} + +ul.breadcrumbs { + margin-left: 120px; +} + + ul.breadcrumbs li { + float: left; + list-style-type: none; + margin-right: 10px; + margin-left: 0; + } + + + +ul.method-list { + margin-top: 0; +} + + ul.method-list li { + margin-top: 0; + float: left; + margin-right: 5px; + margin-left: 0; + list-style-type: none; + } + + ul.method-list li a, + ul.method-list li a:link { + text-decoration: none; + border: 0; + } + +ul.method-details-list { + margin-top: 0; +} + + ul.method-details-list li.method-description { + margin-top: 0; + margin-bottom: 3.0em; + margin-left: 0; + list-style-type: none; + } + + ul.method-details-list li h4 { + margin: 0 0 0.6em; + line-height: 90%; + } + + ul.method-details-list li pre { + margin-top: 0; + } + + ul.method-details-list li pre code { + font-size: 13px; + } + + ul.method-details-list li code { + font-size: 12px; + } + +ul.argument-list { + margin-top: -5px; + list-style-type: disc; + margin-left: 20px; +} + + ul.argument-list li { + list-style-type: disc; + font-size: 90%; + } + + ul.argument-list li code { + font-size: 11px; + } + +ul.section-list { + margin-top: 0; +} + + ul.section-list li { + margin-top: 0; + margin-left: 0; + list-style-type: none; + } + + ul.section-list li h4 { + margin-top: 0; + } + + +/* Aliases */ + +.alias, +.related-to { + font-style: italic; +} + + .alias code, + .related-to code { + font-style: normal; + } + +/* Section icons */ + +.page-content .section .section-title h3 { + padding-right: 24px; + background-position: right 0; + background-repeat: no-repeat; +} + +.section-constructor .section-title h3 { + background-image: url(../images/constructor.png); +} + +.section-method-list .section-title h3, +.section-klass_methods .section-title h3, +.section-instance_methods .section-title h3 { + background-image: url(../images/method.png); +} + +.section-mixins .section-title h3 { + background-image: url(../images/mixin.png); +} + +.section-classes .section-title h3 { + background-image: url(../images/class.png); +} + +.section-namespaces .section-title h3 { + background-image: url(../images/namespace.png); +} + +.section-sections .section-title h3 { + background-image: url(../images/section.png); +} + +.section-utilities .section-title h3 { + background-image: url(../images/utility.png); +} + +.section-description .section-title h3 { + background-image: url(../images/description.png); +} + +/* search box */ + +.search-results { + position: absolute; + background-color: #fff; + height: 200px; + width: 233px; + overflow: auto; + overflow-y: scroll; + margin: 7px -11px 0; + border: 1px solid #999; +} + + +/* search result types */ + +.menu-item a, +.menu-item a:link { + display: block; + padding: 3px 10px 3px 28px; + background-position: 6px 50%; + background-repeat: no-repeat; + text-align: left; + text-decoration: none; + color: #333; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + +} + + .menu-item a:hover, + .menu-item.highlighted a { + border-top: 1px solid #69f; + border-bottom: 1px solid #69f; + background-color: #f0f0ff; + } + + +.menu-item a.section { + font-weight: bold; + background-image: url(../images/section.png); +} + +.menu-item a.class_method, +.menu-item a.instance_method { + background-image: url(../images/method.png); +} + +.menu-item a.class { + background-image: url(../images/class.png); +} + +.menu-item a.constructor { + background-image: url(../images/constructor.png); +} + +.menu-item a.class_property, +.menu-item a.instance_property { + background-image: url(../images/property.png); +} + +.menu-item a.namespace { + background-image: url(../images/namespace.png); +} + +.menu-item a.utility { + background-image: url(../images/utility.png); +} + + +/* halo around selected method */ + +.highlighter { + border: 3px solid #69f; + z-index: -1; +} + +/* MENU */ + +div#menu { + width: 960px; + margin: 0 auto; + position: relative; +} + + #menu .api-box h2 a, + #menu .search-box { + width: 213px; + height: 25px; + line-height: 25px; + padding: 5px 10px; + margin-right: 5px; + text-align: center; + float: right; + } + + #menu .api-box { + } + + #menu .api-box h2 a { + font-size: 14px; + font-weight: normal; + font-family: Verdana, sans-serif; + display: block; + background-color: #cde0fb; + border: 1px solid #669; + border-top: 0; + text-decoration: none; + color: #222; + } + + #menu .api-box .menu-items { + position: absolute; + background-color: #fff; + height: 200px; + width: 233px; + overflow: auto; + overflow-y: scroll; + top: 35px; + border: 1px solid #999; + right: 5px; + } + + #menu .api-box ul, + #menu .api-box li { + margin: 0; + padding: 0; + } + + #menu .api-box .menu-item a { + } + + #menu .search-box { + background-color: #cee8c3; + border: 1px solid #696; + border-top: 0; + } + + #menu .search-box input { + width: 150px; + padding: 3px 6px; + margin-top: 2px; + border: 1px solid #999; + border-radius: 10px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + } + + +/* notes */ + +p.note, +p.alias, +p.related-to { + font-size: 11px; + line-height: 14px; + padding: 5px 5px 5px 60px; + background-repeat: no-repeat; + background-position: 20px 50%; + border: 1px solid #000; +} + +p.note { + background-color: #f0f0f4; + background-image: url(../images/information.png); + border-color: #69c; +} + +p.alias { + background-color: #fff6de; + background-image: url(../images/alias.png); + border-color: #cc9; +} + +p.related-to { + background-color: #f4f0f4; + background-image: url(../images/related_to.png); + border-color: #c9c; +} + + diff --git a/templates/html/assets/stylesheets/core.css b/templates/html/assets/stylesheets/core.css new file mode 100644 index 0000000..8cded36 --- /dev/null +++ b/templates/html/assets/stylesheets/core.css @@ -0,0 +1,416 @@ +/* The "section" class implicitly needs a clearfix; adding it here for convenience. */ + +.clearfix:after, +.section:after { + content: "."; + display: block; + clear: both; + visibility: hidden; + line-height: 0; + height: 0; +} + +.clearfix, .section { + display: inline-block; +} + +html[xmlns] .clearfix, +html[xmlns] .section { + display: block; +} + +* html .clearfix, +* html .section { + height: 1%; +} + +span.replaced { visibility: hidden; } +span.hidden { display: none; } + + +body { + font-family: Verdana, sans-serif; + font-size: 82.5%; + line-height: 1.5em; + margin: 0; + padding: 0; +} + + body * { + margin: 0; + padding: 0; + } + + +h1, h2, h3, h4, h5, h6 { + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; +} + +h4 { + font-size: 15px; + color: #444; + margin: 0 0 0.4em; +} + +h5 { + font-size: 14px; + color: #222; + margin: 0 0 0.4em; +} + +h6 { + font-size: 13px; + color: #000; + margin: 0 0 0.4em; +} + +a img { + border: 0; +} + +ul, li { + list-style-type: none; +} + +ol, ul { + margin: 0 0 15px; +} + +#page a.img, +#page a.img:link, +#page a.img:visited { + border: none; +} + +/* Link bar */ + +div#links { + margin: 0 auto; + width: 835px; + padding: 16px 0; + height: 16px; + overflow: hidden; +} + +div#links_wrapper { + background: #fff; +} + +div#links li { + display: inline; +} + +div#links li a { + color: #666; +} + +div#links li.selected a { + color: #000; + font-weight: bold; + text-decoration: none; +} + +ul#internal_links { + float: left; +} + +ul#internal_links li { + margin-right: 25px; +} + +ul#external_links { + float: right; +} + +ul#external_links li { + margin-left: 25px; + padding-left: 21px; +} + +li#scripty_link { + background: url(http://prototype.conio.net/new/images/link-logo-scripty.png) no-repeat center left; +} + +li#rails_link { + background: url(http://prototype.conio.net/new/images/link-logo-rails.png) no-repeat center left; +} + + + +p a, p a:link, +h1 a, h1 a:link, +h2 a, h2 a:link, +h3 a, h3 a:link, +h4 a, h4 a:link, +h5 a, h5 a:link, +h6 a, h6 a:link { + color: #036; + border-bottom: 1px solid #036; + text-decoration: none; +} + + p a:visited { + border-bottom: 1px solid #666; + } + +code { + font-family: "Panic Sans", "Bitstream Vera Sans Mono", Monaco, Consolas, Andale Mono, monospace; + font-size: 13px; +} + +p code, +li code { + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 3px; + -webkit-border-radius: 3px; + padding: 0 3px; +} + +pre code { + background-color: transparent; + border: 0; + padding: 0; +} + + +#page { + margin: 0 auto; + padding-bottom: 100px; /* FIXME: Temporary as pages are built */ +} + + +/* top */ + +.related-links { + width: 835px; + font-size: 0.9em; + margin: 0 auto 10px; + padding: 10px 0 0; +} + + .related-links a { + color: #000; + text-decoration: none; + } + + .related-links ul { + list-style-type: none; + } + + .related-links ul.internal { + float: left; + width: 355px; + } + + .related-links ul.internal li { + text-align: center; + } + + .related-links ul.external { + float: right; + width: 295px; + } + + .related-links li { + float: left; + padding: 0 15px; + width: 85px; + margin-right: 5px; + } + + .related-links li.last { + margin-right: 0; + } + + .related-links ul.external li.scripty { + padding: 0 8px 0 22px; + background: url(../images/icon-scripty.png) no-repeat; + margin-right: 65px; + } + + .related-links ul.external li.rails { + padding: 0 8px 0 22px; + background: url(../images/icon-rails.png) no-repeat; + } + + +.banner { + height: 152px; + padding: 1px 0; + background: url(../images/header-stripe.png) repeat-x; +} + + .banner-content { + width: 835px; + margin: 0 auto; + } + + .banner h1 { + width: 236px; + height: 150px; + background: url(../images/header-logo.png) no-repeat; + } + + .banner h1 span { + display: none; + } + +.banner-small { + height: 75px; + padding: 1px 0; + background: url(../images/header-stripe-small.png) repeat-x; +} + + .banner-small h1 { + width: 118px; + height: 75px; + background: url(../images/header-logo-small.png) no-repeat; + margin-left: 60px; + } + + .banner-small h1 span { + display: none; + } + + +/* PAGE CONTENT */ + +.page-content { + width: 955px; + margin: 30px auto 0; +} + + .page-content .page-title { + margin-left: 120px; + margin-bottom: 15px; + font-size: 27px; + letter-spacing: -1px; + color: #444; + } + + .page-content .page-introduction { + margin-left: 120px; + font-size: 15px; + margin-bottom: 25px; + } + + .page-content .page-introduction p { + margin-top: 0; + } + + +.page-content .section { + width: 955px; + margin: 10px 0 20px; +} + + .page-content .section .section-title { + width: 110px; + margin-right: 10px; + padding-right: 0; + float: left; + text-align: right; + } + + .page-content .section .section-title h3 { + color: #999; + font-size: 14px; + line-height: 110%; + padding-right: 10px; + padding-bottom: 5px; + } + + .page-content .section .section-content { + width: 835px; + float: left; + } + +.page-content a, +.page-content a:link { + color: #036; + border-bottom: 1px solid #036; + text-decoration: none; +} + + .page-content a:visited { + border-bottom: 1px solid #bbb; + } + +.page-content ul, +.page-content ol { + margin: 10px 0; +} + +.page-content li { + margin: 5px 0 8px 20px; + list-style-type: disc; +} + +.page-content p { + margin: 0 0 0.8em; +} + +.page-content pre { + color: #333; + background-color: #f0f0ff; + border: 1px solid #dde; + padding: 3px 5px; + margin: 0 0 1em; +} + +.page-content .two-column { + +} + + .page-content .two-column-left, + .page-content .two-column-right { + width: 475px; + margin-right: 5px; + float: left; + } + + .page-content .two-column-right { + margin-right: 0; + } + + .page-content .two-column .section { + width: 475px; + } + + .page-content .two-column .section-content { + width: 345px; + padding-right: 10px; + } + + + +.smallcaps { + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 1px; +} + + +/* MASTHEAD */ + +div#masthead { + margin-top: 50px; + background: url(../images/header-stripe-small.png) repeat-x top left; + height: 76px; +} + +div#masthead div#masthead_content { + margin: 0 auto; + width: 835px; + position: relative; +} + +div#masthead h1#logo { + background: url(../images/header-logo-small.png) no-repeat 0 1px; + width: 118px; + height: 76px; + position: relative; + left: 60px; +} + diff --git a/templates/html/assets/stylesheets/grid.css b/templates/html/assets/stylesheets/grid.css new file mode 100644 index 0000000..08824c5 --- /dev/null +++ b/templates/html/assets/stylesheets/grid.css @@ -0,0 +1,13 @@ +body.grid { + width: 955px; + margin: auto; +} + +body.grid div#page { + overflow: hidden; + background: url(../images/grid.png); +} + +body.grid div#page * { + opacity: .9; +} diff --git a/templates/html/assets/stylesheets/highlighter.css b/templates/html/assets/stylesheets/highlighter.css new file mode 100644 index 0000000..8ce358f --- /dev/null +++ b/templates/html/assets/stylesheets/highlighter.css @@ -0,0 +1,116 @@ +/* See license.txt for terms of usage */ + +.firebugHighlight { + z-index: 2147483647; + position: absolute; + background-color: #3875d7; +} + +.firebugLayoutBoxParent { + z-index: 2147483647; + position: absolute; + border-right: 1px dashed #BBBBBB; + border-bottom: 1px dashed #BBBBBB; +} + +.firebugRulerH { + position: absolute; + top: -15px; + left: 0; + width: 100%; + height: 14px; + background: url(chrome://firebug/skin/rulerH.png) repeat-x; + border-top: 1px solid #BBBBBB; + border-right: 1px dashed #BBBBBB; + border-bottom: 1px solid #000000; +} + +.firebugRulerV { + position: absolute; + top: 0; + left: -15px; + width: 14px; + height: 100%; + background: url(chrome://firebug/skin/rulerV.png) repeat-y; + border-left: 1px solid #BBBBBB; + border-right: 1px solid #000000; + border-bottom: 1px dashed #BBBBBB; +} + +.overflowRulerX > .firebugRulerV { + left: 0; +} + +.overflowRulerY > .firebugRulerH { + top: 0; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.firebugLayoutBoxOffset { + z-index: 2147483647; + position: absolute; + opacity: 0.8; +} + +.firebugLayoutBoxMargin { + background-color: #EDFF64; +} + +.firebugLayoutBoxBorder { + background-color: #666666; +} + +.firebugLayoutBoxPadding { + background-color: SlateBlue; +} + +.firebugLayoutBoxContent { + background-color: SkyBlue; +} + +/*.firebugHighlightGroup .firebugLayoutBox { + background-color: transparent; +} + +.firebugHighlightBox { + background-color: Blue !important; +}*/ + +.firebugLayoutLine { + z-index: 2147483647; + background-color: #000000; + opacity: 0.4; +} + +.firebugLayoutLineLeft, +.firebugLayoutLineRight { + position: fixed; + width: 1px; + height: 100%; +} + +.firebugLayoutLineTop, +.firebugLayoutLineBottom { + position: absolute; + width: 100%; + height: 1px; +} + +.firebugLayoutLineTop { + margin-top: -1px; + border-top: 1px solid #999999; +} + +.firebugLayoutLineRight { + border-right: 1px solid #999999; +} + +.firebugLayoutLineBottom { + border-bottom: 1px solid #999999; +} + +.firebugLayoutLineLeft { + margin-left: -1px; + border-left: 1px solid #999999; +} diff --git a/templates/html/assets/stylesheets/main.css b/templates/html/assets/stylesheets/main.css new file mode 100644 index 0000000..b83efd6 --- /dev/null +++ b/templates/html/assets/stylesheets/main.css @@ -0,0 +1,443 @@ +/* @group Tags */ + +body { + font-family: Verdana, sans-serif; +} + +form { + margin: 0; + padding: 0; +} + +a { + color: #036; + text-decoration: none; +} + + p a { + border-bottom: 1px solid #999; + padding: 0 1px; + } + + p a:hover { + background-color: #036; + color: #fff; + border-bottom: 1px solid #036; + } + +h1, h2, h3, h4, h5, h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 0; + padding: 0; +} + +pre { + padding: 0; +} + +code { + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", monospace; + font-size: 11px; +} + + +/* @end */ + +/* @group Masthead */ + +div#masthead { + background: url(../images/header-stripe-small.png) repeat-x top left; + height: 76px; +} + +div#masthead div#masthead_content { + margin: 0 auto; + width: 835px; + position: relative; +} + +div#masthead h1#logo { + background: url(../images/header-logo-small.png) no-repeat 0 1px; + width: 118px; + height: 76px; + position: relative; + left: 60px; +} + + + +/* @end */ + +/* @group Main */ + +#main { + width: 840px; + margin: 20px auto; + position: relative; +} + + #main h2 { + color: #444; + font-size: 22px; + padding-left: 69px; + margin-top: 0; + } + + #main h2 span { + color: #ccc; + display: block; + text-transform: uppercase; + font-size: 13px; + margin-bottom: -10px; + padding-left: 2px; + } + + #main h2 a { + color: #444; + text-decoration: none; + } + + #main h2 a:hover { + color: #222; + border-bottom: 1px solid #999; + } + + #main h4, h5, h6 { + padding-left: 4px; + } + + #main li h4, + #main li h5, + #main li h6 { + padding-left: 0; + } + + #main h4.inherited { + color: #888 !important; + } + + + #main .section { + overflow: hidden; + padding-left: 65px; + padding-bottom: 0; + margin: 5px 0 0; + } + + #main .section h3 { + position: absolute; + left: -85px; + width: 110px; + text-align: right; + font-size: 13px; + padding-top: 3px; + color: #999; + line-height: 100%; + min-height: 30px; + } + + #main .section h4 { + font-size: 15px; + color: #444; + margin: 0 0 0.3em; + } + + #main .section h4.inherited { + color: #888; + } + + #main .section h4.inherited a { + color: #49B; + } + + #main p { + margin: 0 0 1.1em; + } + + #main pre { + background-color: #000; + color: #fff; + padding: 5px 10px; + margin: 0 0 5px; + } + + #main pre.syntax { + background-color: #f5f5f5; + color: #000; + padding: 3px 5px; + } + +#main .section p.purpose { + background-color: #CDE0FB; + padding: 3px 5px; +} + +#main .section p { + padding: 0 5px; +} + +#main ul, #main ol { + padding-left: 5px; + margin: 0 0 10px; +} + +#main ul, #main ul li { + list-style-type: none; +} + + +#main #excerpt p { + color: #000; + border-left: 3px solid #bbb; + padding: 0; + margin-left: -10px; + font-size: 94%; + padding-left: 10px; +} + +#main .meta { + position: absolute; + width: 108px; + left: -60px; + text-align: right; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + font-weight: bold; + color: #888; +} + + + +/* @end */ + +/* @group Method List */ + +ul.method-list li { + display: inline; + border-top: 1px solid #ccc; +} + + ul.method-list li a { + background-color: #eee; + padding: 2px 3px; + border: 1px solid #ccc; + } + + ul.method-list li a:hover { + background-color: #ddd; + } + + + +/* @end */ + +/* @group Menu */ + +#menu { + width: 840px; + margin: 0 auto; + position: relative; + height: 25px; +} + +#menu div { + width: 234px; + float: right; + margin: 0 3px; +} + + #menu div.search-box { + width: 222px; + background-color: #cee8c3; + font-size: 13px; + height: 25px; + line-height: 25px; + padding: 2px 6px; + } + + #menu div.search-box label { + color: #555; + } + + #menu div.search-box input { + border: 1px solid #bbb; + padding: 2px; + width: 163px; + } + + +#menu h2 { + font-size: 13px; + font-weight: normal; +} + + #menu h2 a { + height: 25px; + line-height: 25px; + display: block; + text-align: center; + background-color: #CDE0FB; + font-family: Verdana, sans-serif; + padding: 2px 6px; + } + + #menu h2 a:hover { + background-color: #a4c8fb; + } + + #menu #api_menu, + #menu #search_results { + border: 1px solid #ddd; + background: #fff; + position: absolute; + width: 232px; + top: 26px; + z-index: 1500; + max-height: 200px; + overflow: auto; + } + + #menu #api_menu { + right: 3px; + } + + #menu #search_results { + right: 243px; + } + + + #menu .menu-items li { + background-color: #fff; + } + + #menu .menu-items li a { + display: block; + color: #333; + background-color: #fff; + padding: 2px 6px; + border-top: 1px solid #fff; + border-bottom: 1px solid #fff; + } + + #menu .menu-items li a:hover, + #menu .menu-items li.highlighted a { + background-color: #CDE0FB; + border-top-color: #a4c8fb; + border-bottom-color: #a4c8fb; + } + + + #menu .menu-items ul { + margin: 0; + padding: 0; + } + +#menu .menu-items li a { + background-repeat: no-repeat; + background-position: 6px 3px; + padding: 3px 5px 3px 30px; + font-size: 12px; +} + + #menu .menu-items li a.class { + background-image: url(../images/class.png); + } + + #menu .menu-items li a.namespace { + background-image: url(../images/namespace.png); + } + + #menu .menu-items li a.mixin { + background-image: url(../images/mixin.png); + } + + #menu .menu-items li a.section { + text-transform: uppercase; + color: #777; + background-image: url(../images/section.png); + } + + #menu .menu-items li a.class_method, + #menu .menu-items li a.instance_method, + #menu .menu-items li a.utility { + background-image: url(../images/method.png); + } + + #menu .menu-items li a.class_property, + #menu .menu-items li a.instance_property { + background-image: url(../images/property.png); + } + + #menu .menu-items li a.constructor { + background-image: url(../images/constructor.png); + } + + #menu .menu-items li a.constant { + background-image: url(../images/constant.png); + } + + +/* @end */ + +/* @group Section Headings (H3s) */ + +.section h3 { + padding-right: 25px; + background-repeat: no-repeat; + background-position: right 4px; +} + +.section-superclass h3 { + background-image: url(../images/class.png); +} + +.section-method-list h3, +.section-instance_methods h3, +.section-klass_methods h3 { + background-image: url(../images/method.png); +} + +.section-klass_properties h3, +.section-instance_properties h3 { + background-image: url(../images/property.png); +} + +.section-constructor h3 { + background-image: url(../images/constructor.png); +} + +.section-constants h3 { + background-image: url(../images/constant.png); +} + +.section-mixins h3 { + background-image: url(../images/mixin.png); +} + + +/* @end */ + + + +/* @group Method Details List */ + +ul.method-details-list li { + border: 2px solid #fff; +} + +ul.method-details-list li.highlighted { + border: 2px solid #CDE0FB; +} + +/* @end */ + + +/* floating menu */ + +#menu.fixed { + position: fixed; + top: 0; + z-index: 1000; + left: 232px; +} + diff --git a/templates/html/assets/stylesheets/screen.css b/templates/html/assets/stylesheets/screen.css new file mode 100644 index 0000000..4fe5077 --- /dev/null +++ b/templates/html/assets/stylesheets/screen.css @@ -0,0 +1,244 @@ + + +/* Masthead */ + +div#masthead { + background: url(http://prototype.conio.net/new/images/header-stripe.png) repeat-x top left; + height: 152px; +} + +div#masthead div#masthead_content { + margin: 0 auto; + width: 835px; + position: relative; +} + +div#masthead h1#logo { + background: url(http://prototype.conio.net/new/images/header-logo.png) no-repeat 0 1px; + width: 236px; + height: 152px; +} + +div#masthead div#pitch { + position: absolute; + background: url(http://prototype.conio.net/new/images/header-copy.png) no-repeat 0 1px; + top: 0; + left: 300px; + width: 535px; + height: 152px; +} + +div#masthead h1#logo *, +div#masthead div#pitch * { + display: none; +} + + +/* Buttons */ + +div#buttons, div#more { + overflow: hidden; + width: 840px; + margin: -1px auto 0 auto; + padding: 0 0 0 5px; +} + +div#more { + margin-top: 35px; +} + +div#buttons li { + display: block; + float: left; + border-top: 1px solid #929fb3; + margin: 0 5px 0 0; + width: 175px; + height: 100px; +} + +div#more li { + height: 50px; +} + +div#buttons li a { + display: block; + position: relative; + width: 175px; + height: 100px; + text-decoration: none; + background: #cde0fb no-repeat center 30px; +} + +div#buttons li a:hover { + background-color: #a4c8fb; +} + +div#buttons li a span.title { + display: none; +} + +div#buttons li a span.description { + position: absolute; + display: block; + width: 175px; + top: 55px; + text-align: center; + color: #666; +} + +div#more li a span.title { + position: absolute; + display: block; + width: 175px; + top: 15px; + text-align: center; + color: #666; +} + +div#buttons li a:hover span.description { + color: #333; +} + +div#buttons li#download_button { + width: 295px; +} + +div#buttons li#download_button a, +div#buttons li#download_button a span.description { + width: 295px; +} + +div#buttons li#download_button a { + background-color: #cee8c3; + background-image: url(http://prototype.conio.net/new/images/button-download.png); +} + +div#buttons li#download_button a:hover { + background-color: #a4e289; +} + +div#buttons li#learn_button a { + background-image: url(http://prototype.conio.net/new/images/button-learn.png); +} + +div#buttons li#discuss_button a { + background-image: url(http://prototype.conio.net/new/images/button-discuss.png); +} + +div#buttons li#contribute_button a { + background-image: url(http://prototype.conio.net/new/images/button-contribute.png); +} + +div#more { + position: relative; + height: 400px; + margin: 15px 60px; + color: #444; +} + + div#more .column { + display: block; + float: left; + margin: 0 5px 0 0; + padding-left: 5px; + min-height: 300px; + } + + div#more h3 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + letter-spacing: -1px; + font-weight: bold; + color: #444; + font-size: 18px; + margin: 0 0 5px; + } + +.column { + width: 175px; +} + +.wide-column { + width: 295px; +} + +.medium-column { + width: 235px; +} + +.main-column { + width: 530px; +} + +.sidebar-column { + width: 290px; +} + +div#more { + width: 840px; + margin: 25px auto 0; +} + +/*#buttons_wrapper { + background-color: #0E4FAF; +} + +#page { + background-color: #292929; +} +*/ + +div#more div.main-column p { + font-size: 16px; + margin-right: 10px; +} + +div#more h3.tagline { + height: 23px; + background: url(../images/tagline.png) no-repeat top left; + width: 530px; +} + + div#more h3.tagline span { display: none; } + +.view-master { + text-align: center; + font-family: Verdana; + color: #ccc; + font-size: 18px; + padding: 35px 0; + margin: 10px 0; +} + +.using-prototype { + border-top: 2px solid #ddd; + border-bottom: 2px solid #ddd; + margin: 25px 10px 10px 0; + padding: 5px 0; +} + +.sidebar-column h4 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + font-weight: bold; + margin: 0; +} + +.sidebar-column p { + margin-bottom: 15px; +} + +ol, ol li { + list-style-type: decimal; + line-height: 160%; +} + + ol li { + margin: 0 0 2px; + } + +ol, ul { + margin: 0 0 15px; + padding-left: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + diff --git a/templates/html/helpers.rb b/templates/html/helpers.rb new file mode 100644 index 0000000..c9a74f9 --- /dev/null +++ b/templates/html/helpers.rb @@ -0,0 +1,150 @@ +module PDoc + module Generators + module Html + module Helpers + module BaseHelper + def content_tag(tag_name, content, attributes = {}) + "<#{tag_name}#{attributes_to_html(attributes)}>#{content}" + end + + def img_tag(filename, attributes = {}) + attributes.merge! :src => "#{path_prefix}images/#{filename}" + tag(:img, attributes) + end + + def tag(tag_name, attributes = {}) + "<#{tag_name}#{attributes_to_html(attributes)} />" + end + + def link_to(name, path, attributes={}) + content_tag(:a, name, attributes.merge(:href => path)) + end + + def htmlize(markdown) + BlueCloth.new(markdown).to_html + end + + def javascript_include_tag(*names) + names.map do |name| + attributes = { + :src => "#{path_prefix}javascripts/#{name}.js", + :type => "text/javascript", + :charset => "utf-8" + } + content_tag(:script, "", attributes) + end.join("\n") + end + + def stylesheet_link_tag(*names) + names.map do |name| + attributes = { + :href => "#{path_prefix}stylesheets/#{name}.css", + :type => "text/css", + :media => "screen, projection", + :charset => "utf-8", + :rel => "stylesheet" + } + tag(:link, attributes) + end.join("\n") + end + + private + def attributes_to_html(attributes) + attributes.map { |k, v| v ? " #{k}=\"#{v}\"" : "" }.join + end + end + + module LinkHelper + def path_prefix + "../" * depth + end + + def path_to(obj) + path = path_prefix << [obj.section.name].concat(obj.namespace_string.downcase.split('.')).join("/") + has_own_page?(obj) ? "#{path}/#{obj.id.downcase}.html" : "#{path}.html##{dom_id(obj)}" + end + + def auto_link(obj, short = true, attributes = {}) + obj = root.find_by_name(obj) || obj if obj.is_a?(String) + return nil if obj.nil? + return obj if obj.is_a?(String) + name = short ? obj.name : obj.full_name + link_to(name, path_to(obj), { :title => "#{obj.full_name} (#{obj.type})" }.merge(attributes)) + end + + def auto_link_code(obj, short = true, attributes = {}) + return "#{auto_link(obj, short, attributes)}" + end + + def auto_link_content(content) + content.gsub(/\[\[([a-zA-Z$\.#]+)(?:\s+([^\]]+))?\]\]/) do |m| + if doc_instance = root.find_by_name($1) + $2 ? link_to($2, path_to(doc_instance)) : + auto_link_code(doc_instance, false) + else + $1 + end + end + end + + def dom_id(obj) + "#{obj.id}-#{obj.type.gsub(/\s+/, '_')}" + end + + private + def has_own_page?(obj) + obj.is_a?(Documentation::Namespace) || obj.is_a?(Documentation::Utility) + end + end + + module CodeHelper + def method_synopsis(object) + if (object.methodized?) + return <<-EOS +
    #{ object.signature } -> #{ auto_link(object.returns, false) }
    +#{ object.generic_signature } -> #{ auto_link(object.returns, false) }
    + EOS + end + + <<-EOS +
    #{ object.signature } -> #{ auto_link(object.returns, false) }
    + EOS + end + end + + module MenuHelper + def menu(obj) + class_names = menu_class_name(obj) + html = <<-EOS + + EOS + unless obj.children.empty? + html << content_tag(:ul, obj.children.map { |n|menu(n) }.join("\n")) + end + content_tag(:li, html, :class => class_names) + end + + def menu_class_name(obj) + if !doc_instance + nil + elsif obj == doc_instance + "current" + elsif obj.descendants.include?(doc_instance) + "current-parent" + else + nil + end + end + + def class_names_for(obj) + classes = [obj.type.gsub(/\s+/, '-')] + classes << "deprecated" if obj.deprecated? + classes.join(" ") + end + end + end + end + end +end diff --git a/templates/html/index.erb b/templates/html/index.erb new file mode 100644 index 0000000..a7aa493 --- /dev/null +++ b/templates/html/index.erb @@ -0,0 +1,25 @@ +<% @title = "Home" %> + +

    Prototype API

    + +
    +

    Welcome to the Prototype API Documentation.

    +
    + + +
    +
    +

    Sections

    +
    + +
    +
      + <% @root.sections.each do |section| %> +
    • +

      <%= auto_link(section.name) %>

      +

      <%= section.short_description %>

      +
    • + <% end %> +
    +
    +
    \ No newline at end of file diff --git a/templates/html/item_index.js.erb b/templates/html/item_index.js.erb new file mode 100644 index 0000000..b69d4dd --- /dev/null +++ b/templates/html/item_index.js.erb @@ -0,0 +1,6 @@ +if (!window.PDoc) window.PDoc = {}; +PDoc.elements = { + <%= @root.map { |e, i| + "'#{e.full_name}': { 'name': '#{e.full_name}', 'type': '#{e.type}', 'path': '#{path_to(e)}' }" }.join(",\n") + %> +}; \ No newline at end of file diff --git a/templates/html/layout.erb b/templates/html/layout.erb new file mode 100644 index 0000000..6227d0e --- /dev/null +++ b/templates/html/layout.erb @@ -0,0 +1,65 @@ + + + + + Prototype API documentation | <%= @title %> + + + <%= javascript_include_tag "prototype", "effects", "controls" %> + <%= javascript_include_tag "application", "code_highlighter" %> + + <%= javascript_include_tag "item_index" %> + + + <%= stylesheet_link_tag "grid", "highlighter", "core", "api" %> + + + + +
    + +
    +
    +

    Prototype JavaScript framework

    +
    +
    + + + +
    + + <%= @content_for_layout %> + +
    + + + +
    + + + diff --git a/templates/html/namespace.erb b/templates/html/namespace.erb new file mode 100644 index 0000000..ccfecf7 --- /dev/null +++ b/templates/html/namespace.erb @@ -0,0 +1,157 @@ +<% d = @doc_instance %> + +<% @title = "#{d.full_name} (#{d.type})" %> + +<%= include "partials/breadcrumbs", :object => d %> + +

    + <%= d.type %> <%= d.full_name %> +

    + +<% # Does it have a description? %> + +<% if d.description %> +
    + +
    +

    Description

    +
    + +
    + <%= htmlize(d.description) %> +
    + +
    +<% end %> + +<% # Is it a CLASS? %> +<% if @doc_instance.is_a?(Documentation::Klass) %> + + <% if @doc_instance.superklass %> +
    +
    +

    Superclass

    +
    + +
    +

    <%= auto_link_code(d.superklass, false) %>

    +
    +
    + <% end %> + + <% unless @doc_instance.subklasses.empty? %> +
    +
    +

    Subclasses

    +
    + +
    +

    <%= d.subklasses.map { |s| auto_link_code(s, false) }.join(', ') %>

    +
    +
    + <% end %> + +<% end %> + +<% # Does it have MIXINS? %> +<% unless @doc_instance.mixins.empty? %> +
    +
    +

    Includes

    +
    + +
    +

    <%= d.mixins.map { |m| auto_link_code(m, false) }.join(', ') %>

    +
    +
    +<% end %> + +<% # Are there related utilities? %> +<% unless @doc_instance.related_utilities.empty? %> +
    +
    +

    Related utilities

    +
    + +
    +

    <%= d.related_utilities.map { |u| auto_link_code(u, false) }.join(', ') %>

    +
    +
    +<% end %> + +<% # List its methods. %> +<% unless d.all_methods.empty? && d.mixins.empty? %> +
    +
    +

    Methods

    +
    + +
    +
      + <% d.all_methods.each do |method| %> +
    • <%= auto_link_code(method, true, :class => class_names_for(method)) %>
    • + <% end %> +
    + + <% unless @doc_instance.mixins.empty? %> + <% d.mixins.each do |mixin| %> +

    Inherited from <%= auto_link(mixin) %>

    +
      + <% mixin.all_methods.each do |method| %> +
    • <%= auto_link_code(method, true, :class => class_names_for(method)) %>
    • + <% end %> +
    + <% end %> + <% end %> + + +
    + +
    +<% end %> + +<% if d.is_a?(Documentation::Klass) && d.constructor %> +
    +
    +

    Constructor

    +
    + +
    +
    <%= d.constructor.ebnf_expressions.join("\n").strip %>
    + +

    <%= htmlize(d.constructor.description) %>

    + +
    + +
    +<% end %> + + +<% +types = { + :constants => "Constants", + :klass_methods => "Class methods", + :klass_properties => "Class properties", + :instance_methods => "Instance methods", + :instance_properties => "Instance properties" +} +%> + +<% types.each do |method, title| %> + <% methods = d.send(method) %> + <% unless methods.empty? %> +
    + +
    +

    <%= title %>

    +
    + +
    +
      + <%= include "partials/short_description", :collection => methods %> +
    + +
    +
    + <% end %> +<% end %> \ No newline at end of file diff --git a/templates/html/partials/breadcrumbs.erb b/templates/html/partials/breadcrumbs.erb new file mode 100644 index 0000000..7e02719 --- /dev/null +++ b/templates/html/partials/breadcrumbs.erb @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/templates/html/partials/short_description.erb b/templates/html/partials/short_description.erb new file mode 100644 index 0000000..9c402fe --- /dev/null +++ b/templates/html/partials/short_description.erb @@ -0,0 +1,50 @@ +
  • +

    <%= object.name %>

    + + <% if object.is_a?(Documentation::Method) %> + <%= method_synopsis(object) %> + <% unless object.arguments.empty? %> +
      + <% object.arguments.each do |arg| %> +
    • + <%= arg.name %> + <% unless arg.types.empty? %> + (<%= arg.types.map { |t| auto_link_code(t, false) }.join(' | ') %>) + <% end %> + <%= ' – ' + arg.description unless arg.description.empty? %> +
    • + <% end %> +
    + <% end %> + <% end %> + + + + + <%= htmlize(object.description) %> + + <% # Does it have an alias? %> + <% unless object.aliases.empty? %> +

    Aliased as: <%= object.aliases.map { |a| auto_link_code(a, false) }.join(', ') %>

    + <% end %> + + <% # Is it an alias of something else? %> + <% if object.alias? %> +

    Alias of: <%= auto_link_code(object.alias_of, false) %>

    + <% end %> + + <% # Is it related to something? %> + <% if object.is_a?(Documentation::Utility) && object.related_to %> + + <% end %> + + + <% # Is it methodized? %> + <% if object.is_a?(Documentation::Method) && object.methodized? %> +

    This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.

    + <% end %> + + + +
  • diff --git a/templates/html/section.erb b/templates/html/section.erb new file mode 100644 index 0000000..2b7bdc0 --- /dev/null +++ b/templates/html/section.erb @@ -0,0 +1,90 @@ +<% @title = "#{@doc_instance.full_name} section" %> +<% section = @doc_instance %> + +<%= include "partials/breadcrumbs", :object => section %> + +

    + Section <%= section.name %> +

    + +
    + +
    +

    Description

    +
    + +
    + <%= htmlize(section.description) %> +
    + +
    + +<% # Iterate over the items in this section. %> + +<% utilities = section.utilities %> +<% unless utilities.empty? %> + +
    +
    +

    Utilities

    +
    + +
    +
      + <% utilities.each do |utility| %> +
    • <%= auto_link_code(utility) %>
    • + <% end %> +
    +
    +
    + +<% end %> + +<% namespaces = section.namespaces %> +<% unless namespaces.empty? %> + +
    +
    +

    Namespaces

    +
    + +
    +
      + <% namespaces.each do |namespace| %> +
    • <%= auto_link_code(namespace) %>
    • + <% end %> +
    +
    +
    + +<% end %> + +<% klasses = section.klasses %> +<% unless klasses.empty? %> + +
    + +
    +

    Classes

    +
    + +
    +
      + <% klasses.each do |klass| %> +
    • +

      + <%= klass.full_name %> +

      + + <% unless klass.short_description.nil? %> +

      <%= htmlize(klass.short_description) %>

      + <% end %> + +
    • + <% end %> +
    +
    + +
    + +<% end %> \ No newline at end of file diff --git a/templates/html/utility.erb b/templates/html/utility.erb new file mode 100644 index 0000000..3ffc98d --- /dev/null +++ b/templates/html/utility.erb @@ -0,0 +1,21 @@ +<% d = @doc_instance %> + +<% @title = "#{@doc_instance.full_name} utility" %> + +<%= include "partials/breadcrumbs", :object => d %> + +

    + utility <%= @doc_instance.name %> +

    + +
    +
    +

    Description

    +
    + +
    +
      + <%= include "partials/short_description", :collection => [@doc_instance] %> +
    +
    +
    \ No newline at end of file