JFIFHH(ICC_PROFILE0mntrRGB XYZ acsp- desctrXYZdgXYZxbXYZrTRC(gTRC(bTRC(wtptcprtiPSP Вpu9b"PH+MC<žϓItu'b=o8vӆDD.Gh jLDf@S)"xp\xdD޸@q0^Ks(>ϛd? @5ARA((A(]|N-7<78qr>}7ΩrWvϋ>+gI&!4Qxsf:?9(mɦdy9$נTVm[x3X&$eg]9^tihkhٹj>@"`f}no0773 l^9DcWt!>>:Kwa>OJuvSo %3Ughvò"ݦ-22HHpu^6.=)J$'DuV㎾>ZN$m\R :o1RU.Z}NăTb '!׌_FŢBjg]5Ź a@(yяj) 6 H5%=THU|qSfΏC[s?qk7ĤD&P]>z@[³$|\=ܜ2|ݏƽd5StQ(uVINi:W5ﱏ珔WAS\{4V6w8תm9  ?f+voͧξyK˒ɉQqglq?kYqbj=O`d3JO_6oի>ӜY33$ U /c^(e )TmMar,/}O_)>qvQĝEL^2z*%d:|64Tcvms9h5l<ö !kSdLLINivZyxlЍd5K`IϮ5m=_n~G@n`yqol?6՗ˏRcz}(w%HYMsMqt9nmueovEI9qсa[s{O& wzd\Ua%L")T)fL`^ټQ$"} a59"ddE5;Z8"`zC7ayz "~om~iMeO]ʢG0c|_k'Љ_rGSfk,)ɘ@?9vc]9齛v9 #87|vr]uU_'W4 "@҃LV dwjEd@+7[ven3r%Eq?VD6ti{nO"I@'1C,i\}=k;g/~7LnGI[_z-%;f%lsItTxɛK ʊ_VnB^95Žnr|h>~?>n0R*GGnng鳓KI[^a2/]QTuT0+U|56v j-^yt^+/m%3T10._?f5[7ygezHl~>~8v5Y59+B&(.5ٿw/Nd.w~M5L܏FNl8v'n#3TmC" )*`|sg>D-J ^GERVIrf1ϩOGݠ>^+nC< vfF7ǢMK՜_M}W0v:rv :Nϰf8*\ h \kqar :+ߛMW̕;XP*ژY7iomOi4^€γ7_vnRq=\t(s}0C_5oC'vf4ٳ2S.٘N 3Kjߘ!*4Э6pc_1,;gܧ%t=ǒvYSm8s`wcl?73cN3}{rOյ `g'g.L/}uҚns&:`GW\Hy?uY|ֆaMB` H4t˳} oե Un="-MU`*Onse^^hYZJЙ>o6;Λ`k t$"*E_1a欳tmn1L𢘘g}[9ו)4.0hϗ(5Ao\h#B$dͽ>UX&$DQbgٰ|ys*&`8Cz~or,- "@M%<Ӝlc(7>4xRay"IW6=0UH_FNGJML)Ni}6mU ){x?4;s!+SP5'?0+bgE`P)-gζVzx Lt wg$T"21\ި]Պ " ]FNqBSʝWq]|'<_sB^DA0L ;筬s?Ek:p @zsKZ &Q`Bk<޾dSWI3YC۳9;Gug_s:[ 4gsҼZpl3;1wG^NXlk1Pcƀ}sKSUC:wS JIo l^w: o CW&OLMomr7Vb>L /dLT/.=.Vu[+J'?dK btRzji@Đ r#b¯K)Νqi"2+1k\*3,vpKةIqaS3L %drV\+LуsSD$OW/5(K+B>TѬ2bI&RiqG%J Igǫ6Ec6yEbXL\wzm~(}kkى+X==KN8gvhR3goa #n (_^ME*Qؾ^K.F= J}drH"7;?*"ejw BJc|QJS̜VN(`;ms$~sccTCc?SOY<ޜD:ow!kܞLDWčfsT }&ip䋛ݘg蒻҃>σ007: &QM_-U1y< lk"> .A&Y:h*t7"{|_I{xV125:st'XeE嶐aN5vWIo/o#[Ґ.y-\qF7:srΔ\反$h@szFY'<=.u)sUjvsv[)#gZSO7pwѦh`|#ljPهK4)ڜ+$j1֊1Pq #liZۄSzHM.ƻV͏[#C9.hqǬ]J>:xr˂&"*DMuG+}V(l \ʆ&ܟl_cy ydC&MLY6TUA4ac&#YUB),ʡj;aD߮']i>h$&*4]0fe˨('*+V#`La\y-zhdPrE_ѓ-ƹ N` lnbͰ_O\vfIe|JkPՋ"DreM],74_Q+[FY˖'`!d~M..74F$*~`b'ˏ ?CƯ%Ӯ[8U{ӿGiKYEѡm\yQ<_?܈xTE.or=qF&ٱgƱx6t:uob}tN٢ ܥ_IK/bpW6Ƌ-,֤Wl_.~ aN~NҸL[&%/Uߞ.#.oGzH-k]`M)gؖ 061f/eR{SgL:-4z(fDFҞl7iQ>k<=액a~ЅbM1zH^'N(7@xyb| -g),IVKYh`}8nʏWYGO?aat H!nPŒ)f,'UmbעxȆ2!*֮ӧEUi0Pͨ .<<*PwK7$&R]_jiЉ[}?.sw~}}tgV%jtPlj=-xK=hkcuv-E\vYbu#9z}ʝM|q> E܌6dı+Umaɐ?ؓ ;ȭ6&6wFׂC쫌iCGa[#w[xN|4=%!z$2}.Eig ʽcJ?dd2snO .&HtO"OMN囸=EӬ2:?4}Й ǗS"r&*[MkKA6@wƿvp&! ˭\y,+ Da~HmfpđJ*$sRHf7Pj6d(K\!CMؐoOr74v;<\1L](.;c?Z ,t.X=biKvjUGLIC,UF'qMbZ≩VJI\z]w s~PL,࿬Lj9sFvq*r$X_Zw\ K4}f~IȽ\3p60-[~B|!H5pZ38f7tsn5 ^KzCU6u@ޯf +=C u$ކf_mrXW&jT~]YsTofq}@sTΜ)~Ywh]sμ\\ OKXHfZ||ijdEx1+F0=@JyL&Ze4{.>Ҡ}yHW"6 XBZP3o/#ǐ4-4s}Zr:l"KBr4(L Ak'f'iIbXw 6䞬Rpb}Nj9gQgI2Z5ʅFiŵYm^|[UUe,1kJj`g<_g Og=Gi kslwfgLi\q1FGD-?}JcJ NNV7OcYkR8_~D3&.fv`!C1(\nbnjJr[\ѝ9ϒ9Թk= e}U{&85U5 % ֹ }Jҵ~]MW\`ޤrΞ \웝,gv;&'.9mU.6&W)RnK~))5kD<.7-/VCŘxiz>ʭG!͑k \&)Ha4xodncSp)jc+&kί.[+84L:Sd,XEX E$}bH77;Q4N>Xbl1U囕ڽYv'56s4n'+F(|v?ϏϏD{C6*nk`0pu:7`KjJ݂Jd<'4۵r+9|S;w|dHh\ ETUq,n"Zl2$¢~f),*/"x<{Eoq3QZ,>BlLh )I4v>*vҊ8D||7Ό\LM,ڵ8zSlHz {B1`M!u#ƹL_aj58*md>g)V';WG+do:u:v&*MT>>^/Jl{3a.uφwNcy՛@`{x2&ctmUUaM*fA9"t;Jt;čULV/hc"`5a*{1YkSbk9=mTgh61٧_=Vݽ鎲bhU}6Pv7B~(xlԓږKѿgQΣ^Mv ,h?Z߽~gMUij}Gۀ~/gS"$b)LushGQIog:߽Ɨa.7;OL?OvuMiu{piZ0>+(KiMJ9SjXhoب-@@ܮ7R6XQU=ZL$H36rqVNV1IddD:r+"H]9ywf|85D5M#9ֻ_fd琜H-ssi;b\7?\?\? !"1AQa #023@qrBPRb$4sC?f QZ+}d.]c]KT2#t]+]˸g컆{.˸g컆{.˺ok!h<W1iXo1~v$OhDаi" `y" 9?*4$oF?$ԮkNWYOh4Ǐh(Gf^o2k^]+4{"&F#)L:EA{ hZ&nWE:'o84 aSYMkEqM%ycmZرm|teV0'uZxRu_oZ9 ӽiAUžeSYhuXPhg×^W>LQt\T< (*k0jfF`a`~kV}~h;*.7hoi4'LHWa PuCM&ϺAyKPv_,@9 ᥗzV=gVm/LیM/z4oDxGÞ=ylFK#wp/jM }HT疸T95:zkM߸1[ QxCx qWhdv՛2rS3܁oCD2J|:']ţ(]Z&"trL{u#)d;IMdMj `mX<,(V=L^]At~-Uc+Z޿P +Bu'I]PԺ:#`=:Gq<|hhܩRQ!0rn%?6?%E# .Aֻt1- . BM*dHSi07 Lbv`2phF+5LjgԁiʁuPGukoUQu70d:`[8sݨ! պچ:j4#~.3ѼnY ]H-(1retUU<˹ 7Mi ^衮m6[SG`vVޗx]/P5;1]uF{'cA5Ȭ70d v6+nZWn5FW#8Iem˸zS^ "*N*ʹ;B=ۢTzXWa+84Pk{:>.sܒz |Pzrd?rK5T{Mx"&WZ {Y[sm>J1mUKu(pt`qFhU@2"#=u555%70[9/bӛ9As8-8VNrcrsw - h:(ܫg/e? 1t!_B6Y #PVu(21S|J}8dvkM6;m9<^<v -]3/In]/*2^sj'@]5WNI=O> &pDDN݅V{W9RoZK!"2tr-._SK!r\Fڃ!A4emo6䥄sh`wsQ^̺ڳbw6*]]/U{.j[q] G("F4GzgfY@A/gO$|9)JXش#kWmv֕`a] K 96J mQV]GeĮۗl9\]1+N6RX8sHv!W镎fP[tm#'g?g.s\G;z TE><ƆIx%O>OW:hΛ!Y $o/l 9d2FGfGe Nʹdj=cϟx3$4'y*i|OKw2F&5;"FguVkv)=I˜m bn8^ Nkf gY\Un0) _(s^;~~Y n,ӝ[| n>Yطuָ96@r|S&IR`!O^YQ suأvW'D! Zj…>,-u_4UՎGo/nW,iUS-taW8p,i8sŊՖF?TSZU.&F7eP81b GPŮOwgUHSdVnvZJ]6?$]̲Vs$ .*( '6 mM~y }IX捃ÈS&qrfe5kvix&=h0~+#,*쎐S g\TlTҦj Wh؅6VZc6kn &y{]NM)| EH7d{tBȀ/7Lk56'hOaܟ&I]\"9;5uEFʝAP wҿcZu]Vt:S;'z#`)r{;S#jk@Yǰ7z0vGE+P4]=£\0̲#3E5Pc Hu9ta\ 1%7VYT_!NY0+h릉T1 Gr|8xp;0Zcv@ Cڥam cote5ԺI ,u!vl5KiqִTU6BiThb1j sgۓ#9Uf{);:7XY1^qNtN e_ 5g,Ԣc-v js̒l:pMjH:Bm$ڢc9'-D#L׊ ~Ѯ+j{i8dJ5X]VU3UDG iޜHsgg4=Z(n,Xf]jӒ\WpWuEL+7Fó(v0rhNqED|KyD-ɘVz*^h‰(G7ZllS@mLhE5tJ0>,SchTDRc>+ie|/-6k1hplg=To%i׷⢒'PXbdD6FI1'bGHfp4viLv\ݹK4۩9c:mMnͩt5},} .g>g-6ѷS$v* ~~~~sm__TZ˜.e+AUI@ܳձdHތb[+`FeԳ7 e5Z_G9 Þc{AXL_$`X.!B5UvGHS5f,f&66 J IݢFW&5FAءtoZ[A|5]x}N jڻZ(kt{eȲ,{nrN:C,|X;Ʊ)ON*ZB 'j+Cv2MAߏA9|&]ӣ~/o7Ɣ-'='SP4BhnK+=MA51D6@e$ari5,@oV9 wcGWnNKgei;Pk@aɢ8|ήa63qƇTJ0TWd]cIMT 97/Vsx;矐2Vat:..[b6Lu$#iGk - v[y ։`t;B)FkQ1* tl89wRXS FEZN(GꍆLbl/;َo. #=u r:|MkGu\q=;%Ƨ;_]EI;cAP a]j~LASl`~"3HH~XB6d.GYS:+;S_Umnޯ3qwǘִ]]F+_!hBmvjެ^qlNE5?,֚ɉ,A:s$'Ce4j$K{+=8q (,q\P9 ^*]+E$D/ 6aߵHܱǼs.7~mz3BVHAn[7a̼@9)%!Xc9S)<^F8MMOηѼ6Ѧo-xd@М YOJ_4N_mŝ۽F'uWLoC(.;rvý?;3CۚvMai|Ra&Z]`pnq#I拕M1q~ZL"7.Nc{M.J3iڣjowh5gikpj[vګr8(so{a'Z1%:Kk (,y&fh~LB*ڳ\JlKPYm(O/5S'|2Vv)8Q>/H9ׂuѬj; {Ne3_&vIuZ1690ҡ_/D,:Ykow_ZmY蛝{.t$e/Wqج68978_L;(,g\xTW>W'5p :aG21&55*WZI5+/D,1示nVg6yG:զ^RJUY,9<]t g9@cuVEIe*ie5v)U4y|TX=R`Κ!^?+)([g 2+75plS OlnIpڬV@)`9ZT7z؀WkōcxNDSx,Lbu#eٯ6@2 sU$-}RJ`Br U,=%s'Tyjg*:!<./eNjjq .˝~IOHNz&5w:栲btRհtsEx$9^yF’unDY5]'+<͖Pk=gSP1TDDRQ<үiR()|ܢseűK£Y5^CNmRe=ʕRT=#IS'6.2@ fxX3T(1(e Iq{/n= ȓSmir.q+s(1_bWƾR+W+S騆]Fٕ 4*/ILy’l Ik)P+k.cuh2w\A RoAX八nemJ,\te.%|Ŏl&4ZPOP*J5E] jk?1s/ #4g`uők%?/uBM/u7fBŴVb^!8*q #Ḫ՘q.PŊ<,ԛ׽s( P[M1z+db]w.eAC s`^U)\U Y^5% :.ff^dL?M vрUަfa\Zŝ-ݫ/8RU,(<0iϼ?D;KqeRP*B 7KWvp̰ؕT%؏<T`.4fF,8,/P% ҜkA J^mߖŮW%sy3DQ9sd6a'"+D*[oP"b\FħTlXH qYakp}fSf G )wc7+r)Mڢb KX] ya&4_]՛ aWCGHrLO(7ŸEW2\(VML vA"T45־%LK+9\鮲!AM.x"5):N1 [ v$mEthgXOXd;KL5 r~iZ8*Ð*=ʋ~#DW"3Ys$[kY{"8++;o96)*13/g0MV3̸(xA0h*^tOO"V| pQB3"Ζ ijޓʈO1:W9]MʇyOHRPJ j튅klW8ex`+\yZɘ@yJ `0s6^L ZE0][d8 |Y&^(Pd ʕFM[K0@ıe_뾑^/L`KKG}gP@eiFdeO^vo-CRA F5ӭzC6L|0W>LF%wN" T5B̿X)~%M9Jx7)3q"CeVN.,5qXkuqkVVgbj:7=yh3 +YC뼯H^)@8j$ &Jp۝̰r@qϩ7cqd`&"?MܪTcO#r+;iuR9Ȩ#s0k+5JӆLacmY^X) Zd^͜ʬ0Ua4!tu?MJR#p6`xVT۫VU`0MEsؔN)L P6!a+ \wA/W3B]"U͸|BKKtUrVz?]<@by7ӂ-eߘ5 %5WɼӖ\>qYq~\VzL.Rm(͡4/ >Ie^(XIG%`lRk|GWc_(0:~))7XQ9_ Ls f厠Z5ǘs=w.a)v?' >hf-(-0d;ϤY*لS5uP~aX]3R K--Qfc"8B/ 5|Sfpp&WPNI:L@ԓJr_V9uK{)7U`ԻSq>OUg%LepկzC&WAPe[)T+PJTqcIC65~gβmyk(zV[ΥHq%^-|)Hu,Kʫ-֯1!XcD-c*]^XaGw@Iml[2"lO0 h2xY +YPVեi bnX9ŀo81Yc> =8%W:ћ?iJ^#(XX}lѯ_ĵ74 lֳKjmAhqUĤ~ĺW _&h$e gF#*J kT);DkUn{lI+1/&!J"d/kCNᆉYw;V[FE, WjiL$NzDoE_TRgPjXP@Vc$WiI5a3o2e˄Ae0-k7-+i]I~1[+2Q޶BjRd }9f^:djO']"g7r]FqNaįq/%R70ڇ*@FY6ܔE'(_SY~gJ$ JJa 7^0htt`9 Д2k_XU{3./aYU&,R+Ŵ.IN΍ftT/#﹃'bQҶѓHE&kE\dL2ʘ# b/$Db[=w ѫ.n7B=%VBḶGg9|rtzL^gaz?DjVaFHajU`_Vko#<2KHO,ɞ%а~}ٔؖ` 4(lrvt8@C_NLxZOLjZ06R(&wH-Nzq(t#$f%Rc3C=&`˕N" `(⨚\ fVE N#ec1jK@4%@8d/dC`!fUD (5O2ʇct-8k]حN~Ve"^?k0*c}eLeu W*U˶JRw,MNJE}ϡj*2XT-QymnwfkRbRsq&ȡ `L8~Ɏ1F>F `$Vx.hyc-M~= b=w}q _OHKK!5}'[ P,ɧ~]$iR_kU/,_Z M|4ҵ,'jlgw|Լc5ĵ(^ d^' ^yLh]p^jkeі|lͧU#yr.`ʭ*K:K")PrJ[U؃iOįͫ,&4:^y 紻.W~OȔ}qݒ.D)K*u+!Q,{VeoGL(]T+ Ff(yHmp4h*q7nR*v_],Ϭ'q/ ZiQVz̷[#jj1iBXN Bn^5pJa~HѨ%y>=}Q'Uu'6XuXr`^W>%o_YM)܂]:k E(]*ڡ~f@DU[zb}aԳQQwi01 R^`Žl>DeeY#SjuȯSG,Uhx{|?UH>(U&/'ٳ -u0~F2T#lB-:b6jo,a?k􋮔kqkww:~̲1UoX Y.%z=ҩqat,Z*_ \P@T>42IOIrpG\.+Dcz!^j@]K+F+eDT05ObL -A*9BPA ,rBJVp`G>]8WOEW*Z:NV. G$tm9&$rR``2~:fu-PDq.KPT@s Vʭ˂3N}F@_q *1a3ct9HX~&FWaTqnmǤmu׷,q@ ܗ%t?앇.9r..B[2VuEx0%:qbU&NOU5l26}wnSc'H8l=t6TRhX$K`9E8Ԍd.j'~k ]- %.o2)j"V.xs:rH QXX+tیn!5,Az D@U  p [ PRd yp*/]& #njkʭbWƯdԫKUCFY11'tzs+߬pRJlU]J'*5r&!6JRK*Kxū+ng2P}zCf ӿ00}ADfb,T['P{H>эoL>A C@T)z͝ZV~mX@x2S0xo ua}ɼoQ=.UG)(Zk?[q/:1"$nTŀ^~zW]:ࠚ{D4+E]=%uT8kP4<ĚW*u7ŇM5CN :T̺c JԱk2È%SJ-X@4YtBiw)ŇopV^ПQei2ܪ[2WHX%bxo8ot\J87QoE͸"5`[]EFPk89˗_1,m[̰M싧NUj80,B_bħ. -Ǚ-<@F3 dUxn 6UzBf`t޼·fc6y31+F-+s)Ɇ1p:b`-\6*cQRgDD{?o_ D~+˺+EgJV>ī4/@z*v"!g[Q %-YP+w6gLbqedlѷ04( 3g)ܭpx q6q|6SQ'5~ X&e&7EơRw|8|  mc"ݯx͊ll%>^.RfUjXݼ4,dFxjw_Hr}%ޏ.؃,扏TЃS(HU5WUxDMӋ7)F_\7xf,Yg̩Dd Pj;ITInƉtH(_kbVe)+h]C`qw$7Pٺ\0eƹD`(.syCWbN/Q~56u>u&,Z 5xZ{0^>ﴧl@IuezƱOXa+q.u\b+]5 \Q87>r6p [WKl4+DifP]krXv@ > _ڈi=eJ\CqH\u.NY+*>O̯NL~fw:K*=Pyb^R(/ʽo2ooIҷ>;ݛ+/ ̗s1]bS"cM3wg1pkDQ`\ܳL;le2BKnwToW4\b W07bg\u~f_<ž>x. :p@Qj#U4<3(Tl\ ˵tXb= \Or]7kkyc. ׯˆ(7ȗܹo-}NW>}j-zsW-z?h+9\K6Rm|W[j5t.~!qrcψc(IeGP" % e\GBQaetp,eE.B995.3U7Ի+@ *EZ{+cd,-X1YwOܠuw*WdUBKbq-ŴW!).*U0t.̙ S,V[Kss :L}Ro JT,h}xٌT+/ouk-nlM}c_Joq #0T.epמ˰n vn\ਯɿk 梱%^b!Gw/k(i|5&iԾ7=fAo`㧤jU{̳@ƍ? HJ`ӤB+~PWi*jy֤~HYsu4OǒPPo8 0-)3 kZ;@_v 4cOn엚)U3ؚ1Eem9T\X63.p1po:!g5vM7wz3ԩaR1V헧ya4 n7 Ш,j{6_Z8qbWw,hkdA=)$__'T)NtFu!׃yP? /9GRv>z}'VD-3PUW/7 tǀvnR=}lҁ=Sl<4ޯr$Y1*mOX-~ѝLi~%$" 8`57-U+O4dvC-ea8䶾"Hp`y]0FB2pr F|meUa7䣝U-_O("b?>%sYV#T1SĽ Zp=V6~?| Eec[L܅+0-?+ן,=۫s&jɨM!u\TIXK0bUPxG2,l><be ޥ&}" !c5]nitjZ*tmgGfL%XN+Cn)}-4Vz_1KbR3 h\ʜ# %*(ssDz%ץȱЪgKsi=D\xɄU똬Z#*.s@Qk-l%k LX@*1)Ү/ G pAR@ @B @ `@ $ рE  #\Zd=C'ē8,Z| D/yV H4QpS[?)6#()*kߕ d<LJّ1S ֖'UeFD"Ze)Ѝ ?y43E=/`ҙ挾mw`Њ2`r3QD`4墂|1ITZ fw&:ʐkdj$&Wdfe@`l/Ѭ͊x \+KϥJ:87/NfW\S,iB3:^aAz-ZB)1p(ZЅ2+9cahQ0"Q i!] (Z4:s9,=F 4bx֞a^_}9F3hy͠1/W  d00]4 3v9a+mB% P6/ ೸plw{Qh"&Woǡ _4E=>"H:>V01}W(Ŝ L,ŀ2~ FE!%mC^L|S7p 5iK!`XkPn .C 0- 񨕓QY_`({ PCwW#F+f097a5FCPW([7 1'605!@a,^?߉妀`x`\F/# fm Mn9- ,q30R! W-+.Ee3VEL[FĀlSJw\|_2e&d>xzThz9=LC'U@by@/#/fiD ˜)r -r,珈$6-RkPFAhF?C+j 2#dJ7w/DAd ? һ!Vur^{T*#EGM/t-f~MYhDNG'GCP#9 A}&ǰ Tq8b7'`+z]Z$n܊ > 8 qq7B+D&~5f}Z3 t(&퍑 -@b:y$N#O\ |) ))aZ `z;V$wJ`umCr!{ {WŖS'V\#k@XӜaK4H^ąBɸSűZ o2-_0 p=U7P#:DQ1: 3/A|ElPf$Sncerd,'@Fb_d:y,x1M2JWU; T9\M&Rl.TD/[S Pk`1b4$0\)4nP&+1A1W2 qСm0я0G$?1BfMsо14;RݥK/pҺѸ1`S* Y m? Fa~s~ޖYE@/U/I;ơpM45 z%j 2W͑.yV VB(8E#vi#ă2D(d:2 Xކ R5RHe n^ @1!7QA^>}|N;4Bg#C&7@>â, E$)Z~!Xof} ׁ UlrH2ĀML/̅- 1i-y';$7}_"21IjMa}fm2ގ;LJ?-nWȿ>pZO|2|sw5Fك؅ŘL% ̔@KK| 2(=/lX}_k h H6CR*8x~8Q ]A57=ADi;b3.6MBɣ' (ZauJ U H@TRfS@LA05 .%ȃf e(z&sV4Jf[& 8xZIJ ;kDU2#AW#hRQ& px&onǨOZ=N\ۘ, {y2C+rB A^}e!9*:?V RW d]~bXzBZRU ޥJ'zT Rz(sY7o1$9gHJpJB@nHDg#x+p!JVQ?ߢ#c&#_֢ !K]#C"NEJqBІM_(ad::OC% )x/=t& +P7K;V ) \8YYH3UkT ģl8Ax#C 5`s1 @:?$(\n!_B\;'1#apO'FK4k%`Acm GlQP^ci̘0`[JVj>'ymgS3 eH<L#hAExױD*,~d c * 3-f`{#]cR v 4偩5ɞ.D ۈ dbu4xzP:ŝ6wC]o7Tr3$8J \1J^rFLe`hA`QKf2+G:xq$=#]m+*@827 0LX /Bk ;1-iiL= A&MƫD*ڴ#K"̫&w0kc~ *qTk ~8M- ۆ%H;v 8.?Kv6@Z0AE2hZt@h!T E&nO3etOd^f N@kH8iPyzJa3ZbY␖+’l0`%M S.$gY%B6fA@Vŋ ő J87 :dX!Ì6, { P*UҎk*'ĹqӢ%?Bsi?,%Vq1q]G/(\ϤS328E ?NF5Fb}Qp\MO!dH/J+Y|I.D>e%gX޹xoQFKvxi>$bD(UJkd/|CTڊu&!`U^騾#/ ¡ad_TTegvR #Uxt[T؄5 Q +,|h*W S+ȕ'YBLm{?pK 藭b5L 58Rh*1[C ':l{29p&) dJ @Njٓ *AK Ҵq*g&ZN M 3(rIY |!l;CbJTo#f|D,%[3qQ)h@@GDwyp$?f8fyK}YZL,p(?!N6j2&1^Rsq"Ό-a, fzp**S!U=(I./<ǺvAI>@XAH|gq#kvI]BV50 Fx0#E 00xxNQ5K*_ _-ԈU(F%ec yCd 94fMo >2T6<#d@טjTN qXF%@9FA]#˴U>f b_p25'Cc¡-A >ȵgFGy _16l!cLr*K&֡VLXV~ȽL>D?.,;=gҵEpC. 0^U 9Y*ɐL"r7*JLK gE6sR8oh!a4ՉFv jSP(l$Rҹ+T0T 9ԍoɆ!BP3(002,\nDe.*:u/D+7(#1kV v@9hEE.{Xq6дRa>2Ή1/ T6hP!  McipJHrgz/:/ntiv0!0wN 7^m. [$HW(\V^Ⴀ\FʆIW#,/09(/tH"k&|,N 7xB͹_R0QRt E !`{b_}?@D $4A%CM0@RWB+P ihb"KC e. op >60y*Ѕ_PWemXOd+(0~}3)1yz579rǑ!/B5.ed1Ph"⥉r0;,7Fc*u!AB1f(C˞U@#=NljS.LT9N}zIr;ܩи}'S6죄(ѿ' i 1gs%̧ᣓl"+W;0Oyh)pD\I ǢRaKQc0l{!2}(&_dindmF6ΓHb6wH2kX\`2 bC_ a*1mÔvVZ0b AxB G ?bsFbgw.>R^` ۳Rph> +DT_tC5Y8)"PJ`Qaj8[~1H!>]C(KĶf;%Z͙q~$x*z29 E@[Bx! AY/8hXЀIM L9)Ћ %Q%-9Z2,̖{ Ն!LlįRTE tВ҈W0!]QTц@$7p-6F0?vҵzF^E@^9x"\LE03~"Ҡ@_nVgGl̼#W~}E>R]}4zJƱƠji/= e|[,T[abʳfp*L+Aي$ͩ/b¶TTxFq<ӶyHxQ )Eҗa⡀0jF@D0| 'N-&­yRkd56kIx|SBMWuV&?yQ_N%'Kaw~6Ig{C(ou6 ji ɿR\żs ϔ ?zKQE3'Vb,U'}!']jk4-=*qK5CrXE 6Qu31r˱Ȋ@KT+vL%tq^&B&> #OHAL0K h 0, й#CB4ݲ#mw7[༊~?*r9HspO)~ N >yzTL. ߸ qx@; çdcP80D'غ9;6QnWC6-ziuϖLv>^;tr[H(\(]($J\2+Fr  Cmȳn4i6١$ybzC{eѭ>qcI12t\'$ظY  |ueBy8_ Qʧ,Qp_YIU lqtiU .No aݓ3Ca?҂!`'ȴd3^s2Rr{ pHKe؎n;qG,yTRG<eLJHe]'0q꺬Գ%GD f6$Gd% f7ά{su73rAUظ+55Z|h>?a WTMb-XfSɎʕ kݜԽF!)KtH!d:*(ckvHd= > Default page
  • Your IP: 216.73.216.84
  • Server IP: 13.204.207.56
  • Server: Linux ip-172-31-43-243 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 06:59:36 UTC 2025 x86_64
  • Server Software: Apache/2.4.41 (Ubuntu)
  • PHP Version: 7.4.33
  • Buat File | Buat Folder
Edit File: makegrid.js
'); $editArea.find('textarea').val(value); $editArea .on('keyup', 'textarea', function () { $(g.cEdit).find('.edit_box').val($(this).val()); }); $(g.cEdit).on('keyup', '.edit_box', function () { $editArea.find('textarea').val($(this).val()); }); $editArea.append('
' + g.cellEditHint + '
'); } else { // handle truncated/transformed values values $editArea.addClass('edit_area_loading'); // initialize the original data $td.data('original_data', null); /** * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data */ var sql_query = 'SELECT `' + field_name + '` FROM `' + g.table + '` WHERE ' + where_clause; // Make the Ajax call and get the data, wrap it and insert it g.lastXHR = $.post('sql.php', { 'server' : g.server, 'db' : g.db, 'ajax_request' : true, 'sql_query' : sql_query, 'grid_edit' : true }, function (data) { g.lastXHR = null; $editArea.removeClass('edit_area_loading'); if (typeof data !== 'undefined' && data.success === true) { if ($td.attr('data-type') === 'json') { try { data.value = JSON.stringify(JSON.parse(data.value), null, 4); } catch (e) { // Show as is } } $td.data('original_data', data.value); $(g.cEdit).find('.edit_box').val(data.value); $editArea.append(''); $editArea.find('textarea').val(data.value); $editArea.on('keyup', 'textarea', function () { $(g.cEdit).find('.edit_box').val($(this).val()); }); $(g.cEdit).on('keyup', '.edit_box', function () { $editArea.find('textarea').val($(this).val()); }); $editArea.append('
' + g.cellEditHint + '
'); $editArea.show(); } else { PMA_ajaxShowMessage(data.error, false); } }); // end $.post() } g.isEditCellTextEditable = true; } else if ($td.is('.timefield, .datefield, .datetimefield, .timestampfield')) { var $input_field = $(g.cEdit).find('.edit_box'); // remember current datetime value in $input_field, if it is not null var datetime_value = !is_null ? $input_field.val() : ''; var showMillisec = false; var showMicrosec = false; var timeFormat = 'HH:mm:ss'; // check for decimal places of seconds if (($td.attr('data-decimals') > 0) && ($td.attr('data-type').indexOf('time') !== -1)) { if (datetime_value && datetime_value.indexOf('.') === false) { datetime_value += '.'; } if ($td.attr('data-decimals') > 3) { showMillisec = true; showMicrosec = true; timeFormat = 'HH:mm:ss.lc'; if (datetime_value) { datetime_value += '000000'; var datetime_value = datetime_value.substring(0, datetime_value.indexOf('.') + 7); $input_field.val(datetime_value); } } else { showMillisec = true; timeFormat = 'HH:mm:ss.l'; if (datetime_value) { datetime_value += '000'; var datetime_value = datetime_value.substring(0, datetime_value.indexOf('.') + 4); $input_field.val(datetime_value); } } } // add datetime picker PMA_addDatepicker($input_field, $td.attr('data-type'), { showMillisec: showMillisec, showMicrosec: showMicrosec, timeFormat: timeFormat }); $input_field.on('keyup', function (e) { if (e.which === 13) { // post on pressing "Enter" e.preventDefault(); e.stopPropagation(); g.saveOrPostEditedCell(); } else if (e.which === 27) { } else { toggleDatepickerIfInvalid($td, $input_field); } }); $input_field.datepicker('show'); toggleDatepickerIfInvalid($td, $input_field); // unbind the mousedown event to prevent the problem of // datepicker getting closed, needs to be checked for any // change in names when updating $(document).off('mousedown', $.datepicker._checkExternalClick); // move ui-datepicker-div inside cEdit div var datepicker_div = $('#ui-datepicker-div'); datepicker_div.css({ 'top': 0, 'left': 0, 'position': 'relative' }); $(g.cEdit).append(datepicker_div); // cancel any click on the datepicker element $editArea.find('> *').click(function (e) { e.stopPropagation(); }); g.isEditCellTextEditable = true; } else { g.isEditCellTextEditable = true; // only append edit area hint if there is a null checkbox if ($editArea.children().length > 0) { $editArea.append('
' + g.cellEditHint + '
'); } } if ($editArea.children().length > 0) { $editArea.show(); } } }, /** * Post the content of edited cell. * * @param field Optional, this object contains a boolean named move (true, if called from move* functions) * and a to which the grid_edit should move */ postEditedCell: function (options) { if (g.isSaving) { return; } g.isSaving = true; /** * @var relation_fields Array containing the name/value pairs of relational fields */ var relation_fields = {}; /** * @var relational_display string 'K' if relational key, 'D' if relational display column */ var relational_display = $(g.o).find('input[name=relational_display]:checked').val(); /** * @var transform_fields Array containing the name/value pairs for transformed fields */ var transform_fields = {}; /** * @var transformation_fields Boolean, if there are any transformed fields in the edited cells */ var transformation_fields = false; /** * @var full_sql_query String containing the complete SQL query to update this table */ var full_sql_query = ''; /** * @var rel_fields_list String, url encoded representation of {@link relations_fields} */ var rel_fields_list = ''; /** * @var transform_fields_list String, url encoded representation of {@link transform_fields} */ var transform_fields_list = ''; /** * @var where_clause Array containing where clause for updated fields */ var full_where_clause = []; /** * @var is_unique Boolean, whether the rows in this table is unique or not */ var is_unique = $(g.t).find('td.edit_row_anchor').is('.nonunique') ? 0 : 1; /** * multi edit variables */ var me_fields_name = []; var me_fields_type = []; var me_fields = []; var me_fields_null = []; // alert user if edited table is not unique if (!is_unique) { alert(g.alertNonUnique); } // loop each edited row $(g.t).find('td.to_be_saved').parents('tr').each(function () { var $tr = $(this); var where_clause = $tr.find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } full_where_clause.push(where_clause); var condition_array = JSON.parse($tr.find('.condition_array').val()); /** * multi edit variables, for current row * @TODO array indices are still not correct, they should be md5 of field's name */ var fields_name = []; var fields_type = []; var fields = []; var fields_null = []; // loop each edited cell in a row $tr.find('.to_be_saved').each(function () { /** * @var $this_field Object referring to the td that is being edited */ var $this_field = $(this); /** * @var field_name String containing the name of this field. * @see getFieldName() */ var field_name = getFieldName($(g.t), $this_field); /** * @var this_field_params Array temporary storage for the name/value of current field */ var this_field_params = {}; if ($this_field.is('.transformed')) { transformation_fields = true; } this_field_params[field_name] = $this_field.data('value'); /** * @var is_null String capturing whether 'checkbox_null__' is checked. */ var is_null = this_field_params[field_name] === null; fields_name.push(field_name); if (is_null) { fields_null.push('on'); fields.push(''); } else { if ($this_field.is('.bit')) { fields_type.push('bit'); } else if ($this_field.hasClass('hex')) { fields_type.push('hex'); } fields_null.push(''); // Convert \n to \r\n to be consistent with form submitted value. // The internal browser representation has to be just \n // while form submitted value \r\n, see specification: // https://www.w3.org/TR/html5/forms.html#the-textarea-element fields.push($this_field.data('value').replace(/\n/g, '\r\n')); var cell_index = $this_field.index('.to_be_saved'); if ($this_field.is(':not(.relation, .enum, .set, .bit)')) { if ($this_field.is('.transformed')) { transform_fields[cell_index] = {}; $.extend(transform_fields[cell_index], this_field_params); } } else if ($this_field.is('.relation')) { relation_fields[cell_index] = {}; $.extend(relation_fields[cell_index], this_field_params); } } // check if edited field appears in WHERE clause if (where_clause.indexOf(PMA_urlencode(field_name)) > -1) { var field_str = '`' + g.table + '`.' + '`' + field_name + '`'; for (var field in condition_array) { if (field.indexOf(field_str) > -1) { condition_array[field] = is_null ? 'IS NULL' : '= \'' + this_field_params[field_name].replace(/'/g, '\'\'') + '\''; break; } } } }); // end of loop for every edited cells in a row // save new_clause var new_clause = ''; for (var field in condition_array) { new_clause += field + ' ' + condition_array[field] + ' AND '; } new_clause = new_clause.substring(0, new_clause.length - 5); // remove the last AND $tr.data('new_clause', new_clause); // save condition_array $tr.find('.condition_array').val(JSON.stringify(condition_array)); me_fields_name.push(fields_name); me_fields_type.push(fields_type); me_fields.push(fields); me_fields_null.push(fields_null); }); // end of loop for every edited rows rel_fields_list = $.param(relation_fields); transform_fields_list = $.param(transform_fields); // Make the Ajax post after setting all parameters /** * @var post_params Object containing parameters for the POST request */ var post_params = { 'ajax_request' : true, 'sql_query' : full_sql_query, 'server' : g.server, 'db' : g.db, 'table' : g.table, 'clause_is_unique' : is_unique, 'where_clause' : full_where_clause, 'fields[multi_edit]' : me_fields, 'fields_name[multi_edit]' : me_fields_name, 'fields_type[multi_edit]' : me_fields_type, 'fields_null[multi_edit]' : me_fields_null, 'rel_fields_list' : rel_fields_list, 'do_transformations' : transformation_fields, 'transform_fields_list' : transform_fields_list, 'relational_display' : relational_display, 'goto' : 'sql.php', 'submit_type' : 'save' }; if (!g.saveCellsAtOnce) { $(g.cEdit).find('*').prop('disabled', true); $(g.cEdit).find('.edit_box').addClass('edit_box_posting'); } else { $(g.o).find('div.save_edited').addClass('saving_edited_data') .find('input').prop('disabled', true); // disable the save button } $.ajax({ type: 'POST', url: 'tbl_replace.php', data: post_params, success: function (data) { g.isSaving = false; if (!g.saveCellsAtOnce) { $(g.cEdit).find('*').prop('disabled', false); $(g.cEdit).find('.edit_box').removeClass('edit_box_posting'); } else { $(g.o).find('div.save_edited').removeClass('saving_edited_data') .find('input').prop('disabled', false); // enable the save button back } if (typeof data !== 'undefined' && data.success === true) { if (typeof options === 'undefined' || ! options.move) { PMA_ajaxShowMessage(data.message); } // update where_clause related data in each edited row $(g.t).find('td.to_be_saved').parents('tr').each(function () { var new_clause = $(this).data('new_clause'); var $where_clause = $(this).find('.where_clause'); var old_clause = $where_clause.val(); var decoded_old_clause = old_clause; var decoded_new_clause = new_clause; $where_clause.val(new_clause); // update Edit, Copy, and Delete links also $(this).find('a').each(function () { $(this).attr('href', $(this).attr('href').replace(old_clause, new_clause)); // update delete confirmation in Delete link if ($(this).attr('href').indexOf('DELETE') > -1) { $(this).removeAttr('onclick') .off('click') .on('click', function () { return confirmLink(this, 'DELETE FROM `' + g.db + '`.`' + g.table + '` WHERE ' + decoded_new_clause + (is_unique ? '' : ' LIMIT 1')); }); } }); // update the multi edit checkboxes $(this).find('input[type=checkbox]').each(function () { var $checkbox = $(this); var checkbox_name = $checkbox.attr('name'); var checkbox_value = $checkbox.val(); $checkbox.attr('name', checkbox_name.replace(old_clause, new_clause)); $checkbox.val(checkbox_value.replace(decoded_old_clause, decoded_new_clause)); }); }); // update the display of executed SQL query command if (typeof data.sql_query !== 'undefined') { // extract query box var $result_query = $($.parseHTML(data.sql_query)); var sqlOuter = $result_query.find('.sqlOuter').wrap('

').parent().html(); var tools = $result_query.find('.tools').wrap('

').parent().html(); // sqlOuter and tools will not be present if 'Show SQL queries' configuration is off if (typeof sqlOuter !== 'undefined' && typeof tools !== 'undefined') { $(g.o).find('.result_query:not(:last)').remove(); var $existing_query = $(g.o).find('.result_query'); // If two query box exists update query in second else add a second box if ($existing_query.find('div.sqlOuter').length > 1) { $existing_query.children(':nth-child(4)').remove(); $existing_query.children(':nth-child(4)').remove(); $existing_query.append(sqlOuter + tools); } else { $existing_query.append(sqlOuter + tools); } PMA_highlightSQL($existing_query); } } // hide and/or update the successfully saved cells g.hideEditCell(true, data); // remove the "Save edited cells" button $(g.o).find('div.save_edited').hide(); // update saved fields $(g.t).find('.to_be_saved') .removeClass('to_be_saved') .data('value', null) .data('original_data', null); g.isCellEdited = false; } else { PMA_ajaxShowMessage(data.error, false); if (!g.saveCellsAtOnce) { $(g.t).find('.to_be_saved') .removeClass('to_be_saved'); } } } }).done(function () { if (options !== undefined && options.move) { g.showEditCell(options.cell); } }); // end $.ajax() }, /** * Save edited cell, so it can be posted later. */ saveEditedCell: function () { /** * @var $this_field Object referring to the td that is being edited */ var $this_field = $(g.currentEditCell); var $test_element = ''; // to test the presence of a element var need_to_post = false; /** * @var field_name String containing the name of this field. * @see getFieldName() */ var field_name = getFieldName($(g.t), $this_field); /** * @var this_field_params Array temporary storage for the name/value of current field */ var this_field_params = {}; /** * @var is_null String capturing whether 'checkbox_null__' is checked. */ var is_null = $(g.cEdit).find('input:checkbox').is(':checked'); if ($(g.cEdit).find('.edit_area').is('.edit_area_loading')) { // the edit area is still loading (retrieving cell data), no need to post need_to_post = false; } else if (is_null) { if (!g.wasEditedCellNull) { this_field_params[field_name] = null; need_to_post = true; } } else { if ($this_field.is('.bit')) { this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } else if ($this_field.is('.set')) { $test_element = $(g.cEdit).find('select'); this_field_params[field_name] = $test_element.map(function () { return $(this).val(); }).get().join(','); } else if ($this_field.is('.relation, .enum')) { // for relation and enumeration, take the results from edit box value, // because selected value from drop-down, new window or multiple // selection list will always be updated to the edit box this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } else if ($this_field.hasClass('hex')) { if ($(g.cEdit).find('.edit_box').val().match(/^(0x)?[a-f0-9]*$/i) !== null) { this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } else { var hexError = '

' + PMA_messages.strEnterValidHex + '
'; PMA_ajaxShowMessage(hexError, false); this_field_params[field_name] = PMA_getCellValue(g.currentEditCell); } } else { this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } if (g.wasEditedCellNull || this_field_params[field_name] !== PMA_getCellValue(g.currentEditCell)) { need_to_post = true; } } if (need_to_post) { $(g.currentEditCell).addClass('to_be_saved') .data('value', this_field_params[field_name]); if (g.saveCellsAtOnce) { $(g.o).find('div.save_edited').show(); } g.isCellEdited = true; } return need_to_post; }, /** * Save or post currently edited cell, depending on the "saveCellsAtOnce" configuration. * * @param field Optional, this object contains a boolean named move (true, if called from move* functions) * and a to which the grid_edit should move */ saveOrPostEditedCell: function (options) { var saved = g.saveEditedCell(); // Check if $cfg['SaveCellsAtOnce'] is false if (!g.saveCellsAtOnce) { // Check if need_to_post is true if (saved) { // Check if this function called from 'move' functions if (options !== undefined && options.move) { g.postEditedCell(options); } else { g.postEditedCell(); } // need_to_post is false } else { // Check if this function called from 'move' functions if (options !== undefined && options.move) { g.hideEditCell(true); g.showEditCell(options.cell); // NOT called from 'move' functions } else { g.hideEditCell(true); } } // $cfg['SaveCellsAtOnce'] is true } else { // If need_to_post if (saved) { // If this function called from 'move' functions if (options !== undefined && options.move) { g.hideEditCell(true, true, false, options); g.showEditCell(options.cell); // NOT called from 'move' functions } else { g.hideEditCell(true, true); } } else { // If this function called from 'move' functions if (options !== undefined && options.move) { g.hideEditCell(true, false, false, options); g.showEditCell(options.cell); // NOT called from 'move' functions } else { g.hideEditCell(true); } } } }, /** * Initialize column resize feature. */ initColResize: function () { // create column resizer div g.cRsz = document.createElement('div'); g.cRsz.className = 'cRsz'; // get data columns in the first row of the table var $firstRowCols = $(g.t).find('tr:first th.draggable'); // create column borders $firstRowCols.each(function () { var cb = document.createElement('div'); // column border $(cb).addClass('colborder') .mousedown(function (e) { g.dragStartRsz(e, this); }); $(g.cRsz).append(cb); }); g.reposRsz(); // attach to global div $(g.gDiv).prepend(g.cRsz); }, /** * Initialize column reordering feature. */ initColReorder: function () { g.cCpy = document.createElement('div'); // column copy, to store copy of dragged column header g.cPointer = document.createElement('div'); // column pointer, used when reordering column // adjust g.cCpy g.cCpy.className = 'cCpy'; $(g.cCpy).hide(); // adjust g.cPointer g.cPointer.className = 'cPointer'; $(g.cPointer).css('visibility', 'hidden'); // set visibility to hidden instead of calling hide() to force browsers to cache the image in cPointer class // assign column reordering hint g.reorderHint = PMA_messages.strColOrderHint; // get data columns in the first row of the table var $firstRowCols = $(g.t).find('tr:first th.draggable'); // initialize column order $col_order = $(g.o).find('.col_order'); // check if column order is passed from PHP if ($col_order.length > 0) { g.colOrder = $col_order.val().split(','); for (var i = 0; i < g.colOrder.length; i++) { g.colOrder[i] = parseInt(g.colOrder[i], 10); } } else { g.colOrder = []; for (var i = 0; i < $firstRowCols.length; i++) { g.colOrder.push(i); } } // register events $(g.t).find('th.draggable') .mousedown(function (e) { $(g.o).addClass('turnOffSelect'); if (g.visibleHeadersCount > 1) { g.dragStartReorder(e, this); } }) .mouseenter(function () { if (g.visibleHeadersCount > 1) { $(this).css('cursor', 'move'); } else { $(this).css('cursor', 'inherit'); } }) .mouseleave(function () { g.showReorderHint = false; $(this).tooltip('option', { content: g.updateHint() }); }) .dblclick(function (e) { e.preventDefault(); $('
') .prop('title', PMA_messages.strColNameCopyTitle) .addClass('modal-copy') .text(PMA_messages.strColNameCopyText) .append( $('') .prop('readonly', true) .val($(this).data('column')) ) .dialog({ resizable: false, modal: true }) .find('input').focus().select(); }); $(g.t).find('th.draggable a') .dblclick(function (e) { e.stopPropagation(); }); // restore column order when the restore button is clicked $(g.o).find('div.restore_column').click(function () { g.restoreColOrder(); }); // attach to global div $(g.gDiv).append(g.cPointer); $(g.gDiv).append(g.cCpy); // prevent default "dragstart" event when dragging a link $(g.t).find('th a').on('dragstart', function () { return false; }); // refresh the restore column button state g.refreshRestoreButton(); }, /** * Initialize column visibility feature. */ initColVisib: function () { g.cDrop = document.createElement('div'); // column drop-down arrows g.cList = document.createElement('div'); // column visibility list // adjust g.cDrop g.cDrop.className = 'cDrop'; // adjust g.cList g.cList.className = 'cList'; $(g.cList).hide(); // assign column visibility related hints g.showAllColText = PMA_messages.strShowAllCol; // get data columns in the first row of the table var $firstRowCols = $(g.t).find('tr:first th.draggable'); var i; // initialize column visibility var $col_visib = $(g.o).find('.col_visib'); // check if column visibility is passed from PHP if ($col_visib.length > 0) { g.colVisib = $col_visib.val().split(','); for (i = 0; i < g.colVisib.length; i++) { g.colVisib[i] = parseInt(g.colVisib[i], 10); } } else { g.colVisib = []; for (i = 0; i < $firstRowCols.length; i++) { g.colVisib.push(1); } } // make sure we have more than one column if ($firstRowCols.length > 1) { var $colVisibTh = $(g.t).find('th:not(.draggable)'); PMA_tooltip( $colVisibTh, 'th', PMA_messages.strColVisibHint ); // create column visibility drop-down arrow(s) $colVisibTh.each(function () { var $th = $(this); var cd = document.createElement('div'); // column drop-down arrow var pos = $th.position(); $(cd).addClass('coldrop') .click(function () { if (g.cList.style.display === 'none') { g.showColList(this); } else { g.hideColList(); } }); $(g.cDrop).append(cd); }); // add column visibility control g.cList.innerHTML = '
'; var $listDiv = $(g.cList).find('div'); var tempClick = function () { if (g.toggleCol($(this).index())) { g.afterToggleCol(); } }; for (i = 0; i < $firstRowCols.length; i++) { var currHeader = $firstRowCols[i]; var listElmt = document.createElement('div'); $(listElmt).text($(currHeader).text()) .prepend(''); $listDiv.append(listElmt); // add event on click $(listElmt).click(tempClick); } // add "show all column" button var showAll = document.createElement('div'); $(showAll).addClass('showAllColBtn') .text(g.showAllColText); $(g.cList).append(showAll); $(showAll).click(function () { g.showAllColumns(); }); // prepend "show all column" button at top if the list is too long if ($firstRowCols.length > 10) { var clone = showAll.cloneNode(true); $(g.cList).prepend(clone); $(clone).click(function () { g.showAllColumns(); }); } } // hide column visibility list if we move outside the list $(g.t).find('td, th.draggable').mouseenter(function () { g.hideColList(); }); // attach to global div $(g.gDiv).append(g.cDrop); $(g.gDiv).append(g.cList); // some adjustment g.reposDrop(); }, /** * Move currently Editing Cell to Up */ moveUp: function (e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } var found = false; var $found_row; var $prev_row; var j = 0; $this_field.parents('tr').first().parents('tbody').children().each(function () { if ($(this).find('.where_clause').val() === where_clause) { found = true; $found_row = $(this); } if (!found) { $prev_row = $(this); } }); var new_cell; if (found && $prev_row) { $prev_row.children('td').each(function () { if (getFieldName($(g.t), $(this)) === field_name) { new_cell = this; } }); } if (new_cell) { g.hideEditCell(false, false, false, { move : true, cell : new_cell }); } }, /** * Move currently Editing Cell to Down */ moveDown: function (e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } var found = false; var $found_row; var $next_row; var j = 0; var next_row_found = false; $this_field.parents('tr').first().parents('tbody').children().each(function () { if ($(this).find('.where_clause').val() === where_clause) { found = true; $found_row = $(this); } if (found) { if (j >= 1 && ! next_row_found) { $next_row = $(this); next_row_found = true; } else { j++; } } }); var new_cell; if (found && $next_row) { $next_row.children('td').each(function () { if (getFieldName($(g.t), $(this)) === field_name) { new_cell = this; } }); } if (new_cell) { g.hideEditCell(false, false, false, { move : true, cell : new_cell }); } }, /** * Move currently Editing Cell to Left */ moveLeft: function (e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } var found = false; var $found_row; var j = 0; $this_field.parents('tr').first().parents('tbody').children().each(function () { if ($(this).find('.where_clause').val() === where_clause) { found = true; $found_row = $(this); } }); var left_cell; var cell_found = false; if (found) { $found_row.children('td.grid_edit').each(function () { if (getFieldName($(g.t), $(this)) === field_name) { cell_found = true; } if (!cell_found) { left_cell = this; } }); } if (left_cell) { g.hideEditCell(false, false, false, { move : true, cell : left_cell }); } }, /** * Move currently Editing Cell to Right */ moveRight: function (e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } var found = false; var $found_row; var j = 0; $this_field.parents('tr').first().parents('tbody').children().each(function () { if ($(this).find('.where_clause').val() === where_clause) { found = true; $found_row = $(this); } }); var right_cell; var cell_found = false; var next_cell_found = false; if (found) { $found_row.children('td.grid_edit').each(function () { if (getFieldName($(g.t), $(this)) === field_name) { cell_found = true; } if (cell_found) { if (j >= 1 && ! next_cell_found) { right_cell = this; next_cell_found = true; } else { j++; } } }); } if (right_cell) { g.hideEditCell(false, false, false, { move : true, cell : right_cell }); } }, /** * Initialize grid editing feature. */ initGridEdit: function () { function startGridEditing (e, cell) { if (g.isCellEditActive) { g.saveOrPostEditedCell(); } else { g.showEditCell(cell); } e.stopPropagation(); } function handleCtrlNavigation (e) { if ((e.ctrlKey && e.which === 38) || (e.altKey && e.which === 38)) { g.moveUp(e); } else if ((e.ctrlKey && e.which === 40) || (e.altKey && e.which === 40)) { g.moveDown(e); } else if ((e.ctrlKey && e.which === 37) || (e.altKey && e.which === 37)) { g.moveLeft(e); } else if ((e.ctrlKey && e.which === 39) || (e.altKey && e.which === 39)) { g.moveRight(e); } } // create cell edit wrapper element g.cEditStd = document.createElement('div'); g.cEdit = g.cEditStd; g.cEditTextarea = document.createElement('div'); // adjust g.cEditStd g.cEditStd.className = 'cEdit'; $(g.cEditStd).html('
'); $(g.cEditStd).hide(); // adjust g.cEdit g.cEditTextarea.className = 'cEdit'; $(g.cEditTextarea).html('
'); $(g.cEditTextarea).hide(); // assign cell editing hint g.cellEditHint = PMA_messages.strCellEditHint; g.saveCellWarning = PMA_messages.strSaveCellWarning; g.alertNonUnique = PMA_messages.strAlertNonUnique; g.gotoLinkText = PMA_messages.strGoToLink; // initialize cell editing configuration g.saveCellsAtOnce = $(g.o).find('.save_cells_at_once').val(); g.maxTruncatedLen = PMA_commonParams.get('LimitChars'); // register events $(g.t).find('td.data.click1') .click(function (e) { startGridEditing(e, this); // prevent default action when clicking on "link" in a table if ($(e.target).is('.grid_edit a')) { e.preventDefault(); } }); $(g.t).find('td.data.click2') .click(function (e) { var $cell = $(this); // In the case of relational link, We want single click on the link // to goto the link and double click to start grid-editing. var $link = $(e.target); if ($link.is('.grid_edit.relation a')) { e.preventDefault(); // get the click count and increase var clicks = $cell.data('clicks'); clicks = (typeof clicks === 'undefined') ? 1 : clicks + 1; if (clicks === 1) { // if there are no previous clicks, // start the single click timer var timer = setTimeout(function () { // temporarily remove ajax class so the page loader will not handle it, // submit and then add it back $link.removeClass('ajax'); AJAX.requestHandler.call($link[0]); $link.addClass('ajax'); $cell.data('clicks', 0); }, 700); $cell.data('clicks', clicks); $cell.data('timer', timer); } else { // this is a double click, cancel the single click timer // and make the click count 0 clearTimeout($cell.data('timer')); $cell.data('clicks', 0); // start grid-editing startGridEditing(e, this); } } }) .dblclick(function (e) { if ($(e.target).is('.grid_edit a')) { e.preventDefault(); } else { startGridEditing(e, this); } }); $(g.cEditStd).on('keydown', 'input.edit_box, select', handleCtrlNavigation); $(g.cEditStd).find('.edit_box').focus(function () { g.showEditArea(); }); $(g.cEditStd).on('keydown', '.edit_box, select', function (e) { if (e.which === 13) { // post on pressing "Enter" e.preventDefault(); g.saveOrPostEditedCell(); } }); $(g.cEditStd).keydown(function (e) { if (!g.isEditCellTextEditable) { // prevent text editing e.preventDefault(); } }); $(g.cEditTextarea).on('keydown', 'textarea.edit_box, select', handleCtrlNavigation); $(g.cEditTextarea).find('.edit_box').focus(function () { g.showEditArea(); }); $(g.cEditTextarea).on('keydown', '.edit_box, select', function (e) { if (e.which === 13 && !e.shiftKey) { // post on pressing "Enter" e.preventDefault(); g.saveOrPostEditedCell(); } }); $(g.cEditTextarea).keydown(function (e) { if (!g.isEditCellTextEditable) { // prevent text editing e.preventDefault(); } }); $('html').click(function (e) { // hide edit cell if the click is not fromDat edit area if ($(e.target).parents().index($(g.cEdit)) === -1 && !$(e.target).parents('.ui-datepicker-header').length && !$('.browse_foreign_modal.ui-dialog:visible').length && !$(e.target).closest('.dismissable').length ) { g.hideEditCell(); } }).keydown(function (e) { if (e.which === 27 && g.isCellEditActive) { // cancel on pressing "Esc" g.hideEditCell(true); } }); $(g.o).find('div.save_edited').click(function () { g.hideEditCell(); g.postEditedCell(); }); $(window).on('beforeunload', function () { if (g.isCellEdited) { return g.saveCellWarning; } }); // attach to global div $(g.gDiv).append(g.cEditStd); $(g.gDiv).append(g.cEditTextarea); // add hint for grid editing feature when hovering "Edit" link in each table row if (PMA_messages.strGridEditFeatureHint !== undefined) { PMA_tooltip( $(g.t).find('.edit_row_anchor a'), 'a', PMA_messages.strGridEditFeatureHint ); } } }; /** **************** * Initialize grid ******************/ // wrap all truncated data cells with span indicating the original length // todo update the original length after a grid edit $(t).find('td.data.truncated:not(:has(span))') .wrapInner(function () { return ''; }); // wrap remaining cells, except actions cell, with span $(t).find('th, td:not(:has(span))') .wrapInner(''); // create grid elements g.gDiv = document.createElement('div'); // create global div // initialize the table variable g.t = t; // enclosing .sqlqueryresults div g.o = $(t).parents('.sqlqueryresults'); // get data columns in the first row of the table var $firstRowCols = $(t).find('tr:first th.draggable'); // initialize visible headers count g.visibleHeadersCount = $firstRowCols.filter(':visible').length; // assign first column (actions) span if (! $(t).find('tr:first th:first').hasClass('draggable')) { // action header exist g.actionSpan = $(t).find('tr:first th:first').prop('colspan'); } else { g.actionSpan = 0; } // assign table create time // table_create_time will only available if we are in "Browse" tab g.tableCreateTime = $(g.o).find('.table_create_time').val(); // assign the hints g.sortHint = PMA_messages.strSortHint; g.strMultiSortHint = PMA_messages.strMultiSortHint; g.markHint = PMA_messages.strColMarkHint; g.copyHint = PMA_messages.strColNameCopyHint; // assign common hidden inputs var $common_hidden_inputs = $(g.o).find('div.common_hidden_inputs'); g.server = $common_hidden_inputs.find('input[name=server]').val(); g.db = $common_hidden_inputs.find('input[name=db]').val(); g.table = $common_hidden_inputs.find('input[name=table]').val(); // add table class $(t).addClass('pma_table'); // add relative position to global div so that resize handlers are correctly positioned $(g.gDiv).css('position', 'relative'); // link the global div $(t).before(g.gDiv); $(g.gDiv).append(t); // FEATURES enableResize = enableResize === undefined ? true : enableResize; enableReorder = enableReorder === undefined ? true : enableReorder; enableVisib = enableVisib === undefined ? true : enableVisib; enableGridEdit = enableGridEdit === undefined ? true : enableGridEdit; if (enableResize) { g.initColResize(); } // disable reordering for result from EXPLAIN or SHOW syntax, which do not have a table navigation panel if (enableReorder && $(g.o).find('table.navigation').length > 0) { g.initColReorder(); } if (enableVisib) { g.initColVisib(); } // make sure we have the ajax class if (enableGridEdit && $(t).is('.ajax')) { g.initGridEdit(); } // create tooltip for each with draggable class PMA_tooltip( $(t).find('th.draggable'), 'th', g.updateHint() ); // register events for hint tooltip (anchors inside draggable th) $(t).find('th.draggable a') .mouseenter(function () { g.showSortHint = true; g.showMultiSortHint = true; $(t).find('th.draggable').tooltip('option', { content: g.updateHint() }); }) .mouseleave(function () { g.showSortHint = false; g.showMultiSortHint = false; $(t).find('th.draggable').tooltip('option', { content: g.updateHint() }); }); // register events for dragging-related feature if (enableResize || enableReorder) { $(document).mousemove(function (e) { g.dragMove(e); }); $(document).mouseup(function (e) { $(g.o).removeClass('turnOffSelect'); g.dragEnd(e); }); } // some adjustment $(t).removeClass('data'); $(g.gDiv).addClass('data'); } /** * jQuery plugin to cancel selection in HTML code. */ (function ($) { $.fn.noSelect = function (p) { // no select plugin by Paulo P.Marinas var prevent = (p === null) ? true : p; var is_msie = navigator.userAgent.indexOf('MSIE') > -1 || !!window.navigator.userAgent.match(/Trident.*rv\:11\./); var is_firefox = navigator.userAgent.indexOf('Firefox') > -1; var is_safari = navigator.userAgent.indexOf('Safari') > -1; var is_opera = navigator.userAgent.indexOf('Presto') > -1; if (prevent) { return this.each(function () { if (is_msie || is_safari) { $(this).on('selectstart', false); } else if (is_firefox) { $(this).css('MozUserSelect', 'none'); $('body').trigger('focus'); } else if (is_opera) { $(this).on('mousedown', false); } else { $(this).attr('unselectable', 'on'); } }); } else { return this.each(function () { if (is_msie || is_safari) { $(this).off('selectstart'); } else if (is_firefox) { $(this).css('MozUserSelect', 'inherit'); } else if (is_opera) { $(this).off('mousedown'); } else { $(this).removeAttr('unselectable'); } }); } }; // end noSelect }(jQuery));