PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/home/xaviersmandi.in/www/wp-content/plugins/nextgen-gallery/static/AttachToPost/
Upload File :
Current File : /home/xaviersmandi.in/www/wp-content/plugins/nextgen-gallery/static/AttachToPost/display_tab.js
jQuery(function($){

    /*****************************************************************************
     ** NGG DEFINITION
     ***/

    /**
     Setup a namespace for NextGEN-offered Backbone components
     **/
    var Ngg = {
        Models: {},
        Views: {}
    };

    /*****************************************************************************
     ** NGG MODELS
     ***/

    /**
     * Ngg.Models.SelectableItems
     * A collection of items that can be selectable. Commonly used with the
     * Ngg.Views.SelectTag widget (view)
     **/
    Ngg.Models.SelectableItems = Backbone.Collection.extend({
        selected: function(){
            return this.filter(function(item){
                return item.get('selected') == true;
            });
        },

        deselect_all: function(){
            this.each(function(item){
                item.set('selected', false);
            });
        },

        selected_ids: function(){
            return _.pluck(this.selected(), 'id');
        },

        select: function(ids){
            if (!_.isArray(ids)) ids = [ids];
            this.each(function(item){
                if (_.indexOf(ids, item.id) >= 0) {
                    item.set('selected', true);
                }
            });
            this.trigger('selected');
        }
    });


    /*****************************************************************************
     ** NGG VIEWS
     ***/

    /**
     * Ngg.Views.SelectTag
     * Used to render a Select tag (drop-down list)
     **/
    Ngg.Views.SelectTag                    = Backbone.View.extend({
        tagName: 'select',

        collection: null,

        multiple: false,

        value_field: 'id',

        text_field: 'title',

        initialize: function(options) {
            this.options = options || {};
            _.each(this.options, function(value, key){
                this[key] = value;
            }, this);
            this.collection.on('add', this.render_new_option, this);
            this.collection.on('remove', this.remove_existing_option, this);
            this.collection.on('reset', this.empty_list, this);
        },

        events: {
            'change': 'selection_changed'
        },

        empty_list: function(){
            this.$el.empty();
        },

        render_new_option: function(item){
            this.$el.append(new this.Option({
                model: item,
                value_field: this.value_field,
                text_field: this.text_field
            }).render().el);
        },

        remove_existing_option: function(item){
            this.$el.find("option[value='"+item.id+"']").remove();
        },

        /**
         * After a selection has changed, set the 'selected' property for each item in the
         * collection
         * @triggers 'selected'
         **/
        selection_changed: function(){
            // Get selected options from DOM
            var selections = _.map(this.$el.find(':selected'), function(element){
                return $(element).val();
            });

            // Set the 'selected' attribute for each item in the collection
            this.collection.each(function(item){
                if (_.indexOf(selections, item.id) >= 0 || _.indexOf(selections, item.id.toString()) >= 0)
                    item.set('selected', true);
                else
                    item.set('selected', false);
            });
            this.collection.trigger('selected');

            if (this.onSelect) this.onSelect();
        },

        render: function(){
            this.$el.empty();

            if (this.multiple) {
                this.$el.prop('multiple', true);
                this.$el.attr('multiple', 'multiple');
            }

            this.collection.each(function(item){
                var option = new this.Option({
                    model: item,
                    value_field: this.value_field,
                    text_field: this.text_field
                });
                this.$el.append(option.render().el);
            }, this);

            if (this.width) {
                this.$el.width(this.width);
            }

            return this;
        },

        /**
         * Represents an option in the Select drop-down
         **/
        Option: Backbone.View.extend({
            tagName: 'option',

            model: null,

            initialize: function(options) {
                this.options = options || {};
                _.each(this.options, function(value, key){
                    this[key] = value;
                }, this);
                this.model.on('change', this.render, this);
            },

            render: function(){
                var self = this;
                this.$el.html(this.model.get(this.text_field).replace(/\\&/g, '&').replace(/\\'/g, "'"));
                this.$el.prop({
                    value:    this.value_field == 'id' ? this.model.id : this.model.get(this.value_field),
                });
                if (self.model.get('selected') == true) {
                    this.$el.prop('selected', true).attr('selected', 'selected');
                }
                return this;
            }
        })
    });


    Ngg.Views.Chosen								= Backbone.View.extend({
        tagName: 'span',

        initialize: function(options) {
            this.options = options || {};
            this.collection = this.options.collection;
            this.select_tag = new Ngg.Views.SelectTag(this.options);
            this.collection.on('change', this.selection_changed, this);
        },

        selection_changed: function(e){
            if (_.isUndefined(e.changed['selected'])) this.render();
        },

        render: function(){

            this.$el.append(this.select_tag.render().$el);
            if (this.options.width)
                this.select_tag.$el.width(this.options.width);

            // Configure select2 options
            this.select2_opts = {
                placeholder: this.options.placeholder
            };

            // Create the select2 drop-down
            this.select_tag.$el.select2(this.select2_opts);

            return this;
        }
    });

    /*****************************************************************************
     ** DISPLAY TAB DEFINITION
     ***/

    /**
     * Setup a namespace
     **/
    Ngg.DisplayTab = {
        Models: {},
        Views: {},
        App: {}
    };

    /*****************************************************************************
     * MODEL CLASSES
     **/

    /**
     * A collection that can fetch it's entities from the server
     **/
    Ngg.Models.Remote_Collection			= Ngg.Models.SelectableItems.extend({
        fetch_limit: 5000,
        in_progress: false,
        fetch_url:   photocrati_ajax.rest_url,
        action: 	 '',
        extra_data:  {},

        _create_request: function(limit, offset) {
            var request = {
                nonce: igw_data.nonce,
            };
            for (var index in this.extra_data) {
                var value = this.extra_data[index];
                if (typeof(request[index]) === 'undefined') {
                    request[index] = {};
                }
                if (typeof(value['toJSON']) !== 'undefined') {
                    value = value.toJSON();
                }
                request[index] = _.extend(request[index], value);
            }
            return request;
        },

        _add_item: function(item) {
            this.push(item);
        },

        fetch: 	function(limit, offset){
            // Request the entities from the server
            var self = this;
            this.in_progress = true;
            $.ajax({
                method: 'POST',
                url: this.fetch_url + this.action,
                data: this._create_request(limit, offset),
                beforeSend: function(xhr) {
                    xhr.setRequestHeader('X-WP-Nonce', igw_data.nonce);
                }
            }).done(function(response) {
                if (typeof (_) == 'undefined')
                    return;
                if (!_.isObject(response))
                    response = JSON.parse(response);

                if (response.items) {
                    _.each(response.items, function (item) {
                        self._add_item(item);
                    });

                    self.in_progress = false;
                    self.trigger('finished_fetching');
                }
            });
        }
    });


    /**
     * Ngg.DisplayTab.Models.Displayed_Gallery
     * Represents the displayed gallery being edited or created by the Display Tab
     **/
    Ngg.DisplayTab.Models.Displayed_Gallery = Backbone.Model.extend({
        defaults: {
            source: null,
            container_ids: [],
            entity_ids: [],
            display_type: null,
            display_settings: {},
            exclusions: [],
            sortorder: [],
            slug: null
        },

        to_shortcode: function() {
            retval = null;

            var get_shortcode_attr = function(object, key) {
                var val = object[key];

                // Prevent default shortcode attributes from being included
                if (typeof igw_data.shortcode_defaults[key] !== 'undefined'
                &&  igw_data.shortcode_defaults[key] == val) {
                    val = null;
                }

                if (_.isArray(val)) {
                    val = val.length > 0 ? val.join(',') : null;
                }
                if (val) {
                    val = val.toString().replace('[', '&#91;');
                    val = val.toString().replace(']', '&#93;');

                    // Some keys have aliases to be used when writing shortcodes
                    if (typeof igw_data.shortcode_attr_replacements[key] !== 'undefined') {
                        key = igw_data.shortcode_attr_replacements[key];
                    }

                    return key + '="' + val +'"';
                }
            };

            // Convert the displayed gallery to a JSON object
            var display_type = Ngg.DisplayTab.instance.display_types.find_by_name_or_alias(this.get('display_type'));
            var obj = this.toJSON();
            obj.display_type = display_type.get_shortcode_value();


            // Convert the displayed gallery to a shortcode
            var snippet = '[ngg';
            var val = null;

            if ((val = get_shortcode_attr(obj, 'source'))) 			snippet += ' ' + val;
            if ((val = get_shortcode_attr(obj, 'container_ids')))	snippet += ' ' + val;
            if ((val = get_shortcode_attr(obj, 'entity_ids')))		snippet += ' ' + val;
            if ((val = get_shortcode_attr(obj, 'exclusions')))		snippet += ' ' + val;
            if ((val = get_shortcode_attr(obj, 'sortorder')))		snippet += ' ' + val;

            for (var key in obj) {
                var skipped = [
                    'source',
                    'container_ids',
                    'entity_ids',
                    'exclusions',
                    'sortorder',
                    '__defaults_set',
                    'id_field',
                    'post_category',
                    'ID'
                ];

                if (skipped.indexOf(key) > -1) {
                    continue;
                }
                else if (key == 'display_settings') {
                    for (var display_key in obj[key]) {
                        if ((val = get_shortcode_attr(obj[key], display_key))) {
                            snippet += ' ' + val;
                        }
                    }
                }
                else {
                    val = get_shortcode_attr(obj, key);
                    if (val) {
                        snippet += ' ' + val;
                    }
                }
            }

            snippet += ']';

            return snippet;
        }
    });

    /**
     * Ngg.DisplayTab.Models.Source
     * Represents an individual source used to collect displayable entities from
     **/
    Ngg.DisplayTab.Models.Source                = Backbone.Model.extend({
        idAttribute: 'name',
        defaults: {
            title: '',
            name: '',
            selected: false
        }
    });

    /**
     * Ngg.DisplayTab.Models.Source_Collection
     * Used as a collection of all the available sources for entities
     **/
    Ngg.DisplayTab.Models.Source_Collection        = Ngg.Models.SelectableItems.extend({
        model: Ngg.DisplayTab.Models.Source,

        selected_value: function(){
            var retval = null;
            var selected = this.selected();
            if (selected.length > 0) {
                retval = selected[0].get('name');
            }
            return retval;
        },

        find_by_name_or_alias: function(name) {
            return this.find(function(source) {
                return source.get('name') == name || (_.isArray(source.get('aliases')) && source.get('aliases').indexOf(name) > -1);
            });
        }
    });

    /**
     * Ngg.DisplayTab.Models.Gallery
     * Represents an individual gallery entity
     **/
    Ngg.DisplayTab.Models.Gallery                = Backbone.Model.extend({
        idAttribute: igw_data.gallery_primary_key,
        defaults: {
            title:     '',
            name:   ''
        }
    });

    /**
     * Ngg.DisplayTab.Models.Gallery_Collection
     * Collection of gallery objects
     **/
    Ngg.DisplayTab.Models.Gallery_Collection    = Ngg.Models.Remote_Collection.extend({
        model: Ngg.DisplayTab.Models.Gallery,

        action: 'ngg/v1/admin/attach_to_post/galleries'
    });

    /**
     * Ngg.DisplayTab.Models.Album
     * Represents an individual Album object
     **/
    Ngg.DisplayTab.Models.Album                    = Backbone.Model.extend({
        defaults: {
            title: '',
            name:  ''
        }
    });

    /**
     * Ngg.DisplayTab.Models.Album_Collection
     * Used as a collection of album objects
     **/
    Ngg.DisplayTab.Models.Album_Collection        = Ngg.Models.Remote_Collection.extend({
        model: Ngg.DisplayTab.Models.Album,

        action: 'ngg/v1/admin/attach_to_post/albums'
    });

    /**
     * Ngg.DisplayTab.Models.Tag
     * Represents an individual tag object
     **/
    Ngg.DisplayTab.Models.Tag                    = Backbone.Model.extend({
        defaults: {
            title: ''
        }
    });

    /**
     * Ngg.DisplayTab.Models.Tag_Collection
     * Represents a collection of tag objects
     **/
    Ngg.DisplayTab.Models.Tag_Collection        = Ngg.Models.Remote_Collection.extend({
        model: Ngg.DisplayTab.Models.Tag,
        /*
         selected_ids: function(){
         return this.selected().map(function(item){
         return item.get('name');
         });
         },
         */

        action: 'ngg/v1/admin/attach_to_post/tags'
    });

    /**
     * Ngg.DisplayTab.Models.Display_Type
     * Represents an individual display type
     **/
    Ngg.DisplayTab.Models.Display_Type			= Backbone.Model.extend({
        idAttribute: 'name',
        defaults: {
            title: ''
        },

        is_compatible_with_source: function(source){
            var success = true;
            for (index in source.get('returns')) {
                var returned_entity_type = source.get('returns')[index];
                if (_.indexOf(this.get('entity_types'), returned_entity_type) < 0) {
                    success = false;
                    break;
                }
            }
            return success;
        },

        get_shortcode_value: function() {
            var retval = this.id;

            var aliases = this.get('aliases');
            if (_.isArray(aliases) && aliases.length > 0) {
                retval = aliases[0];
            }

            return retval;
        }
    });

    /**
     * Ngg.DisplayTab.Models.Display_Type_Collection
     * Represents a collection of display type objects
     **/
    Ngg.DisplayTab.Models.Display_Type_Collection = Ngg.Models.SelectableItems.extend({
        model: Ngg.DisplayTab.Models.Display_Type,

        selected_value: function(){
            var retval = null;
            var selected = this.selected();
            if (selected.length > 0) {
                return selected[0].get('name');
            }
            return retval;
        },

        find_by_name_or_alias: function(name){
            return this.find(function(display_type){
                return display_type.get('name') == name || (_.isArray(display_type.get('aliases')) && display_type.get('aliases').indexOf(name) > -1);
            });
        }
    });

    /**
     * Ngg.DisplayTab.Models.Entity
     * Represents an entity to display on the front-end
     **/
    Ngg.DisplayTab.Models.Entity				= Backbone.Model.extend({
        entity_id: function(){
            return this.get(this.get('id_field'));
        },

        is_excluded: function() {
            current_value = this.get('exclude');
            if (_.isUndefined(current_value)) return false;
            else if (_.isBoolean(current_value)) return current_value;
            else return parseInt(current_value) == 0 ? false : true;
        },

        is_included: function(){
            return !this.is_excluded();
        },

        is_gallery: function(){
            retval = false;
            if (this.get('is_gallery') == true) retval = true;
            return retval;
        },

        is_album: function(){
            retval = false;
            if (this.get('is_album') == true) retval = true;
            return retval;
        },

        is_image: function(){
            return !this.is_album() && !this.is_gallery();
        },

        alttext: function(){
            if (this.is_image()) {
                return this.get('alttext');
            }
            else if (this.is_gallery()) {
                return this.get('title');
            }
            else if (this.is_album()) {
                return this.get('name');
            }
        }
    });

    /**
     * Ngg.DisplayTab.Models.Entity_Collection
     * Represents a collection of entities
     **/
    Ngg.DisplayTab.Models.Entity_Collection		= Ngg.Models.Remote_Collection.extend({
        model: Ngg.DisplayTab.Models.Entity,

        action: 'ngg/v1/admin/attach_to_post/images',

        _add_item: function(item){
            item.exclude = parseInt(item.exclude) == 1 ? true : false;
            item.is_gallery = parseInt(item.is_gallery) == 1 ? true : false;
            item.is_album = parseInt(item.is_album) == 1 ? true : false;
            this.push(item);
        },

        entity_ids: function(){
            return this.map(function(item){
                return item.entity_id();
            });
        },

        included_ids: function(){
            return _.compact(this.map(function(item){
                if (item.is_included()) return item.entity_id();
            }));
        },

        excluded_ids: function() {
            return _.compact(this.map(function(item) {
                if (!item.is_included()) {
                    return item.entity_id();
                }
            }));
        }
    });


    Ngg.DisplayTab.Models.SortOrder				= Backbone.Model.extend({
    });

    Ngg.DisplayTab.Models.SortOrder_Options		= Ngg.Models.SelectableItems.extend({
        model: Ngg.DisplayTab.Models.SortOrder
    });
    Ngg.DisplayTab.Models.SortDirection			= Backbone.Model.extend({

    });
    Ngg.DisplayTab.Models.SortDirection_Options = Backbone.Collection.extend({
        model: Ngg.DisplayTab.Models.SortDirection
    });

    Ngg.DisplayTab.Models.Slug = Backbone.Model.extend({});

    /*****************************************************************************
     * VIEW CLASSES
     **/

    /**
     * Ngg.DisplayTab.Views.Source_Config
     * Used to populate the source configuration tab
     **/
    Ngg.DisplayTab.Views.Source_Config             = Backbone.View.extend({
        el: '#source_configuration',

        selected_view: null,

        /**
         * Bind to the "sources" collection to know when a selection has been made
         * and determine what sub-view to render
         **/
        initialize: function(){
            this.sources = Ngg.DisplayTab.instance.sources;
            this.sources.on('selected', this.render, this);
            _.bindAll(this, 'render');
            this.render();
        },

        render: function(){
            var chosen = new Ngg.Views.Chosen({
                id: 'source_select',
                collection: this.sources,
                placeholder: 'Select a source',
                width: 500,
                onSelect: function(){
                    $('.main_menu_tab').off('scroll');
                }
            });

            var template = _.template('<tr><td id="source_column"></td><td><label><%- sources %></label></td></tr>');
            this.$el.html(template(igw_data.i18n));
            this.$el.find('#source_column').append(chosen.render().el);

            var selected = this.sources.selected();
            if (selected.length) {
                function capitalizeFirstLetter(text) {
                    text = String(text);
                    return text.charAt(0).toUpperCase() + text.slice(1);
                }
                var view_name = capitalizeFirstLetter(selected.pop().id) + "Source";
                if (typeof(Ngg.DisplayTab.Views[view_name]) != 'undefined') {
                    var selected_view = new Ngg.DisplayTab.Views[view_name];
                    this.$el.append(selected_view.render().el);
                }
            }

            return this;
        }
    });

    Ngg.DisplayTab.Views.Slug_Config = Backbone.View.extend({
        el: '#slug_configuration',

        selected_view: null,

        initialize: function() {
            this.displayed_gallery = Ngg.DisplayTab.instance.displayed_gallery;
            this.slug = Ngg.DisplayTab.instance.displayed_gallery.get('slug');
            this.render();
        },

        render: function() {
            var self = this;

            var input = $('<input>').prop({
                type: 'text',
                name: 'slug',
                value: this.slug,
                placeholder: igw_data.i18n.optional,
                id: 'field_slug'
            });

            input.on('input', function() {
                // Do not allow the following characters in the slug
                $(this).val($(this).val().replace(/\s|\?|\\|\/|&|=|\[|]|#/gm, '-'));
                self.displayed_gallery.set('slug', $(this).val());
            });

            // Trim extraneous leading/following dashes from the above sanitation
            input.on('change', function() {
                $(this).val(
                    $(this).val()
                        .replace(/^-*/gm, '')
                        .replace(/-*$/gm, '')
                );
                self.displayed_gallery.set('slug', $(this).val());
            });

            var template = _.template('<tr><td id="slug_label"><label for="field_slug" class="tooltip" title="<%- slug_tooltip %><"><<%- slug_label %></label></td><td id="slug_column"></td></tr>');
            this.$el.append(template(igw_data.i18n));
            this.$el.find('#slug_column').append(input);

            return this;
        }
    });

    Ngg.DisplayTab.Views.Display_Type_Selector = Backbone.View.extend({
        el: '#display_type_selector',

        initialize: function(){
            this.display_types	= Ngg.DisplayTab.instance.display_types;
            this.display_type_order_base	= Ngg.DisplayTab.instance.display_type_order_base;
            this.display_type_order_step	= Ngg.DisplayTab.instance.display_type_order_step;
            this.sources		= Ngg.DisplayTab.instance.sources;
            this.render();
        },

        selection_changed: function(value){
            var selected_type = null;
            this.display_types.each(function(item){
                if (item.get('name') == value) {
                    selected_type = item;
                    item.set('selected', true);
                }
                else {
                    item.set('selected', false);
                }
            });

            $('.display_settings_form').each(function(){
                $this = $(this);
                if ($this.attr('rel') == value) $this.removeClass('hidden');
                else $this.addClass('hidden');
            });
        },

        render: function(){
            var selected_source = this.sources.selected();
            var current_step = 0;
            selected_source = selected_source.length > 0 ? selected_source[0] : false;
            this.$el.empty();

            var order_base = this.display_type_order_base;
            var order_step = this.display_type_order_step;

            this.display_types.each(function(item){
                if (selected_source && !item.is_compatible_with_source(selected_source)) {

                    // Show all display types if we're viewing the display type
                    // selector tab
                    var display_tab =  $('#display_type_tab_content:visible');
                    if (display_tab.length == 0) return;
                    else if (display_tab.css('visibility') == 'hidden') return;
                }
                var display_type = new Ngg.DisplayTab.Views.DisplayType;
                display_type.model = item;
                display_type.on('selected', this.selection_changed, this);
                if (!this.display_types.selected_value()) {
                    item.set('selected', true);
                    this.selection_changed(item.id);
                }
                var display_order = item.get('view_order');
                if (!display_order)
                    display_order = order_base;
                var display_step = Math.floor(display_order / order_step);
                current_step = display_step;
                this.$el.append(display_type.render().el);
            }, this);
            this.$el.append('<li class="clear" style="height: 10px; list-style-type:none" />');
            return this;
        },

        
    });

    Ngg.DisplayTab.Views.DisplayType = Backbone.View.extend({
        className: 'display_type_preview',

        events: {
            click: 'clicked'
        },

        clicked: function(e){
            this.trigger('selected', this.model.get('name'));
        },

        render: function() {
            // Create all elements
            var image_container = $('<label style="display: block; cursor: pointer;"/>').addClass('image_container');

            var img = $('<img/>').attr({
                src: this.model.get('preview_image_url'),
                title: this.model.get('title'),
                alt: this.model.get('alt')
            });
            var inner_div = $('<div/>');
            var radio_button = $('<input/>').prop({
                type: 'radio',
                value: this.model.get('name'),
                title: this.model.get('title'),
                name: 'display_type',
                checked: this.model.get('selected')
            });
            var line_break = $('<br>');
            image_container.append(inner_div);
            image_container.append(img);
            image_container.append('<br>');
            image_container.append(this.model.get('title').replace(/nextgen /gi, ''));
            inner_div.append(radio_button);
            inner_div.append(line_break);
            // inner_div.append(this.model.get('title').replace(/nextgen /gi, ''));
            this.$el.append(image_container);
            return this;
        }
    })

    Ngg.DisplayTab.Views.Preview_Area = Backbone.View.extend({
        el: '#preview_area',

        initialize: function(){
            this.entities			= Ngg.DisplayTab.instance.entities;
            this.sources			= Ngg.DisplayTab.instance.sources;
            this.displayed_gallery	= Ngg.DisplayTab.instance.displayed_gallery;

            // Create the entity list
            this.entity_list		= $('<ul/>').attr('id', 'entity_list').append('<li class="clear"/>');

            // When an entity is added/removed to the collection, we'll add/remove it on the DOM
            this.entities.on('add', this.render_entity, this);
            this.entities.on('remove', this.remove_entity, this);

            // When the collection is reset, we add a list item to clear the float. This is important -
            // jQuery sortable() will break without the cleared element.
            this.entities.on('reset', this.entities_reset, this);

            // When jQuery sortable() is finished sorting, we need to adjust the order of models in the collection
            this.entities.on('change:sortorder', function(model){
                this.entities.remove(model, {silent: true});
                this.entities.add(model, {at: model.changed.sortorder, silent: true});
                this.displayed_gallery.set('sortorder', this.entities.entity_ids());
                if (typeof(console) != 'undefined' && typeof(console.log) != 'undefined') {
                    console.log(this.entities.entity_ids());
                }
                this.displayed_gallery.set('order_by', 'sortorder');
            }, this);

            // Reset when the source changes
            this.sources.on('selected', this.render, this);

            this.render();
        },

        events: {
            opened: 'entities_reset'
        },

        entities_reset: function(e){
            this.entities.reset(null, {silent: true});
            this.entity_list.empty().append('<li class="clear"/>');
            if (!this.entities.in_progress) this.entities.fetch();
        },

        render_entity: function(model){
            var entity_element = new this.EntityElement({model: model});
            this.entity_list.find('.clear').before(entity_element.render().$el);
            entity_element.$el.css('visibility', 'hidden');
            setTimeout(function(){
                entity_element.$el.css('visibility', 'visible');
            }, 0);
            if (this.$el.find('.no_entities').length == 1) {
                this.render();
            }
            else if (this.entities.length > 1) {
                this.entity_list.sortable('refresh');
            }
        },

        remove_entity: function(model){
            var id = this.id = model.get('id_field')+'_'+model.entity_id();
            var entity = this.entity_list.find('#'+id).remove();
            this.entity_list.sortable('refresh');
            if (this.entities.length == 0) {
                this.render_no_images_notice();
            }
        },

        render_no_images_notice: function(){
            this.$el.empty();
            this.$el.append("<p class='no_entities'>"+igw_data.i18n.no_entities+"</p>");
        },

        render: function(){
            this.$el.empty();
            if (this.entities.length > 0 && this.displayed_gallery.get('container_ids').length > 0) {

                // Render header rows
                this.$el.append(new this.RefreshButton({
                    entities: this.entities
                }).render().el);
                this.$el.append(new this.SortButtons({
                    entities: this.entities,
                    displayed_gallery: this.displayed_gallery,
                    sources: this.sources
                }).render().el);
                this.$el.append(new this.ExcludeButtons({
                    entities: this.entities
                }).render().el);

                this.$el.append(this.entity_list);

                // Activate jQuery Sortable for the entity list
                this.entity_list.sortable({
                    placeholder: 'placeholder',
                    forcePlaceholderSize: true,
                    containment: 'parent',
                    opacity: 0.7,
                    revert: true,
                    dropOnEmpty: true,
                    start: function(e, ui){
                        ui.placeholder.css({
                            height: ui.item.height()
                        });
                        return true;
                    },
                    stop: function(e, ui) {
                        ui.item.trigger('drop', ui.item.index());
                    }
                });
                this.entity_list.disableSelection();
            }
            else {
                this.render_no_images_notice();
            }
            return this;
        },

        RefreshButton: Backbone.View.extend({
            className: 'refresh_button button-primary',

            tagName: 'input',

            label: 'Refresh',

            events: {
                click: 'clicked'
            },

            clicked: function(){
                this.entities.reset();
            },

            initialize: function(options) {
                this.options = options || {};
                _.each(this.options, function(value, key){
                    this[key] = value;
                }, this);
            },

            render: function(){
                this.$el.attr({
                    value: this.label,
                    type:  'button'
                });
                return this;
            }
        }),

        ExcludeButtons: Backbone.View.extend({
            className: 'header_row',

            initialize: function(options) {
                this.options = options || {};
                _.each(this.options, function(value, key){
                    this[key] = value;
                }, this);
            },

            render: function(){
                this.$el.empty();
                this.$el.append('<span style="margin-right: 8px;">Exclude:</span>');
                var all_button = new this.Button({
                    value: true,
                    text: 'All',
                    entities: this.entities
                });
                this.$el.append(all_button.render().el);
                this.$el.append('<span class="separator">|</span>');
                var none_button = new this.Button({
                    value: false,
                    text: 'None',
                    entities: this.entities
                });
                this.$el.append(none_button.render().el);
                return this;
            },

            Button: Backbone.View.extend({
                tagName: 'a',

                value: 1,

                text: '',

                events: {
                    click: 'clicked'
                },

                initialize: function(options) {
                    this.options = options || {};
                    _.each(this.options, function(value, key){
                        this[key] = value;
                    }, this);
                },

                clicked: function(e){
                    e.preventDefault();
                    this.entities.each(function(item){
                        item.set('exclude', this.value);
                    }, this);
                },

                render: function(){
                    this.$el.text(this.text).attr('href', '#');
                    return this;
                }
            })
        }),

        SortButtons: Backbone.View.extend({
            className: 'header_row',

            initialize: function(options) {
                this.options = options || {};
                _.each(this.options, function(value, key){
                    this[key] = value;
                }, this);
                this.sortorder_options = new Ngg.DisplayTab.Models.SortOrder_Options();
                this.sortorder_options.on('change:selected', this.sortoption_changed, this);

                // Create sort directions and listen for selection changes
                this.sortdirection_options = new Ngg.DisplayTab.Models.SortDirection_Options([
                    {
                        value: 'ASC',
                        title: 'Ascending',
                        selected: this.displayed_gallery.get('order_direction') == 'ASC'
                    },
                    {
                        value: 'DESC',
                        title: 'Descending',
                        selected: this.displayed_gallery.get('order_direction') == 'DESC'
                    }
                ]);
                this.sortdirection_options.on('change:selected', this.sortdirection_changed, this);
                this.displayed_gallery.on('change:order_by', this.displayed_gallery_order_changed, this);
                this.displayed_gallery.on('change.order_direction', this.displayed_gallery_order_dir_changed, this);
            },

            populate_sorting_fields: function(){
                // We display difference sorting buttons depending on what type of entities we're dealing with.
                var entity_types = this.sources.selected().pop().get('returns');
                if (_.indexOf(entity_types, 'image') !== -1) {
                    this.fill_image_sortorder_options();
                }
                else {
                    this.fill_gallery_sortorder_options();
                }
            },

            create_sortorder_option: function(name, title){
                return new Ngg.DisplayTab.Models.SortOrder({
                    name: name,
                    title: title,
                    value: name,
                    selected: this.displayed_gallery.get('order_by') == name
                });
            },

            fill_image_sortorder_options: function(){
                this.sortorder_options.reset();
                this.sortorder_options.push(this.create_sortorder_option('', 'None'));
                this.sortorder_options.push(this.create_sortorder_option('sortorder', 'Custom'));
                this.sortorder_options.push(this.create_sortorder_option(Ngg.DisplayTab.instance.image_key, 'Image ID'));
                this.sortorder_options.push(this.create_sortorder_option('filename', 'Filename'));
                this.sortorder_options.push(this.create_sortorder_option('alttext', 'Alt/Title Text'));
                this.sortorder_options.push(this.create_sortorder_option('imagedate', 'Date/Time'));
            },

            fill_gallery_sortorder_options: function(){
                this.sortorder_options.reset();
                this.sortorder_options.push(this.create_sortorder_option('', 'None'));
                this.sortorder_options.push(this.create_sortorder_option('sortorder' ,'Custom'));
                this.sortorder_options.push(this.create_sortorder_option('name', 'Name'));
                this.sortorder_options.push(this.create_sortorder_option('galdesc', 'Description'));
            },

            displayed_gallery_order_changed: function(e){
                this.sortorder_options.findWhere({value: e.get('order_by')}).set('selected', true);
            },


            displayed_gallery_order_dir_changed: function(e){
                this.sortdirection_options.findWhere({value: e.get('order_direction')}).set('selected', true);
            },

            sortoption_changed: function(model){
                this.sortorder_options.each(function(item){
                    item.set('selected', model.get('value') == item.get('value') ? true : false, {silent: true});
                });

                this.displayed_gallery.set('sortorder', []);

                var sort_by = model.get('value');

                // If "None" was selected, then clear the "sortorder" property
                if (model.get('value').length == 0) {
                    sort_by = 'sortorder';
                }

                // Change the "sort by" parameter
                this.displayed_gallery.set('order_by', sort_by);

                this.entities.reset();
                this.$el.find('a.sortorder').each(function(){
                    var $item = $(this);
                    if ($item.attr('value') == model.get('value'))
                        $item.addClass('selected');
                    else
                        $item.removeClass('selected');
                });
            },

            sortdirection_changed: function(model){

                this.sortdirection_options.each(function(item){
                    item.set('selected', model.get('value') == item.get('value') ? true : false, {silent: true});
                });
                this.displayed_gallery.set('order_direction', model.get('value'));
                this.entities.reset();
                this.$el.find('a.sortdirection').each(function(){
                    var $item = $(this);
                    if ($item.attr('value') == model.get('value'))
                        $item.addClass('selected');
                    else
                        $item.removeClass('selected');
                });
            },

            render: function(){
                this.$el.empty();
                this.populate_sorting_fields();
                this.$el.append('<span style="margin-right: 8px;">Sort By:</span>');
                this.sortorder_options.each(function(item, index){
                    var button = new this.Button({model: item, className: 'sortorder'});
                    this.$el.append(button.render().el);
                    if (this.sortorder_options.length-1 > index) {
                        this.$el.append('<span class="separator">|</span>');
                    }
                }, this);
                this.$el.append('<span style="margin: 0 8px 0 40px;">Order By:</span>');
                this.sortdirection_options.each(function(item, index){
                    var button = new this.Button({model: item, className: 'sortdirection'});
                    this.$el.append(button.render().el);
                    if (this.sortdirection_options.length-1 > index) {
                        this.$el.append('<span class="separator">|</span>');
                    }
                }, this);
                return this;
            },

            Button: Backbone.View.extend({
                tagName: 'a',

                initialize: function(options) {
                    this.options = options || {};
                    _.each(this.options, function(value, key){
                        this[key] = value;
                    }, this);
                },

                events: {
                    click: 'clicked'
                },

                clicked: function(e){
                    e.preventDefault();
                    this.model.set('selected', true);
                },

                render: function(){
                    this.$el.prop({
                        value: this.model.get('value'),
                        href: '#'
                    });
                    this.$el.text(this.model.get('title'));
                    if (this.model.get('selected')) this.$el.addClass('selected');
                    return this;
                }
            })
        }),

        // Individual entity in the preview area
        EntityElement: Backbone.View.extend({
            tagName: 'li',

            events: {
                drop: 'item_dropped'
            },

            initialize: function(options) {
                this.options = options || {};
                _.each(this.options, function(value, key){
                    this[key] = value;
                }, this);
                this.initTime = new Date().getTime();
                this.model.on('change', this.render, this);
                if (this.model.get('sortorder') == 0) {
                    this.model.set('sortorder', -1, {silent: true});
                }
                this.id = this.model.get('id_field')+'_'+this.model.entity_id()
            },

            item_dropped: function(e, index){
                Ngg.DisplayTab.instance.displayed_gallery.set('order_by', 'sortorder');
                //Ngg.DisplayTab.instance.displayed_gallery.set('order_direction', 'ASC');
                this.model.set('sortorder', index);
            },

            render: function(){
                this.$el.empty();
                var preview_item = $('<div/>').addClass('preview_item');
                var image_container = $('<div/>').addClass('image_container');
                var alt_text = this.model.alttext().replace(/\\&/g, '&').replace(/\\'/g, "'");
                var timestamp = this.initTime;
                image_container.attr({
                    title: alt_text,
                    style: "background-image: url('"+this.model.get('thumb_url')+"?timestamp"+timestamp+"')"
                });

                this.$el.append(preview_item).addClass('ui-state-default');

                preview_item.append(image_container);

                // Add exclude checkbox
                var exclude_container = $('<div/>').addClass('exclude_container');
                var exclude_label = $('<label/>');
                exclude_label.append(igw_data.i18n.exclude_question);
                var exclude_checkbox = new this.ExcludeCheckbox({model: this.model});
                exclude_label.append(exclude_checkbox.render().el);
                exclude_container.append(exclude_label);
                preview_item.append(exclude_container);
                return this;
            },

            ExcludeCheckbox: Backbone.View.extend({
                tagName: 'input',

                events: {
                    'change': 'entity_excluded'
                },

                type_set: false,

                entity_excluded: function(e){
                    this.model.set('exclude', e.target.checked);
                },

                initialize: function(options) {
                    this.options = options || {};
                    _.each(this.options, function(value, key){
                        this[key] = value;
                    }, this);
                    this.model.on('change:exclude', this.render, this);
                },

                render: function(){
                    if (!this.type_set) {
                        this.$el.attr('type', 'checkbox');
                        this.type_set = true;
                    }
                    if (this.model.is_excluded()) this.$el.prop('checked', true);
                    else this.$el.prop('checked', false);
                    return this;
                }
            })
        })
    });


    // Additional source configuration views. These will be rendered dynamically by PHP.
    // Adapters will add them.
    Ngg.DisplayTab.Views.GalleriesSource = Backbone.View.extend({
        tagName: 'tbody',

        initialize: function(){
            this.galleries = Ngg.DisplayTab.instance.galleries;
        },

        render: function(){
            var select = new Ngg.Views.Chosen({
                collection: this.galleries,
                placeholder: igw_data.i18n.select_gallery,
                multiple: true,
                width: 500
            });
            var html = $('<tr><td class="galleries_column"></td><td><label>'+igw_data.i18n.galleries+'</label></td></tr>');
            this.$el.empty();
            this.$el.append(html);
            this.$el.find('.galleries_column').append(select.render().el);
            return this;
        }
    });

    Ngg.DisplayTab.Views.AlbumsSource = Backbone.View.extend({
        tagName: 'tbody',

        initialize: function(){
            this.albums 	= Ngg.DisplayTab.instance.albums;
        },

        render: function(){
            var album_select = new Ngg.Views.Chosen({
                collection: this.albums,
                multiple: true,
                placeholder: 'Select an album',
                text_field: 'name',
                width: 500
            });
            this.$el.empty();
            this.$el.append('<tr><td class="albums_column"></td><td><label>'+igw_data.i18n.albums+'</label></td></tr>');
            this.$el.find('.albums_column').append(album_select.render().el);
            return this;
        }
    });

    Ngg.DisplayTab.Views.TagsSource = Backbone.View.extend({
        tagName: 'tbody',

        initialize: function(){
            this.tags	= Ngg.DisplayTab.instance.tags;
        },

        render: function(){
            var tag_select = new Ngg.Views.Chosen({
                collection: this.tags,
                multiple: true,
                placeholder: 'Select a tag',
                text_field: 'name',
                width: 500
            });
            this.$el.empty();
            this.$el.append('<tr><td class="tags_column"></td><td><label>Tags</label></td></tr>');
            this.$el.find('.tags_column').append(tag_select.render().el);
            return this;
        }
    });

    Ngg.DisplayTab.Views.Recent_imagesSource = Backbone.View.extend({
        tagName: 'tbody',

        initialize: function(){
            this.displayed_gallery		= Ngg.DisplayTab.instance.displayed_gallery;
            this.maximum_entity_count	= Ngg.DisplayTab.instance.displayed_gallery.get('maximum_entity_count');
            this.displayed_gallery.set('container_ids', []);
        },

        render: function(){
            var self = this;
            var edit_field = $('<input/>').prop({
                type: 'text',
                value: this.maximum_entity_count,
                name: 'maximum_entity_count'
            });

            edit_field.on('change', function () {
                self.displayed_gallery.set('maximum_entity_count', $(this).val());
            });

            this.$el.empty();
            this.$el.append('<tr><td class="recent_images_column"></td><td><label># of Images To Display</label></td></tr>');
            this.$el.find('.recent_images_column').append(edit_field);
            return this;
        }
    });

    Ngg.DisplayTab.Views.Random_imagesSource = Backbone.View.extend({
        tagName: 'tbody',

        initialize: function(){
            this.displayed_gallery		= Ngg.DisplayTab.instance.displayed_gallery;
            this.maximum_entity_count	= Ngg.DisplayTab.instance.displayed_gallery.get('maximum_entity_count');
            this.displayed_gallery.set('container_ids', []);
        },

        render: function(){
            var self = this;
            var edit_field = $('<input/>').prop({
                type: 'text',
                value: this.maximum_entity_count,
                name: 'maximum_entity_count'
            });

            edit_field.on('change', function () {
                self.displayed_gallery.set('maximum_entity_count', $(this).val());
            });

            this.$el.empty();
            this.$el.append('<tr><td class="random_images_column"></td><td><label># of Images To Display</label></td></tr>');
            this.$el.find('.random_images_column').append(edit_field);
            return this;
        }
    });

    Ngg.DisplayTab.Views.SaveButton = Backbone.View.extend({
        el: '#save_displayed_gallery',

        errors_el: '#errors',

        displayed_gallery: null,

        events: {
            click: 'clicked'
        },

        initialize: function(){
            this.displayed_gallery	= Ngg.DisplayTab.instance.displayed_gallery;
            this.entities			= Ngg.DisplayTab.instance.entities;
            this.render();
        },

        clicked: function(){
            this.set_display_settings();
            var shortcode = this.displayed_gallery.to_shortcode();
            insert_into_editor(shortcode, (this.displayed_gallery.id ? this.displayed_gallery.id : igw_data.shortcode_ref));
            var editor = null
            if ((editor = location.toString().match(/editor=([^\&]+)/)) && editor.length >= 2) {
                top.tinyMCE.editors[editor[1]].fire('ngg-inserted', {shortcode: shortcode})
            }
            
            close_attach_to_post_window();
        },

        set_display_settings: function() {
            var display_type = this.displayed_gallery.get('display_type');
            if (display_type) {
                // Collect display settings
                var form = $("form[rel='" + display_type + "']");
                var defaults = form.data('defaults')
                var display_settings = (function(item) {
                    var obj = {};
                    $.each(item.serializeArray(), function(key, item) {
                        var parts = item.name.split('[');
                        var current_obj = obj;
                        for (var i = 0; i < parts.length; i++) {
                            var part = parts[i].replace(/\]$/, '');

                            // Skip settings that haven't been changed from the default
                            if (defaults[part] == item.value) {
                                return true;
                            }

                            if (!current_obj[part]) {
                                if (i == (parts.length - 1)) {
                                    current_obj[part] = item.value;
                                } else {
                                    current_obj[part] = {};
                                }
                            }
                            current_obj = current_obj[part];
                        }
                    });
                    return obj;
                })(form);

                // Set display settings for displayed gallery
                this.displayed_gallery.set('display_settings', display_settings[display_type]);
            }
        },

        render: function(){
            this.$el.css('z-index', 1000);
            return this;
        }
    });

    /*****************************************************************************
     * APPLICATION
     **/
    Ngg.DisplayTab.App = Backbone.View.extend({
        /**
         * Initializes the DisplayTab object
         **/
        initialize: function(){
            // TODO: We're currently fetching ALL galleries, albums, and tags
            // in one shot. Instead, we should display the displayed_gallery's
            // containers, if there are any, otherwise get the first 100 or so.
            // We can then use AJAX to fetch the rest of batches.
            this.displayed_gallery = new Ngg.DisplayTab.Models.Displayed_Gallery(igw_data.displayed_gallery);
            this.original_displayed_gallery = new Ngg.DisplayTab.Models.Displayed_Gallery(igw_data.displayed_gallery);
            this.galleries = new Ngg.DisplayTab.Models.Gallery_Collection(igw_data.galleries);
            this.albums = new Ngg.DisplayTab.Models.Album_Collection(igw_data.albums);
            this.tags = new Ngg.DisplayTab.Models.Tag_Collection(igw_data.tags);
            this.sources = new Ngg.DisplayTab.Models.Source_Collection(igw_data.sources);
            this.display_types = new Ngg.DisplayTab.Models.Display_Type_Collection(igw_data.display_types);
            this.display_type_order_base = igw_data.display_type_priority_base;
            this.display_type_order_step = igw_data.display_type_priority_step;
            this.entities = new Ngg.DisplayTab.Models.Entity_Collection();
            this.entities.extra_data.displayed_gallery = this.displayed_gallery;
            this.image_key = igw_data.image_primary_key;

            // Pre-select current displayed gallery values
            if (this.displayed_gallery.get('source')) {

                // Pre-select source
                if (this.displayed_gallery.get('source')) {
                    var source = this.sources.find_by_name_or_alias(this.displayed_gallery.get('source'));
                    if (source) source.set('selected', true);
                }

                // Pre-select containers
                if (this.displayed_gallery.get('container_ids')) {
                    _.each(this.displayed_gallery.get('container_ids'), function(id){
                        var container = this[this.displayed_gallery.get('source')].find(function(item){
                            return item.id == id;
                        }, this);
                        if (container) container.set('selected', true);
                    }, this);
                }

                // Pre-select display type
                if ((this.displayed_gallery.get('display_type'))) {
                    var display_type = this.display_types.find_by_name_or_alias(this.displayed_gallery.get('display_type'));
                    if (display_type) {
                        display_type.set('selected', true);
                        this.displayed_gallery.set('display_type', display_type.get('name'));
                    }
                }
            }

            // Bind to the 'selected' event for each of the collections, and update the displayed
            // gallery object's 'container_ids' attribute when something has changed
            collections = ['galleries', 'albums', 'tags'];
            _.each(collections, function(collection){
                this[collection].on('selected', function(){this.update_selected_containers(collection);}, this);
            }, this);

            // Bind to the 'selected' event for the display types collection, updating the displayed gallery
            this.display_types.on('change:selected', function(){
                this.displayed_gallery.set('display_type', this.display_types.selected_value());
            }, this);

            // Bind to the 'selected' event for the source, updating the displayed gallery
            this.sources.on('selected', function() {

                // It is possible for fast acting users to get an invalid shortcode: by changing gallery source and
                // then rushing to the 'insert gallery' button it's possible for the state to be unchanged when the new
                // shortcode is written thus 'leaving behind' the old displayed gallery without the newly chosen attr.
                // This just temporarily disables that button for one second for the internal state to catch up.
                $('#save_displayed_gallery').prop('disabled', true);
                setTimeout(function() {
                    $('#save_displayed_gallery').prop('disabled', false);
                }, 1000);

                this.displayed_gallery.set('source', this.sources.selected_value());

                // If the source changed, and it's not the set to the original value, then
                // exclusions get's set to []
                if (this.sources.selected_value() != this.original_displayed_gallery.get('source'))
                    this.displayed_gallery.set('exclusions', this.entities.excluded_ids());

                // Otherwise, we revert to the original exclusions
                else
                    this.displayed_gallery.set('exclusions', this.original_displayed_gallery.get('exclusions'));

                // special exemption: these should default to a reasonable limit
                if (this.sources.selected_value() == 'random_images' || this.sources.selected_value() == 'recent_images') {
                    this.displayed_gallery.set('maximum_entity_count', 20);
                }

                // Reset everything else
                this.galleries.deselect_all();
                this.albums.deselect_all();
                this.tags.deselect_all();

                // If the selected source is incompatible with the current display type, then
                // display a new list
                var selected_display_type = this.display_types.selected();
                var selected_source		  = this.sources.selected();
                if (selected_display_type.length > 0 && selected_source.length > 0) {
                    selected_display_type = selected_display_type[0];
                    selected_source       = selected_source[0];
                    if (!selected_display_type.is_compatible_with_source(selected_source))
                        this.display_types.deselect_all();
                    if (this.display_type_selector) this.display_type_selector.render();
                }
                if (this.preview_area) this.preview_area.render();
            }, this);

            // Synchronize changes made to entities with the displayed gallery
            this.entities.on('change:exclude finished_fetching', function(){
                //this.displayed_gallery.set('sortorder', this.entities.entity_ids());
                this.displayed_gallery.set('exclusions', this.entities.excluded_ids());
            }, this);

            // Default to the "galleries" display types when creating new entries
            if (!this.displayed_gallery.get('source')) {
                var defaultsource = this.sources.find_by_name_or_alias('galleries');
                if (defaultsource) {
                    defaultsource.set('selected', true);
                    this.sources.trigger('selected');
                }
            }

            // Monitor events in other tabs and respond as appropriate
            if (window.Frame_Event_Publisher) {
                var app = this;

                // New gallery event
                Frame_Event_Publisher.listen_for('attach_to_post:new_gallery', function(){
                    app.galleries.reset();
                    app.galleries.fetch();
                });

                // A change has been made using the "Manage Galleries" page
                Frame_Event_Publisher.listen_for('attach_to_post:manage_galleries attach_to_post:manage_images', function(data){

                    // Refresh the list of galleries
                    app.galleries.reset();
                    app.galleries.fetch();

                    // If we're viewing galleries or images, then we need to refresh the entity list
                    var selected_source = app.sources.selected().pop();
                    if (selected_source) {
                        if (_.indexOf(selected_source.get('returns'), 'image') >= 0 ||
                            _.indexOf(selected_source.get('returns'), 'gallery')) {
                            app.entities.reset();
                        }
                    }
                });

                // A change has been made using the "Manage Albums" page
                Frame_Event_Publisher.listen_for('attach_to_post:manage_album', function(data){
                    // Refresh the list of albums
                    app.albums.reset();
                    app.albums.fetch();

                    // If we're viewing albums, then we need to refresh the entity list
                    var selected_source = app.sources.selected().pop();
                    if (selected_source) {
                        if (_.indexOf(selected_source.get('returns'), 'album') >= 0) {
                            app.entities.reset();
                        }
                    }
                });

                // A change has been made using the "Manage Tags" page
                Frame_Event_Publisher.listen_for('attach_to_post:manage_tags attach_to_post:manage_images', function(data){
                    // Refresh the list of tags
                    app.tags.reset();
                    app.tags.fetch();

                    // If we're viewing galleries or images, then we need to refresh the entity list
                    var selected_source = app.sources.selected().pop();
                    if (selected_source) {
                        if (_.indexOf(selected_source.get('returns'), 'image') >= 0 ||
                            _.indexOf(selected_source.get('returns'), 'gallery')) {
                            app.entities.reset();
                        }
                    }
                });

                // Thumbnail modified event
                Frame_Event_Publisher.listen_for('attach_to_post:thumbnail_modified', function(data){
                    var selected_source = app.sources.selected().pop();
                    var image_id = data.image[data.image.id_field];

                    if (selected_source) {

                        // Does the currently selected source return images? If so,
                        // check refresh the modified image's thumbnail
                        if(_.indexOf(selected_source.get('returns'), 'image') >= 0) {
                            var image = app.entities.find(function(item){
                                return parseInt(item.entity_id()) == parseInt(image_id);
                            }, this);
                            if (image) image.set('thumb_url', data.image.thumb_url);
                        }

                        // It must be an album or gallery
                        else {
                            var entity = app.entities.find(function(item){
                                return parseInt(item.get('previewpic')) == image_id;
                            }, this);
                            if (entity) entity.trigger('change');
                        }
                    }
                });
            }
        },

        // Updates the selected container_ids for the displayed gallery
        update_selected_containers: function(collection){
            this.displayed_gallery.set('container_ids', this[collection].selected_ids());
        },

        render: function(){
            this.display_type_selector = new Ngg.DisplayTab.Views.Display_Type_Selector();
            new Ngg.DisplayTab.Views.Source_Config();
            new Ngg.DisplayTab.Views.Slug_Config();
            this.preview_area = new Ngg.DisplayTab.Views.Preview_Area();
            new Ngg.DisplayTab.Views.SaveButton();
        }
    });
    window.Ngg = Ngg;
    $(window).trigger('ngg_before_igw_render');
    Ngg.DisplayTab.instance = new Ngg.DisplayTab.App();
    Ngg.DisplayTab.instance.render();

    // Invoke styling libraries
    $('span.tooltip, label.tooltip').tooltip();
});