PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/backups/cpanel_plugin
Viewing File: /opt/backups/cpanel_plugin/file_browse.js
// code: language=javascript insertSpaces=True tabSize=4 /* Internet Explorer 11 lacks String.startsWith() */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { position = position || 0; return this.substr(position, searchString.length) === searchString; }; } /* Internet Explorer 8 lacks Array.indexOf */ if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(what, i) { i = i || 0; var L = this.length; while (i < L) { if (this[i] === what) return i; ++i; } return -1; }; } /* Add [].remove */ Array.prototype.remove = function() { var what, a = arguments, L = a.length, ax; while (L && this.length) { what = a[--L]; while ((ax = this.indexOf(what)) !== -1) { this.splice(ax, 1); } } return this; }; function bySortedValue(obj, callback, context) { // get a list of keys, sorted by their value, descending var keys = []; for (var key in obj) keys.push(key); keys.sort(function(a, b) { return obj[b] - obj[a] }); for (var i = 0; i < keys.length; i++) { callback.call(context, keys[i], obj[keys[i]]); } } /* get all checked items in a file browser by its ID */ function get_browser_selected(id) { var unshown_selections = $j(id).data('unshown-selections'); var hex_slash = ($j(id).data('post-action') == 'listdir'); var shown = []; var selected = []; // get the list of selected folders $j.each($j(id.concat(' :input')), function(i, input) { var input = $j(input); shown.push(input.val()); if (input.is(':checked')) { selected.push(input.val()); } }); // remove any items from unshown_selections which the browser has loaded, // then add the remaining to selected $j.each(unshown_selections, function(i, unshown_item) { if (shown.indexOf(unshown_item) != -1) { unshown_selections.remove(unshown_item); } }); $j.each(unshown_selections, function(i, unshown_item) { selected.push(unshown_item); }); // iterate over them again to set .prop('indeterminate', true) as needed $j.each($j(id.concat(' :input')), function(i, input) { var input = $j(input); if (input.is(':checked')) { input.prop('indeterminate', false); } else { // if this item is unchecked var indeterminate = false; var unchecked_path = input.val(); $j.each(selected, function(sel_i, selected_item) { // if selected_item is a child of unchecked_path, it should be set to indeterminate // example: unchecked_path="/root" and selected_item="/root/something/something" if (is_parent_path(unchecked_path, selected_item, hex_slash)) { indeterminate = true; } }); input.prop('indeterminate', indeterminate); } }); return selected; } /* check if all items were selected */ function all_selected(id) { var inputs = $j(id.concat(' :input')); for (let i = 0; i < inputs.length; i++) { if (! $j(inputs[i]).is(':checked')){ return false; } } return true; } function is_parent_path(parent, child, hex_slash) { // ensure one and only one trailing slash if (hex_slash) { // '2f' = utf-8 of '/' in hex var child = child.replace(/(?:2f)+$/, "").concat('2f'); var parent = parent.replace(/(?:2f)+$/, "").concat('2f'); } else { var child = child.replace(/[\/]+$/, "").concat('/'); var parent = parent.replace(/[\/]+$/, "").concat('/'); } if (child == parent) { return false; } return child.startsWith(parent); } /* called when document is ready, this is called */ function init_file_browse(browser_id, snap, geo) { // this tracks which folders are currently trying to fetch contents // to prevent unnecssary API calls var browser_div = $j(browser_id); browser_div.data('processing', []); var post_uri = browser_div.data('post-uri'); var action = browser_div.data('post-action'); if (action == 'listdir') { // loading items from local disk init_from_local_listdir(browser_div); } else { // loading items from restic init_from_restic_browse(action, post_uri, browser_div, snap, geo); } } function hex2str(hex) { var pairs = hex.match(/(..?)/g); var arr = []; $j.each(pairs, function(i, pair) { arr.push(parseInt(pair, 16)); }); return new TextDecoder().decode(new Uint8Array(arr)); }; function init_from_local_listdir(browser_div) { var all_sizes = $j('#settings_tab').data('subpaths') var browser_id = browser_div.attr('id'); var selections = browser_div.data('orig-selections'); browser_div.empty(); // create the main ul where file/folders are displayed var ul = $j('<ul>', { style: 'list-style-type: none;' }); bySortedValue($j('#settings_tab').data('home-items').dirs, function(dir, size_mb) { // for each directory var checked = selections.indexOf(dir) != -1; if (checked) selections.remove(dir); all_sizes[dir] = size_mb; ul.append(create_browser_li({ browser_id: browser_id, folder: true, path: dir, toplevel: true, size: size_mb, checked: checked })); }); bySortedValue($j('#settings_tab').data('home-items').files, function(path, size_mb) { // for each file var checked = selections.indexOf(path) != -1; if (checked) selections.remove(path); all_sizes[path] = size_mb; ul.append(create_browser_li({ browser_id: browser_id, folder: false, path: path, toplevel: true, size: size_mb, checked: checked })); }); browser_div.append(ul); // Any selections previously made which haven't been expanded yet browser_div.data('unshown-selections', selections); browser_div.data('all-sizes', all_sizes); } function init_from_restic_browse(action, post_uri, browser_div, snap, geo) { var browser_id = browser_div.attr('id'); browser_div.data('unshown-selections', []); // not relevant to restic's browser; just set it empty browser_div.empty(); if (snap == undefined) { console.log('There appears to be no file backups to browse; not initializing the browser widget'); return; } var temp_p = $j('<p>', { text: 'Loading ', class: 'browser-msg' }); temp_p.append($j('<img>', { src: window.filebrowse_img_root.concat('/spinner.gif') })); browser_div.append(temp_p); var home = browser_div.data('home-path'); var post_args = JSON.stringify({ path: home, snap: snap, geo: geo }); $j.ajax({ url: post_uri, type: 'POST', timeout: 120 * 1000, data: { action: action, args: post_args } }) .done(function(data) { try { data = JSON.parse(data); console.log(data); } catch (err) { browser_div.append($j('<p>', { text: 'Invalid JSON from server', class: 'browser-msg text-danger' })); console.log('could not decode server response as JSON: '.concat(data)); return; } browser_div.empty(); if (data.status != 0) { // successfully contacted server, but ran into an error browser_div.append($j('<p>', { text: data.data })); console.log(data); return; } // create the main ul where file/folders are displayed var ul = $j('<ul>', { style: 'list-style-type: none;' }); $j.each(data.data.dirs, function(dir_index, dir) { // for each directory if (home == '/') { var path = home.concat(dir); } else { var path = home.concat('/').concat(dir); } ul.append(create_browser_li({ folder: true, browser_id: browser_id, snap: snap, geo: geo, path: path, toplevel: true })); }); $j.each(data.data.files, function(file_index, file) { // for each file if (home == '/') { var path = home.concat(file); } else { var path = home.concat('/').concat(file); } ul.append(create_browser_li({ folder: false, browser_id: browser_id, path: path, toplevel: true })); }); browser_div.append(ul); }) .fail(function (xhr, statusText, errorThrown) { // could not contact server console.log(xhr); console.log(errorThrown); temp_p.text('Server error - '.concat(statusText)); }); } function update_sel_count() { $j('.filebrowser-count').each(function(index, span) { var span = $j(span); var browser_name = span.data('browser'); var num_items = get_browser_selected(browser_name).length; span.text(num_items); if (num_items > 0) { span.parent().removeClass('count-zero'); } else { span.parent().addClass('count-zero'); } var has_items_func = window[span.data('has-items-func')]; has_items_func(num_items > 0); }); } /* create a <li> for the browser. params: folder: whether this is a folder which can be expanded browser_id: id for the browser div (only if folder=true) snap: optional snapshot ID to set in data for the li path: file/folder path checked: whether to set prop checked (default: false) toplevel: whether to include the browser-toplevel class (default: false) size: size to display for the item (optional) */ function create_browser_li(opts) { var post_action = $j('#'.concat(opts.browser_id)).data('post-action'); if (post_action == 'listdir') { var path = hex2str(opts.path); } else { var path = opts.path; } if (opts.size === undefined) { var label = path; } else if (opts.size === null) { var label = path; } else { var label = path.concat(' (').concat((opts.size / 1024).toFixed(2)).concat('GB)'); } var li_args = {}; if (opts.toplevel) li_args['class'] = 'browser-toplevel'; if (opts.folder) { li_args['style'] = 'list-style-image: url("'.concat(window.filebrowse_img_root).concat('/directory.png")'); li_args['onclick'] = 'browse_expand(event, this);'; } else { li_args['style'] = 'list-style-image: url("'.concat(icon_for(path)).concat('")'); } var check_label = $j('<label>', { text: label }); var check_input = $j('<input>', { type: 'checkbox', value: opts.path, onclick: 'update_checked(this)' }); if (opts.checked) check_input.prop('checked', true); if (!(opts.size === undefined)) { if (opts.size === null) { check_input.data('size', '?'); } else { check_input.data('size', opts.size); } } var li = $j('<li>', li_args); li.data('path', opts.path); li.data('browser_id', opts.browser_id); if (!(opts.snap === undefined)) { li.data('snap', opts.snap); li.data('geo', opts.geo); } var check_div = $j('<div>', { class: 'checkbox' }); check_label.append(check_input); check_div.append(check_label); li.append(check_div); return li; } /* triggers when a checkbox is clicked */ function update_checked(checkbox) { checkbox = $j(checkbox); var file_browse = checkbox.closest('.file_browse'); var path = checkbox.val(); var checked = checkbox.is(':checked'); // when a checkbox is manually checked: // - check all items underneath it // when a checkbox is manually unchecked // - uncheck all items underneath it // - uncheck all items above it. update_sel_count() will then set them as indeterminate if (file_browse.data('post-action') == 'listdir') { var slash = '2f'; // utf-8 of '/' in hex } else { var slash = '/'; } file_browse.find(' :input').each(function(i, check) { var check = $j(check); if (check.val() != path && check.val().startsWith(path.concat(slash))) { check.prop('checked', checked); } if (!checked && check.val() != path && path.startsWith(check.val().concat(slash))) { check.prop('checked', false); } }); update_sel_count(); } /* show an alert div for errors */ function show_browser_error(alert_div, msg, full_error) { console.log(full_error); alert_div.find('span').text(msg); alert_div.removeClass('hidden'); alert_div.show(); } /* expands a folder when clicked for the first time */ function browse_expand(event, li_item) { if (event.target.tagName == 'LABEL') { return; // it triggers twice if the label part of the checkbox is clicked } if (event.target.tagName == 'INPUT') { // the checkbox triggered this, not the li update_checked($j(event.target)); return; } li_item = $j(li_item); var path = li_item.data('path'); var snap = li_item.data('snap'); var geo = li_item.data('geo'); var browser_id = li_item.data('browser_id'); if (li_item.data('open') == 'y') { // already populated the items if (li_item.data('expanded') == 'y') { // expanded - hide the items beneath it expand_item(li_item, false); } else { // items hidden - show them again expand_item(li_item, true); } return; } var browser_div = $j('#'.concat(browser_id)); var processing = browser_div.data('processing'); if (processing.indexOf(path) != -1) { console.log(browser_id.concat(' is already processing a request for ').concat(path)); return; } else { processing.push(path); browser_div.data('processing', processing); } li_item.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/spinner.gif")')); var browser_div = $j('#'.concat(browser_id)); var action = browser_div.data('post-action'); if (action == 'listdir') { var post_args = JSON.stringify({ path: path }); } else { var post_args = JSON.stringify({ path: path, snap: snap, geo: geo }); } var post_uri = browser_div.data('post-uri'); $j.ajax({ url: post_uri, type: 'POST', timeout: 120 * 1000, data: { action: action, args: post_args } }) .done(function(data) { try { data = JSON.parse(data); } catch (err) { show_browser_error( $j(li_item.closest('.file_browse').data('errors')), 'Error browsing '.concat(path).concat(': error - invalid JSON from server'), data ); return; } if (data.status != 0) { // successfully contacted server, but ran into an error show_browser_error( $j(li_item.closest('.file_browse').data('errors')), 'Error browsing '.concat(path).concat(': ').concat(data.error), data ); return; } // update data-all-sizes on the browser div if (action == 'listdir') { var all_sizes = browser_div.data('all-sizes'); $j.each(data.data.dirs, function(path, size) { all_sizes[path] = size; }); $j.each(data.data.files, function(path, size) { all_sizes[path] = size; }) browser_div.data('all-sizes', all_sizes); } var next_li = $j('<li>'); var ul = $j('<ul>', { style: 'list-style-type: none;' }); var empty = true; var check_new_items = li_item.find(' :input').is(':checked'); var unshown_selections = browser_div.data('unshown-selections'); $j.each(data.data.dirs, function(key, val) { // for each directory if (action == 'listdir') { // local listdir returns a dict of {dir:size} var dir = key; var size = val; var this_path = dir; } else { // restic browse returns a list of dirs var dir = val; var size = undefined; var this_path = path.concat('/').concat(dir); } empty = false; var check = check_new_items; if (unshown_selections.indexOf(this_path) != -1) { var check = true; } ul.append(create_browser_li({ folder: true, browser_id: browser_id, snap: snap, geo: geo, path: this_path, size: size, checked: check })); }); $j.each(data.data.files, function(key, val) { // for each file if (action == 'listdir') { // local listdir returns a dict of {file:size} var file = key; var size = val; var this_path = file; } else { // restic browse returns a list of files var file = val; var size = undefined; var this_path = path.concat('/').concat(file); } empty = false; var check = check_new_items; if (unshown_selections.indexOf(this_path) != -1) { var check = true; } ul.append(create_browser_li({ folder: false, browser_id: browser_id, path: this_path, size: size, checked: check })); }); if (li_item.data('open') != 'y') { li_item.data('open', 'y'); li_item.data('expanded', 'y'); next_li.append(ul) li_item.after(next_li); li_item.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/folder_open.png")')); var dir_label = li_item.first('checkbox'); if (empty) { dir_label.text(dir_label.text().concat(' (empty)')); } } }) .fail(function(data) { // could not contact server show_browser_error( $j(li_item.closest('.file_browse').data('errors')), 'Error browsing '.concat(path).concat(': ').concat(data.statusText), data ); li_item.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/directory.png")')); }) .always(function() { var processing = browser_div.data('processing'); processing.remove(path); browser_div.data('processing', processing); }); } /* expand (or hide) an already opened folder */ function expand_item(li_elem, expand) { var inner_li = li_elem.next('li'); if (expand) { // items hidden - show them again inner_li.show(); li_elem.data('expanded', 'y'); li_elem.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/folder_open.png")')); } else { // expanded - hide the items beneath it inner_li.hide(); li_elem.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/directory.png")')); li_elem.data('expanded', 'n'); } } /* when the select all or deselect all button is clicked */ function filebrowser_selectall(browser_id, checked) { var browser_div = $j(browser_id); browser_div.find('li').each(function(li_index, li) { li = $j(li); if (checked) { // selecting all if (li.hasClass('browser-toplevel')) { $j(li.find('input')).prop('checked', true); update_checked($j(li.find('input'))); } if (li.data('expanded') == 'y') { expand_item(li, false); } } else { // deselecting all $j(li.find('input')).prop('checked', false); update_checked($j(li.find('input'))); } }); update_sel_count(); } /* get the icon that should be displayed for a file. * directories are different and should be directory.png or folder_open.png */ function icon_for(filename) { var ext = filename.substr(filename.lastIndexOf('.') + 1); // unused: file-lock.png, directory-lock.png var file_browse_extensions = { 'rtf': 'txt', 'gz': 'zip', 'jpeg': 'picture', '4fb': 'flash', 'mp4': 'picture', 'mp2': 'film', 'mp3': 'music', 'm4p': 'film', 'jar': 'java', 'wmv': 'film', 'wml': 'html', 'm4b': 'music', 'wma': 'music', 'm4a': 'music', 'bin': 'application', 'mpg': 'film', 'mpe': 'film', 'cpio': 'zip', 'psd': 'psd', 'mpv': 'film', 'tif': 'picture', 'f4p': 'flash', 'bat': 'script', 'gifv': 'film', 'f4v': 'flash', 'f4a': 'flash', 'pbm': 'picture', 'htm': 'html', 'webm': 'film', 'webp': 'picture', 'mpeg': 'film', 'm2v': 'film', 'rb': 'ruby', 'cgi': 'script', 'js': 'script', 'plx': 'script', 'bz': 'zip', 'c': 'code', 's7z': 'zip', 'iso': 'zip', 'pdf': 'pdf', 'tiff': 'picture', 'pgm': 'picture', 'ppm': 'picture', 'xz': 'zip', 'txt': 'txt', 'doc': 'doc', 'pp': 'code', 'vob': 'film', 'zip': 'zip', 'py': 'script', 'swf': 'flash', 'gif': 'picture', 'wav': 'music', 'pl': 'script', 'phtml': 'html', 'ogv': 'film', 'pnm': 'picture', 'flac': 'music', 'ogg': 'film', 'oga': 'music', 'png': 'picture', 'aac': 'music', 'flv': 'flash', 'erb': 'ruby', 'cab': 'zip', 'z': 'zip', 'tar': 'zip', '3g2': 'film', 'jpg': 'picture', 'ar': 'zip', 'rar': 'zip', 'avi': 'film', 'vox': 'music', '7z': 'zip', 'shtml': 'html', 'bz2': 'zip', 'html': 'html', 'php4': 'php', 'php5': 'php', 'xls': 'xls', 'xhtml': 'html', 'php7': 'php', 'css': 'css', 'php3': 'php', '3gp': 'music', 'ppt': 'ppt', 'mov': 'film', 'perl': 'script', 'jsp': 'code', 'sql': 'db', 'php': 'php', 'm4v': 'film', 'a': 'zip', 'svg': 'picture', 'sh': 'script', 'so': 'linux', 'cpp': 'code' }; if (ext in file_browse_extensions) { return window.filebrowse_img_root.concat('/').concat(file_browse_extensions[ext]).concat('.png'); } return window.filebrowse_img_root.concat('/file.png'); }