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/wp/core/5.9/wp-admin/js
Viewing File: /opt/wp/core/5.9/wp-admin/js/nav-menu.js
/** * WordPress Administration Navigation Menu * Interface JS functions * * @version 2.0.0 * * @package WordPress * @subpackage Administration * @output wp-admin/js/nav-menu.js */ /* global menus, postboxes, columns, isRtl, ajaxurl, wpNavMenu */ (function($) { var api; /** * Contains all the functions to handle WordPress navigation menus administration. * * @namespace wpNavMenu */ api = window.wpNavMenu = { options : { menuItemDepthPerLevel : 30, // Do not use directly. Use depthToPx and pxToDepth instead. globalMaxDepth: 11, sortableItems: '> *', targetTolerance: 0 }, menuList : undefined, // Set in init. targetList : undefined, // Set in init. menusChanged : false, isRTL: !! ( 'undefined' != typeof isRtl && isRtl ), negateIfRTL: ( 'undefined' != typeof isRtl && isRtl ) ? -1 : 1, lastSearch: '', // Functions that run on init. init : function() { api.menuList = $('#menu-to-edit'); api.targetList = api.menuList; this.jQueryExtensions(); this.attachMenuEditListeners(); this.attachBulkSelectButtonListeners(); this.attachMenuCheckBoxListeners(); this.attachMenuItemDeleteButton(); this.attachPendingMenuItemsListForDeletion(); this.attachQuickSearchListeners(); this.attachThemeLocationsListeners(); this.attachMenuSaveSubmitListeners(); this.attachTabsPanelListeners(); this.attachUnsavedChangesListener(); if ( api.menuList.length ) this.initSortables(); if ( menus.oneThemeLocationNoMenus ) $( '#posttype-page' ).addSelectedToMenu( api.addMenuItemToBottom ); this.initManageLocations(); this.initAccessibility(); this.initToggles(); this.initPreviewing(); }, jQueryExtensions : function() { // jQuery extensions. $.fn.extend({ menuItemDepth : function() { var margin = api.isRTL ? this.eq(0).css('margin-right') : this.eq(0).css('margin-left'); return api.pxToDepth( margin && -1 != margin.indexOf('px') ? margin.slice(0, -2) : 0 ); }, updateDepthClass : function(current, prev) { return this.each(function(){ var t = $(this); prev = prev || t.menuItemDepth(); $(this).removeClass('menu-item-depth-'+ prev ) .addClass('menu-item-depth-'+ current ); }); }, shiftDepthClass : function(change) { return this.each(function(){ var t = $(this), depth = t.menuItemDepth(), newDepth = depth + change; t.removeClass( 'menu-item-depth-'+ depth ) .addClass( 'menu-item-depth-'+ ( newDepth ) ); if ( 0 === newDepth ) { t.find( '.is-submenu' ).hide(); } }); }, childMenuItems : function() { var result = $(); this.each(function(){ var t = $(this), depth = t.menuItemDepth(), next = t.next( '.menu-item' ); while( next.length && next.menuItemDepth() > depth ) { result = result.add( next ); next = next.next( '.menu-item' ); } }); return result; }, shiftHorizontally : function( dir ) { return this.each(function(){ var t = $(this), depth = t.menuItemDepth(), newDepth = depth + dir; // Change .menu-item-depth-n class. t.moveHorizontally( newDepth, depth ); }); }, moveHorizontally : function( newDepth, depth ) { return this.each(function(){ var t = $(this), children = t.childMenuItems(), diff = newDepth - depth, subItemText = t.find('.is-submenu'); // Change .menu-item-depth-n class. t.updateDepthClass( newDepth, depth ).updateParentMenuItemDBId(); // If it has children, move those too. if ( children ) { children.each(function() { var t = $(this), thisDepth = t.menuItemDepth(), newDepth = thisDepth + diff; t.updateDepthClass(newDepth, thisDepth).updateParentMenuItemDBId(); }); } // Show "Sub item" helper text. if (0 === newDepth) subItemText.hide(); else subItemText.show(); }); }, updateParentMenuItemDBId : function() { return this.each(function(){ var item = $(this), input = item.find( '.menu-item-data-parent-id' ), depth = parseInt( item.menuItemDepth(), 10 ), parentDepth = depth - 1, parent = item.prevAll( '.menu-item-depth-' + parentDepth ).first(); if ( 0 === depth ) { // Item is on the top level, has no parent. input.val(0); } else { // Find the parent item, and retrieve its object id. input.val( parent.find( '.menu-item-data-db-id' ).val() ); } }); }, hideAdvancedMenuItemFields : function() { return this.each(function(){ var that = $(this); $('.hide-column-tog').not(':checked').each(function(){ that.find('.field-' + $(this).val() ).addClass('hidden-field'); }); }); }, /** * Adds selected menu items to the menu. * * @ignore * * @param jQuery metabox The metabox jQuery object. */ addSelectedToMenu : function(processMethod) { if ( 0 === $('#menu-to-edit').length ) { return false; } return this.each(function() { var t = $(this), menuItems = {}, checkboxes = ( menus.oneThemeLocationNoMenus && 0 === t.find( '.tabs-panel-active .categorychecklist li input:checked' ).length ) ? t.find( '#page-all li input[type="checkbox"]' ) : t.find( '.tabs-panel-active .categorychecklist li input:checked' ), re = /menu-item\[([^\]]*)/; processMethod = processMethod || api.addMenuItemToBottom; // If no items are checked, bail. if ( !checkboxes.length ) return false; // Show the Ajax spinner. t.find( '.button-controls .spinner' ).addClass( 'is-active' ); // Retrieve menu item data. $(checkboxes).each(function(){ var t = $(this), listItemDBIDMatch = re.exec( t.attr('name') ), listItemDBID = 'undefined' == typeof listItemDBIDMatch[1] ? 0 : parseInt(listItemDBIDMatch[1], 10); if ( this.className && -1 != this.className.indexOf('add-to-top') ) processMethod = api.addMenuItemToTop; menuItems[listItemDBID] = t.closest('li').getItemData( 'add-menu-item', listItemDBID ); }); // Add the items. api.addItemToMenu(menuItems, processMethod, function(){ // Deselect the items and hide the Ajax spinner. checkboxes.prop( 'checked', false ); t.find( '.button-controls .select-all' ).prop( 'checked', false ); t.find( '.button-controls .spinner' ).removeClass( 'is-active' ); }); }); }, getItemData : function( itemType, id ) { itemType = itemType || 'menu-item'; var itemData = {}, i, fields = [ 'menu-item-db-id', 'menu-item-object-id', 'menu-item-object', 'menu-item-parent-id', 'menu-item-position', 'menu-item-type', 'menu-item-title', 'menu-item-url', 'menu-item-description', 'menu-item-attr-title', 'menu-item-target', 'menu-item-classes', 'menu-item-xfn' ]; if( !id && itemType == 'menu-item' ) { id = this.find('.menu-item-data-db-id').val(); } if( !id ) return itemData; this.find('input').each(function() { var field; i = fields.length; while ( i-- ) { if( itemType == 'menu-item' ) field = fields[i] + '[' + id + ']'; else if( itemType == 'add-menu-item' ) field = 'menu-item[' + id + '][' + fields[i] + ']'; if ( this.name && field == this.name ) { itemData[fields[i]] = this.value; } } }); return itemData; }, setItemData : function( itemData, itemType, id ) { // Can take a type, such as 'menu-item', or an id. itemType = itemType || 'menu-item'; if( !id && itemType == 'menu-item' ) { id = $('.menu-item-data-db-id', this).val(); } if( !id ) return this; this.find('input').each(function() { var t = $(this), field; $.each( itemData, function( attr, val ) { if( itemType == 'menu-item' ) field = attr + '[' + id + ']'; else if( itemType == 'add-menu-item' ) field = 'menu-item[' + id + '][' + attr + ']'; if ( field == t.attr('name') ) { t.val( val ); } }); }); return this; } }); }, countMenuItems : function( depth ) { return $( '.menu-item-depth-' + depth ).length; }, moveMenuItem : function( $this, dir ) { var items, newItemPosition, newDepth, menuItems = $( '#menu-to-edit li' ), menuItemsCount = menuItems.length, thisItem = $this.parents( 'li.menu-item' ), thisItemChildren = thisItem.childMenuItems(), thisItemData = thisItem.getItemData(), thisItemDepth = parseInt( thisItem.menuItemDepth(), 10 ), thisItemPosition = parseInt( thisItem.index(), 10 ), nextItem = thisItem.next(), nextItemChildren = nextItem.childMenuItems(), nextItemDepth = parseInt( nextItem.menuItemDepth(), 10 ) + 1, prevItem = thisItem.prev(), prevItemDepth = parseInt( prevItem.menuItemDepth(), 10 ), prevItemId = prevItem.getItemData()['menu-item-db-id'], a11ySpeech = menus[ 'moved' + dir.charAt(0).toUpperCase() + dir.slice(1) ]; switch ( dir ) { case 'up': newItemPosition = thisItemPosition - 1; // Already at top. if ( 0 === thisItemPosition ) break; // If a sub item is moved to top, shift it to 0 depth. if ( 0 === newItemPosition && 0 !== thisItemDepth ) thisItem.moveHorizontally( 0, thisItemDepth ); // If prev item is sub item, shift to match depth. if ( 0 !== prevItemDepth ) thisItem.moveHorizontally( prevItemDepth, thisItemDepth ); // Does this item have sub items? if ( thisItemChildren ) { items = thisItem.add( thisItemChildren ); // Move the entire block. items.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId(); } else { thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId(); } break; case 'down': // Does this item have sub items? if ( thisItemChildren ) { items = thisItem.add( thisItemChildren ), nextItem = menuItems.eq( items.length + thisItemPosition ), nextItemChildren = 0 !== nextItem.childMenuItems().length; if ( nextItemChildren ) { newDepth = parseInt( nextItem.menuItemDepth(), 10 ) + 1; thisItem.moveHorizontally( newDepth, thisItemDepth ); } // Have we reached the bottom? if ( menuItemsCount === thisItemPosition + items.length ) break; items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) ).updateParentMenuItemDBId(); } else { // If next item has sub items, shift depth. if ( 0 !== nextItemChildren.length ) thisItem.moveHorizontally( nextItemDepth, thisItemDepth ); // Have we reached the bottom? if ( menuItemsCount === thisItemPosition + 1 ) break; thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) ).updateParentMenuItemDBId(); } break; case 'top': // Already at top. if ( 0 === thisItemPosition ) break; // Does this item have sub items? if ( thisItemChildren ) { items = thisItem.add( thisItemChildren ); // Move the entire block. items.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId(); } else { thisItem.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId(); } break; case 'left': // As far left as possible. if ( 0 === thisItemDepth ) break; thisItem.shiftHorizontally( -1 ); break; case 'right': // Can't be sub item at top. if ( 0 === thisItemPosition ) break; // Already sub item of prevItem. if ( thisItemData['menu-item-parent-id'] === prevItemId ) break; thisItem.shiftHorizontally( 1 ); break; } $this.trigger( 'focus' ); api.registerChange(); api.refreshKeyboardAccessibility(); api.refreshAdvancedAccessibility(); if ( a11ySpeech ) { wp.a11y.speak( a11ySpeech ); } }, initAccessibility : function() { var menu = $( '#menu-to-edit' ); api.refreshKeyboardAccessibility(); api.refreshAdvancedAccessibility(); // Refresh the accessibility when the user comes close to the item in any way. menu.on( 'mouseenter.refreshAccessibility focus.refreshAccessibility touchstart.refreshAccessibility' , '.menu-item' , function(){ api.refreshAdvancedAccessibilityOfItem( $( this ).find( 'a.item-edit' ) ); } ); // We have to update on click as well because we might hover first, change the item, and then click. menu.on( 'click', 'a.item-edit', function() { api.refreshAdvancedAccessibilityOfItem( $( this ) ); } ); // Links for moving items. menu.on( 'click', '.menus-move', function () { var $this = $( this ), dir = $this.data( 'dir' ); if ( 'undefined' !== typeof dir ) { api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), dir ); } }); }, /** * refreshAdvancedAccessibilityOfItem( [itemToRefresh] ) * * Refreshes advanced accessibility buttons for one menu item. * Shows or hides buttons based on the location of the menu item. * * @param {Object} itemToRefresh The menu item that might need its advanced accessibility buttons refreshed */ refreshAdvancedAccessibilityOfItem : function( itemToRefresh ) { // Only refresh accessibility when necessary. if ( true !== $( itemToRefresh ).data( 'needs_accessibility_refresh' ) ) { return; } var thisLink, thisLinkText, primaryItems, itemPosition, title, parentItem, parentItemId, parentItemName, subItems, $this = $( itemToRefresh ), menuItem = $this.closest( 'li.menu-item' ).first(), depth = menuItem.menuItemDepth(), isPrimaryMenuItem = ( 0 === depth ), itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(), position = parseInt( menuItem.index(), 10 ), prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1, 10 ), prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(), prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(), totalMenuItems = $('#menu-to-edit li').length, hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length; menuItem.find( '.field-move' ).toggle( totalMenuItems > 1 ); // Where can they move this menu item? if ( 0 !== position ) { thisLink = menuItem.find( '.menus-move-up' ); thisLink.attr( 'aria-label', menus.moveUp ).css( 'display', 'inline' ); } if ( 0 !== position && isPrimaryMenuItem ) { thisLink = menuItem.find( '.menus-move-top' ); thisLink.attr( 'aria-label', menus.moveToTop ).css( 'display', 'inline' ); } if ( position + 1 !== totalMenuItems && 0 !== position ) { thisLink = menuItem.find( '.menus-move-down' ); thisLink.attr( 'aria-label', menus.moveDown ).css( 'display', 'inline' ); } if ( 0 === position && 0 !== hasSameDepthSibling ) { thisLink = menuItem.find( '.menus-move-down' ); thisLink.attr( 'aria-label', menus.moveDown ).css( 'display', 'inline' ); } if ( ! isPrimaryMenuItem ) { thisLink = menuItem.find( '.menus-move-left' ), thisLinkText = menus.outFrom.replace( '%s', prevItemNameLeft ); thisLink.attr( 'aria-label', menus.moveOutFrom.replace( '%s', prevItemNameLeft ) ).text( thisLinkText ).css( 'display', 'inline' ); } if ( 0 !== position ) { if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) { thisLink = menuItem.find( '.menus-move-right' ), thisLinkText = menus.under.replace( '%s', prevItemNameRight ); thisLink.attr( 'aria-label', menus.moveUnder.replace( '%s', prevItemNameRight ) ).text( thisLinkText ).css( 'display', 'inline' ); } } if ( isPrimaryMenuItem ) { primaryItems = $( '.menu-item-depth-0' ), itemPosition = primaryItems.index( menuItem ) + 1, totalMenuItems = primaryItems.length, // String together help text for primary menu items. title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$d', totalMenuItems ); } else { parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(), parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(), parentItemName = parentItem.find( '.menu-item-title' ).text(), subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ), itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1; // String together help text for sub menu items. title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$s', parentItemName ); } $this.attr( 'aria-label', title ); // Mark this item's accessibility as refreshed. $this.data( 'needs_accessibility_refresh', false ); }, /** * refreshAdvancedAccessibility * * Hides all advanced accessibility buttons and marks them for refreshing. */ refreshAdvancedAccessibility : function() { // Hide all the move buttons by default. $( '.menu-item-settings .field-move .menus-move' ).hide(); // Mark all menu items as unprocessed. $( 'a.item-edit' ).data( 'needs_accessibility_refresh', true ); // All open items have to be refreshed or they will show no links. $( '.menu-item-edit-active a.item-edit' ).each( function() { api.refreshAdvancedAccessibilityOfItem( this ); } ); }, refreshKeyboardAccessibility : function() { $( 'a.item-edit' ).off( 'focus' ).on( 'focus', function(){ $(this).off( 'keydown' ).on( 'keydown', function(e){ var arrows, $this = $( this ), thisItem = $this.parents( 'li.menu-item' ), thisItemData = thisItem.getItemData(); // Bail if it's not an arrow key. if ( 37 != e.which && 38 != e.which && 39 != e.which && 40 != e.which ) return; // Avoid multiple keydown events. $this.off('keydown'); // Bail if there is only one menu item. if ( 1 === $('#menu-to-edit li').length ) return; // If RTL, swap left/right arrows. arrows = { '38': 'up', '40': 'down', '37': 'left', '39': 'right' }; if ( $('body').hasClass('rtl') ) arrows = { '38' : 'up', '40' : 'down', '39' : 'left', '37' : 'right' }; switch ( arrows[e.which] ) { case 'up': api.moveMenuItem( $this, 'up' ); break; case 'down': api.moveMenuItem( $this, 'down' ); break; case 'left': api.moveMenuItem( $this, 'left' ); break; case 'right': api.moveMenuItem( $this, 'right' ); break; } // Put focus back on same menu item. $( '#edit-' + thisItemData['menu-item-db-id'] ).trigger( 'focus' ); return false; }); }); }, initPreviewing : function() { // Update the item handle title when the navigation label is changed. $( '#menu-to-edit' ).on( 'change input', '.edit-menu-item-title', function(e) { var input = $( e.currentTarget ), title, titleEl; title = input.val(); titleEl = input.closest( '.menu-item' ).find( '.menu-item-title' ); // Don't update to empty title. if ( title ) { titleEl.text( title ).removeClass( 'no-title' ); } else { titleEl.text( wp.i18n._x( '(no label)', 'missing menu item navigation label' ) ).addClass( 'no-title' ); } } ); }, initToggles : function() { // Init postboxes. postboxes.add_postbox_toggles('nav-menus'); // Adjust columns functions for menus UI. columns.useCheckboxesForHidden(); columns.checked = function(field) { $('.field-' + field).removeClass('hidden-field'); }; columns.unchecked = function(field) { $('.field-' + field).addClass('hidden-field'); }; // Hide fields. api.menuList.hideAdvancedMenuItemFields(); $('.hide-postbox-tog').on( 'click', function () { var hidden = $( '.accordion-container li.accordion-section' ).filter(':hidden').map(function() { return this.id; }).get().join(','); $.post(ajaxurl, { action: 'closed-postboxes', hidden: hidden, closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(), page: 'nav-menus' }); }); }, initSortables : function() { var currentDepth = 0, originalDepth, minDepth, maxDepth, prev, next, prevBottom, nextThreshold, helperHeight, transport, menuEdge = api.menuList.offset().left, body = $('body'), maxChildDepth, menuMaxDepth = initialMenuMaxDepth(); if( 0 !== $( '#menu-to-edit li' ).length ) $( '.drag-instructions' ).show(); // Use the right edge if RTL. menuEdge += api.isRTL ? api.menuList.width() : 0; api.menuList.sortable({ handle: '.menu-item-handle', placeholder: 'sortable-placeholder', items: api.options.sortableItems, start: function(e, ui) { var height, width, parent, children, tempHolder; // Handle placement for RTL orientation. if ( api.isRTL ) ui.item[0].style.right = 'auto'; transport = ui.item.children('.menu-item-transport'); // Set depths. currentDepth must be set before children are located. originalDepth = ui.item.menuItemDepth(); updateCurrentDepth(ui, originalDepth); // Attach child elements to parent. // Skip the placeholder. parent = ( ui.item.next()[0] == ui.placeholder[0] ) ? ui.item.next() : ui.item; children = parent.childMenuItems(); transport.append( children ); // Update the height of the placeholder to match the moving item. height = transport.outerHeight(); // If there are children, account for distance between top of children and parent. height += ( height > 0 ) ? (ui.placeholder.css('margin-top').slice(0, -2) * 1) : 0; height += ui.helper.outerHeight(); helperHeight = height; height -= 2; // Subtract 2 for borders. ui.placeholder.height(height); // Update the width of the placeholder to match the moving item. maxChildDepth = originalDepth; children.each(function(){ var depth = $(this).menuItemDepth(); maxChildDepth = (depth > maxChildDepth) ? depth : maxChildDepth; }); width = ui.helper.find('.menu-item-handle').outerWidth(); // Get original width. width += api.depthToPx(maxChildDepth - originalDepth); // Account for children. width -= 2; // Subtract 2 for borders. ui.placeholder.width(width); // Update the list of menu items. tempHolder = ui.placeholder.next( '.menu-item' ); tempHolder.css( 'margin-top', helperHeight + 'px' ); // Set the margin to absorb the placeholder. ui.placeholder.detach(); // Detach or jQuery UI will think the placeholder is a menu item. $(this).sortable( 'refresh' ); // The children aren't sortable. We should let jQuery UI know. ui.item.after( ui.placeholder ); // Reattach the placeholder. tempHolder.css('margin-top', 0); // Reset the margin. // Now that the element is complete, we can update... updateSharedVars(ui); }, stop: function(e, ui) { var children, subMenuTitle, depthChange = currentDepth - originalDepth; // Return child elements to the list. children = transport.children().insertAfter(ui.item); // Add "sub menu" description. subMenuTitle = ui.item.find( '.item-title .is-submenu' ); if ( 0 < currentDepth ) subMenuTitle.show(); else subMenuTitle.hide(); // Update depth classes. if ( 0 !== depthChange ) { ui.item.updateDepthClass( currentDepth ); children.shiftDepthClass( depthChange ); updateMenuMaxDepth( depthChange ); } // Register a change. api.registerChange(); // Update the item data. ui.item.updateParentMenuItemDBId(); // Address sortable's incorrectly-calculated top in Opera. ui.item[0].style.top = 0; // Handle drop placement for rtl orientation. if ( api.isRTL ) { ui.item[0].style.left = 'auto'; ui.item[0].style.right = 0; } api.refreshKeyboardAccessibility(); api.refreshAdvancedAccessibility(); }, change: function(e, ui) { // Make sure the placeholder is inside the menu. // Otherwise fix it, or we're in trouble. if( ! ui.placeholder.parent().hasClass('menu') ) (prev.length) ? prev.after( ui.placeholder ) : api.menuList.prepend( ui.placeholder ); updateSharedVars(ui); }, sort: function(e, ui) { var offset = ui.helper.offset(), edge = api.isRTL ? offset.left + ui.helper.width() : offset.left, depth = api.negateIfRTL * api.pxToDepth( edge - menuEdge ); /* * Check and correct if depth is not within range. * Also, if the dragged element is dragged upwards over an item, * shift the placeholder to a child position. */ if ( depth > maxDepth || offset.top < ( prevBottom - api.options.targetTolerance ) ) { depth = maxDepth; } else if ( depth < minDepth ) { depth = minDepth; } if( depth != currentDepth ) updateCurrentDepth(ui, depth); // If we overlap the next element, manually shift downwards. if( nextThreshold && offset.top + helperHeight > nextThreshold ) { next.after( ui.placeholder ); updateSharedVars( ui ); $( this ).sortable( 'refreshPositions' ); } } }); function updateSharedVars(ui) { var depth; prev = ui.placeholder.prev( '.menu-item' ); next = ui.placeholder.next( '.menu-item' ); // Make sure we don't select the moving item. if( prev[0] == ui.item[0] ) prev = prev.prev( '.menu-item' ); if( next[0] == ui.item[0] ) next = next.next( '.menu-item' ); prevBottom = (prev.length) ? prev.offset().top + prev.height() : 0; nextThreshold = (next.length) ? next.offset().top + next.height() / 3 : 0; minDepth = (next.length) ? next.menuItemDepth() : 0; if( prev.length ) maxDepth = ( (depth = prev.menuItemDepth() + 1) > api.options.globalMaxDepth ) ? api.options.globalMaxDepth : depth; else maxDepth = 0; } function updateCurrentDepth(ui, depth) { ui.placeholder.updateDepthClass( depth, currentDepth ); currentDepth = depth; } function initialMenuMaxDepth() { if( ! body[0].className ) return 0; var match = body[0].className.match(/menu-max-depth-(\d+)/); return match && match[1] ? parseInt( match[1], 10 ) : 0; } function updateMenuMaxDepth( depthChange ) { var depth, newDepth = menuMaxDepth; if ( depthChange === 0 ) { return; } else if ( depthChange > 0 ) { depth = maxChildDepth + depthChange; if( depth > menuMaxDepth ) newDepth = depth; } else if ( depthChange < 0 && maxChildDepth == menuMaxDepth ) { while( ! $('.menu-item-depth-' + newDepth, api.menuList).length && newDepth > 0 ) newDepth--; } // Update the depth class. body.removeClass( 'menu-max-depth-' + menuMaxDepth ).addClass( 'menu-max-depth-' + newDepth ); menuMaxDepth = newDepth; } }, initManageLocations : function () { $('#menu-locations-wrap form').on( 'submit', function(){ window.onbeforeunload = null; }); $('.menu-location-menus select').on('change', function () { var editLink = $(this).closest('tr').find('.locations-edit-menu-link'); if ($(this).find('option:selected').data('orig')) editLink.show(); else editLink.hide(); }); }, attachMenuEditListeners : function() { var that = this; $('#update-nav-menu').on('click', function(e) { if ( e.target && e.target.className ) { if ( -1 != e.target.className.indexOf('item-edit') ) { return that.eventOnClickEditLink(e.target); } else if ( -1 != e.target.className.indexOf('menu-save') ) { return that.eventOnClickMenuSave(e.target); } else if ( -1 != e.target.className.indexOf('menu-delete') ) { return that.eventOnClickMenuDelete(e.target); } else if ( -1 != e.target.className.indexOf('item-delete') ) { return that.eventOnClickMenuItemDelete(e.target); } else if ( -1 != e.target.className.indexOf('item-cancel') ) { return that.eventOnClickCancelLink(e.target); } } }); $( '#menu-name' ).on( 'input', _.debounce( function () { var menuName = $( document.getElementById( 'menu-name' ) ), menuNameVal = menuName.val(); if ( ! menuNameVal || ! menuNameVal.replace( /\s+/, '' ) ) { // Add warning for invalid menu name. menuName.parent().addClass( 'form-invalid' ); } else { // Remove warning for valid menu name. menuName.parent().removeClass( 'form-invalid' ); } }, 500 ) ); $('#add-custom-links input[type="text"]').on( 'keypress', function(e){ $('#customlinkdiv').removeClass('form-invalid'); if ( e.keyCode === 13 ) { e.preventDefault(); $( '#submit-customlinkdiv' ).trigger( 'click' ); } }); }, /** * Handle toggling bulk selection checkboxes for menu items. * * @since 5.8.0 */ attachBulkSelectButtonListeners : function() { var that = this; $( '.bulk-select-switcher' ).on( 'change', function() { if ( this.checked ) { $( '.bulk-select-switcher' ).prop( 'checked', true ); that.enableBulkSelection(); } else { $( '.bulk-select-switcher' ).prop( 'checked', false ); that.disableBulkSelection(); } }); }, /** * Enable bulk selection checkboxes for menu items. * * @since 5.8.0 */ enableBulkSelection : function() { var checkbox = $( '#menu-to-edit .menu-item-checkbox' ); $( '#menu-to-edit' ).addClass( 'bulk-selection' ); $( '#nav-menu-bulk-actions-top' ).addClass( 'bulk-selection' ); $( '#nav-menu-bulk-actions-bottom' ).addClass( 'bulk-selection' ); $.each( checkbox, function() { $(this).prop( 'disabled', false ); }); }, /** * Disable bulk selection checkboxes for menu items. * * @since 5.8.0 */ disableBulkSelection : function() { var checkbox = $( '#menu-to-edit .menu-item-checkbox' ); $( '#menu-to-edit' ).removeClass( 'bulk-selection' ); $( '#nav-menu-bulk-actions-top' ).removeClass( 'bulk-selection' ); $( '#nav-menu-bulk-actions-bottom' ).removeClass( 'bulk-selection' ); if ( $( '.menu-items-delete' ).is( '[aria-describedby="pending-menu-items-to-delete"]' ) ) { $( '.menu-items-delete' ).removeAttr( 'aria-describedby' ); } $.each( checkbox, function() { $(this).prop( 'disabled', true ).prop( 'checked', false ); }); $( '.menu-items-delete' ).addClass( 'disabled' ); $( '#pending-menu-items-to-delete ul' ).empty(); }, /** * Listen for state changes on bulk action checkboxes. * * @since 5.8.0 */ attachMenuCheckBoxListeners : function() { var that = this; $( '#menu-to-edit' ).on( 'change', '.menu-item-checkbox', function() { that.setRemoveSelectedButtonStatus(); }); }, /** * Create delete button to remove menu items from collection. * * @since 5.8.0 */ attachMenuItemDeleteButton : function() { var that = this; $( document ).on( 'click', '.menu-items-delete', function( e ) { var itemsPendingDeletion, itemsPendingDeletionList, deletionSpeech; e.preventDefault(); if ( ! $(this).hasClass( 'disabled' ) ) { $.each( $( '.menu-item-checkbox:checked' ), function( index, element ) { $( element ).parents( 'li' ).find( 'a.item-delete' ).trigger( 'click' ); }); $( '.menu-items-delete' ).addClass( 'disabled' ); $( '.bulk-select-switcher' ).prop( 'checked', false ); itemsPendingDeletion = ''; itemsPendingDeletionList = $( '#pending-menu-items-to-delete ul li' ); $.each( itemsPendingDeletionList, function( index, element ) { var itemName = $( element ).find( '.pending-menu-item-name' ).text(); var itemSpeech = menus.menuItemDeletion.replace( '%s', itemName ); itemsPendingDeletion += itemSpeech; if ( ( index + 1 ) < itemsPendingDeletionList.length ) { itemsPendingDeletion += ', '; } }); deletionSpeech = menus.itemsDeleted.replace( '%s', itemsPendingDeletion ); wp.a11y.speak( deletionSpeech, 'polite' ); that.disableBulkSelection(); } }); }, /** * List menu items awaiting deletion. * * @since 5.8.0 */ attachPendingMenuItemsListForDeletion : function() { $( '#post-body-content' ).on( 'change', '.menu-item-checkbox', function() { var menuItemName, menuItemType, menuItemID, listedMenuItem; if ( ! $( '.menu-items-delete' ).is( '[aria-describedby="pending-menu-items-to-delete"]' ) ) { $( '.menu-items-delete' ).attr( 'aria-describedby', 'pending-menu-items-to-delete' ); } menuItemName = $(this).next().text(); menuItemType = $(this).parent().next( '.item-controls' ).find( '.item-type' ).text(); menuItemID = $(this).attr( 'data-menu-item-id' ); listedMenuItem = $( '#pending-menu-items-to-delete ul' ).find( '[data-menu-item-id=' + menuItemID + ']' ); if ( listedMenuItem.length > 0 ) { listedMenuItem.remove(); } if ( this.checked === true ) { $( '#pending-menu-items-to-delete ul' ).append( '<li data-menu-item-id="' + menuItemID + '">' + '<span class="pending-menu-item-name">' + menuItemName + '</span> ' + '<span class="pending-menu-item-type">(' + menuItemType + ')</span>' + '<span class="separator"></span>' + '</li>' ); } $( '#pending-menu-items-to-delete li .separator' ).html( ', ' ); $( '#pending-menu-items-to-delete li .separator' ).last().html( '.' ); }); }, /** * Set status of bulk delete checkbox. * * @since 5.8.0 */ setBulkDeleteCheckboxStatus : function() { var that = this; var checkbox = $( '#menu-to-edit .menu-item-checkbox' ); $.each( checkbox, function() { if ( $(this).prop( 'disabled' ) ) { $(this).prop( 'disabled', false ); } else { $(this).prop( 'disabled', true ); } if ( $(this).is( ':checked' ) ) { $(this).prop( 'checked', false ); } }); that.setRemoveSelectedButtonStatus(); }, /** * Set status of menu items removal button. * * @since 5.8.0 */ setRemoveSelectedButtonStatus : function() { var button = $( '.menu-items-delete' ); if ( $( '.menu-item-checkbox:checked' ).length > 0 ) { button.removeClass( 'disabled' ); } else { button.addClass( 'disabled' ); } }, attachMenuSaveSubmitListeners : function() { /* * When a navigation menu is saved, store a JSON representation of all form data * in a single input to avoid PHP `max_input_vars` limitations. See #14134. */ $( '#update-nav-menu' ).on( 'submit', function() { var navMenuData = $( '#update-nav-menu' ).serializeArray(); $( '[name="nav-menu-data"]' ).val( JSON.stringify( navMenuData ) ); }); }, attachThemeLocationsListeners : function() { var loc = $('#nav-menu-theme-locations'), params = {}; params.action = 'menu-locations-save'; params['menu-settings-column-nonce'] = $('#menu-settings-column-nonce').val(); loc.find('input[type="submit"]').on( 'click', function() { loc.find('select').each(function() { params[this.name] = $(this).val(); }); loc.find( '.spinner' ).addClass( 'is-active' ); $.post( ajaxurl, params, function() { loc.find( '.spinner' ).removeClass( 'is-active' ); }); return false; }); }, attachQuickSearchListeners : function() { var searchTimer; // Prevent form submission. $( '#nav-menu-meta' ).on( 'submit', function( event ) { event.preventDefault(); }); $( '#nav-menu-meta' ).on( 'input', '.quick-search', function() { var $this = $( this ); $this.attr( 'autocomplete', 'off' ); if ( searchTimer ) { clearTimeout( searchTimer ); } searchTimer = setTimeout( function() { api.updateQuickSearchResults( $this ); }, 500 ); }).on( 'blur', '.quick-search', function() { api.lastSearch = ''; }); }, updateQuickSearchResults : function(input) { var panel, params, minSearchLength = 2, q = input.val(); /* * Minimum characters for a search. Also avoid a new Ajax search when * the pressed key (e.g. arrows) doesn't change the searched term. */ if ( q.length < minSearchLength || api.lastSearch == q ) { return; } api.lastSearch = q; panel = input.parents('.tabs-panel'); params = { 'action': 'menu-quick-search', 'response-format': 'markup', 'menu': $('#menu').val(), 'menu-settings-column-nonce': $('#menu-settings-column-nonce').val(), 'q': q, 'type': input.attr('name') }; $( '.spinner', panel ).addClass( 'is-active' ); $.post( ajaxurl, params, function(menuMarkup) { api.processQuickSearchQueryResponse(menuMarkup, params, panel); }); }, addCustomLink : function( processMethod ) { var url = $('#custom-menu-item-url').val().toString(), label = $('#custom-menu-item-name').val(); if ( '' !== url ) { url = url.trim(); } processMethod = processMethod || api.addMenuItemToBottom; if ( '' === url || 'https://' == url || 'http://' == url ) { $('#customlinkdiv').addClass('form-invalid'); return false; } // Show the Ajax spinner. $( '.customlinkdiv .spinner' ).addClass( 'is-active' ); this.addLinkToMenu( url, label, processMethod, function() { // Remove the Ajax spinner. $( '.customlinkdiv .spinner' ).removeClass( 'is-active' ); // Set custom link form back to defaults. $('#custom-menu-item-name').val('').trigger( 'blur' ); $( '#custom-menu-item-url' ).val( '' ).attr( 'placeholder', 'https://' ); }); }, addLinkToMenu : function(url, label, processMethod, callback) { processMethod = processMethod || api.addMenuItemToBottom; callback = callback || function(){}; api.addItemToMenu({ '-1': { 'menu-item-type': 'custom', 'menu-item-url': url, 'menu-item-title': label } }, processMethod, callback); }, addItemToMenu : function(menuItem, processMethod, callback) { var menu = $('#menu').val(), nonce = $('#menu-settings-column-nonce').val(), params; processMethod = processMethod || function(){}; callback = callback || function(){}; params = { 'action': 'add-menu-item', 'menu': menu, 'menu-settings-column-nonce': nonce, 'menu-item': menuItem }; $.post( ajaxurl, params, function(menuMarkup) { var ins = $('#menu-instructions'); menuMarkup = menuMarkup || ''; menuMarkup = menuMarkup.toString().trim(); // Trim leading whitespaces. processMethod(menuMarkup, params); // Make it stand out a bit more visually, by adding a fadeIn. $( 'li.pending' ).hide().fadeIn('slow'); $( '.drag-instructions' ).show(); if( ! ins.hasClass( 'menu-instructions-inactive' ) && ins.siblings().length ) ins.addClass( 'menu-instructions-inactive' ); callback(); }); }, /** * Process the add menu item request response into menu list item. Appends to menu. * * @param {string} menuMarkup The text server response of menu item markup. * * @fires document#menu-item-added Passes menuMarkup as a jQuery object. */ addMenuItemToBottom : function( menuMarkup ) { var $menuMarkup = $( menuMarkup ); $menuMarkup.hideAdvancedMenuItemFields().appendTo( api.targetList ); api.refreshKeyboardAccessibility(); api.refreshAdvancedAccessibility(); wp.a11y.speak( menus.itemAdded ); $( document ).trigger( 'menu-item-added', [ $menuMarkup ] ); }, /** * Process the add menu item request response into menu list item. Prepends to menu. * * @param {string} menuMarkup The text server response of menu item markup. * * @fires document#menu-item-added Passes menuMarkup as a jQuery object. */ addMenuItemToTop : function( menuMarkup ) { var $menuMarkup = $( menuMarkup ); $menuMarkup.hideAdvancedMenuItemFields().prependTo( api.targetList ); api.refreshKeyboardAccessibility(); api.refreshAdvancedAccessibility(); wp.a11y.speak( menus.itemAdded ); $( document ).trigger( 'menu-item-added', [ $menuMarkup ] ); }, attachUnsavedChangesListener : function() { $('#menu-management input, #menu-management select, #menu-management, #menu-management textarea, .menu-location-menus select').on( 'change', function(){ api.registerChange(); }); if ( 0 !== $('#menu-to-edit').length || 0 !== $('.menu-location-menus select').length ) { window.onbeforeunload = function(){ if ( api.menusChanged ) return wp.i18n.__( 'The changes you made will be lost if you navigate away from this page.' ); }; } else { // Make the post boxes read-only, as they can't be used yet. $( '#menu-settings-column' ).find( 'input,select' ).end().find( 'a' ).attr( 'href', '#' ).off( 'click' ); } }, registerChange : function() { api.menusChanged = true; }, attachTabsPanelListeners : function() { $('#menu-settings-column').on('click', function(e) { var selectAreaMatch, selectAll, panelId, wrapper, items, target = $(e.target); if ( target.hasClass('nav-tab-link') ) { panelId = target.data( 'type' ); wrapper = target.parents('.accordion-section-content').first(); // Upon changing tabs, we want to uncheck all checkboxes. $( 'input', wrapper ).prop( 'checked', false ); $('.tabs-panel-active', wrapper).removeClass('tabs-panel-active').addClass('tabs-panel-inactive'); $('#' + panelId, wrapper).removeClass('tabs-panel-inactive').addClass('tabs-panel-active'); $('.tabs', wrapper).removeClass('tabs'); target.parent().addClass('tabs'); // Select the search bar. $('.quick-search', wrapper).trigger( 'focus' ); // Hide controls in the search tab if no items found. if ( ! wrapper.find( '.tabs-panel-active .menu-item-title' ).length ) { wrapper.addClass( 'has-no-menu-item' ); } else { wrapper.removeClass( 'has-no-menu-item' ); } e.preventDefault(); } else if ( target.hasClass( 'select-all' ) ) { selectAreaMatch = target.closest( '.button-controls' ).data( 'items-type' ); if ( selectAreaMatch ) { items = $( '#' + selectAreaMatch + ' .tabs-panel-active .menu-item-title input' ); if ( items.length === items.filter( ':checked' ).length && ! target.is( ':checked' ) ) { items.prop( 'checked', false ); } else if ( target.is( ':checked' ) ) { items.prop( 'checked', true ); } } } else if ( target.hasClass( 'menu-item-checkbox' ) ) { selectAreaMatch = target.closest( '.tabs-panel-active' ).parent().attr( 'id' ); if ( selectAreaMatch ) { items = $( '#' + selectAreaMatch + ' .tabs-panel-active .menu-item-title input' ); selectAll = $( '.button-controls[data-items-type="' + selectAreaMatch + '"] .select-all' ); if ( items.length === items.filter( ':checked' ).length && ! selectAll.is( ':checked' ) ) { selectAll.prop( 'checked', true ); } else if ( selectAll.is( ':checked' ) ) { selectAll.prop( 'checked', false ); } } } else if ( target.hasClass('submit-add-to-menu') ) { api.registerChange(); if ( e.target.id && 'submit-customlinkdiv' == e.target.id ) api.addCustomLink( api.addMenuItemToBottom ); else if ( e.target.id && -1 != e.target.id.indexOf('submit-') ) $('#' + e.target.id.replace(/submit-/, '')).addSelectedToMenu( api.addMenuItemToBottom ); return false; } }); /* * Delegate the `click` event and attach it just to the pagination * links thus excluding the current page `<span>`. See ticket #35577. */ $( '#nav-menu-meta' ).on( 'click', 'a.page-numbers', function() { var $container = $( this ).closest( '.inside' ); $.post( ajaxurl, this.href.replace( /.*\?/, '' ).replace( /action=([^&]*)/, '' ) + '&action=menu-get-metabox', function( resp ) { var metaBoxData = JSON.parse( resp ), toReplace; if ( -1 === resp.indexOf( 'replace-id' ) ) { return; } // Get the post type menu meta box to update. toReplace = document.getElementById( metaBoxData['replace-id'] ); if ( ! metaBoxData.markup || ! toReplace ) { return; } // Update the post type menu meta box with new content from the response. $container.html( metaBoxData.markup ); } ); return false; }); }, eventOnClickEditLink : function(clickedEl) { var settings, item, matchedSection = /#(.*)$/.exec(clickedEl.href); if ( matchedSection && matchedSection[1] ) { settings = $('#'+matchedSection[1]); item = settings.parent(); if( 0 !== item.length ) { if( item.hasClass('menu-item-edit-inactive') ) { if( ! settings.data('menu-item-data') ) { settings.data( 'menu-item-data', settings.getItemData() ); } settings.slideDown('fast'); item.removeClass('menu-item-edit-inactive') .addClass('menu-item-edit-active'); } else { settings.slideUp('fast'); item.removeClass('menu-item-edit-active') .addClass('menu-item-edit-inactive'); } return false; } } }, eventOnClickCancelLink : function(clickedEl) { var settings = $( clickedEl ).closest( '.menu-item-settings' ), thisMenuItem = $( clickedEl ).closest( '.menu-item' ); thisMenuItem.removeClass( 'menu-item-edit-active' ).addClass( 'menu-item-edit-inactive' ); settings.setItemData( settings.data( 'menu-item-data' ) ).hide(); // Restore the title of the currently active/expanded menu item. thisMenuItem.find( '.menu-item-title' ).text( settings.data( 'menu-item-data' )['menu-item-title'] ); return false; }, eventOnClickMenuSave : function() { var locs = '', menuName = $('#menu-name'), menuNameVal = menuName.val(); // Cancel and warn if invalid menu name. if ( ! menuNameVal || ! menuNameVal.replace( /\s+/, '' ) ) { menuName.parent().addClass( 'form-invalid' ); return false; } // Copy menu theme locations. $('#nav-menu-theme-locations select').each(function() { locs += '<input type="hidden" name="' + this.name + '" value="' + $(this).val() + '" />'; }); $('#update-nav-menu').append( locs ); // Update menu item position data. api.menuList.find('.menu-item-data-position').val( function(index) { return index + 1; } ); window.onbeforeunload = null; return true; }, eventOnClickMenuDelete : function() { // Delete warning AYS. if ( window.confirm( wp.i18n.__( 'You are about to permanently delete this menu.\n\'Cancel\' to stop, \'OK\' to delete.' ) ) ) { window.onbeforeunload = null; return true; } return false; }, eventOnClickMenuItemDelete : function(clickedEl) { var itemID = parseInt(clickedEl.id.replace('delete-', ''), 10); api.removeMenuItem( $('#menu-item-' + itemID) ); api.registerChange(); return false; }, /** * Process the quick search response into a search result * * @param string resp The server response to the query. * @param object req The request arguments. * @param jQuery panel The tabs panel we're searching in. */ processQuickSearchQueryResponse : function(resp, req, panel) { var matched, newID, takenIDs = {}, form = document.getElementById('nav-menu-meta'), pattern = /menu-item[(\[^]\]*/, $items = $('<div>').html(resp).find('li'), wrapper = panel.closest( '.accordion-section-content' ), selectAll = wrapper.find( '.button-controls .select-all' ), $item; if( ! $items.length ) { $('.categorychecklist', panel).html( '<li><p>' + wp.i18n.__( 'No results found.' ) + '</p></li>' ); $( '.spinner', panel ).removeClass( 'is-active' ); wrapper.addClass( 'has-no-menu-item' ); return; } $items.each(function(){ $item = $(this); // Make a unique DB ID number. matched = pattern.exec($item.html()); if ( matched && matched[1] ) { newID = matched[1]; while( form.elements['menu-item[' + newID + '][menu-item-type]'] || takenIDs[ newID ] ) { newID--; } takenIDs[newID] = true; if ( newID != matched[1] ) { $item.html( $item.html().replace(new RegExp( 'menu-item\\[' + matched[1] + '\\]', 'g'), 'menu-item[' + newID + ']' ) ); } } }); $('.categorychecklist', panel).html( $items ); $( '.spinner', panel ).removeClass( 'is-active' ); wrapper.removeClass( 'has-no-menu-item' ); if ( selectAll.is( ':checked' ) ) { selectAll.prop( 'checked', false ); } }, /** * Remove a menu item. * * @param {Object} el The element to be removed as a jQuery object. * * @fires document#menu-removing-item Passes the element to be removed. */ removeMenuItem : function(el) { var children = el.childMenuItems(); $( document ).trigger( 'menu-removing-item', [ el ] ); el.addClass('deleting').animate({ opacity : 0, height: 0 }, 350, function() { var ins = $('#menu-instructions'); el.remove(); children.shiftDepthClass( -1 ).updateParentMenuItemDBId(); if ( 0 === $( '#menu-to-edit li' ).length ) { $( '.drag-instructions' ).hide(); ins.removeClass( 'menu-instructions-inactive' ); } api.refreshAdvancedAccessibility(); wp.a11y.speak( menus.itemRemoved ); }); }, depthToPx : function(depth) { return depth * api.options.menuItemDepthPerLevel; }, pxToDepth : function(px) { return Math.floor(px / api.options.menuItemDepthPerLevel); } }; $( function() { wpNavMenu.init(); // Prevent focused element from being hidden by the sticky footer. $( '.menu-edit a, .menu-edit button, .menu-edit input, .menu-edit textarea, .menu-edit select' ).on('focus', function() { if ( window.innerWidth >= 783 ) { var navMenuHeight = $( '#nav-menu-footer' ).height() + 20; var bottomOffset = $(this).offset().top - ( $(window).scrollTop() + $(window).height() - $(this).height() ); if ( bottomOffset > 0 ) { bottomOffset = 0; } bottomOffset = bottomOffset * -1; if( bottomOffset < navMenuHeight ) { var scrollTop = $(document).scrollTop(); $(document).scrollTop( scrollTop + ( navMenuHeight - bottomOffset ) ); } } }); }); })(jQuery);