media-views.js 265 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491
  1. /******/ (function() { // webpackBootstrap
  2. /******/ var __webpack_modules__ = ({
  3. /***/ 1517:
  4. /***/ (function(module) {
  5. var Selection = wp.media.model.Selection,
  6. Library = wp.media.controller.Library,
  7. CollectionAdd;
  8. /**
  9. * wp.media.controller.CollectionAdd
  10. *
  11. * A state for adding attachments to a collection (e.g. video playlist).
  12. *
  13. * @memberOf wp.media.controller
  14. *
  15. * @class
  16. * @augments wp.media.controller.Library
  17. * @augments wp.media.controller.State
  18. * @augments Backbone.Model
  19. *
  20. * @param {object} [attributes] The attributes hash passed to the state.
  21. * @param {string} [attributes.id=library] Unique identifier.
  22. * @param {string} attributes.title Title for the state. Displays in the frame's title region.
  23. * @param {boolean} [attributes.multiple=add] Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
  24. * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse.
  25. * If one is not supplied, a collection of attachments of the specified type will be created.
  26. * @param {boolean|string} [attributes.filterable=uploaded] Whether the library is filterable, and if so what filters should be shown.
  27. * Accepts 'all', 'uploaded', or 'unattached'.
  28. * @param {string} [attributes.menu=gallery] Initial mode for the menu region.
  29. * @param {string} [attributes.content=upload] Initial mode for the content region.
  30. * Overridden by persistent user setting if 'contentUserSetting' is true.
  31. * @param {string} [attributes.router=browse] Initial mode for the router region.
  32. * @param {string} [attributes.toolbar=gallery-add] Initial mode for the toolbar region.
  33. * @param {boolean} [attributes.searchable=true] Whether the library is searchable.
  34. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  35. * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection.
  36. * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
  37. * @param {int} [attributes.priority=100] The priority for the state link in the media menu.
  38. * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state.
  39. * Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
  40. * @param {string} attributes.type The collection's media type. (e.g. 'video').
  41. * @param {string} attributes.collectionType The collection type. (e.g. 'playlist').
  42. */
  43. CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{
  44. defaults: _.defaults( {
  45. // Selection defaults. @see media.model.Selection
  46. multiple: 'add',
  47. // Attachments browser defaults. @see media.view.AttachmentsBrowser
  48. filterable: 'uploaded',
  49. priority: 100,
  50. syncSelection: false
  51. }, Library.prototype.defaults ),
  52. /**
  53. * @since 3.9.0
  54. */
  55. initialize: function() {
  56. var collectionType = this.get('collectionType');
  57. if ( 'video' === this.get( 'type' ) ) {
  58. collectionType = 'video-' + collectionType;
  59. }
  60. this.set( 'id', collectionType + '-library' );
  61. this.set( 'toolbar', collectionType + '-add' );
  62. this.set( 'menu', collectionType );
  63. // If we haven't been provided a `library`, create a `Selection`.
  64. if ( ! this.get('library') ) {
  65. this.set( 'library', wp.media.query({ type: this.get('type') }) );
  66. }
  67. Library.prototype.initialize.apply( this, arguments );
  68. },
  69. /**
  70. * @since 3.9.0
  71. */
  72. activate: function() {
  73. var library = this.get('library'),
  74. editLibrary = this.get('editLibrary'),
  75. edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library');
  76. if ( editLibrary && editLibrary !== edit ) {
  77. library.unobserve( editLibrary );
  78. }
  79. // Accepts attachments that exist in the original library and
  80. // that do not exist in gallery's library.
  81. library.validator = function( attachment ) {
  82. return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
  83. };
  84. /*
  85. * Reset the library to ensure that all attachments are re-added
  86. * to the collection. Do so silently, as calling `observe` will
  87. * trigger the `reset` event.
  88. */
  89. library.reset( library.mirroring.models, { silent: true });
  90. library.observe( edit );
  91. this.set('editLibrary', edit);
  92. Library.prototype.activate.apply( this, arguments );
  93. }
  94. });
  95. module.exports = CollectionAdd;
  96. /***/ }),
  97. /***/ 1817:
  98. /***/ (function(module) {
  99. var Library = wp.media.controller.Library,
  100. l10n = wp.media.view.l10n,
  101. $ = jQuery,
  102. CollectionEdit;
  103. /**
  104. * wp.media.controller.CollectionEdit
  105. *
  106. * A state for editing a collection, which is used by audio and video playlists,
  107. * and can be used for other collections.
  108. *
  109. * @memberOf wp.media.controller
  110. *
  111. * @class
  112. * @augments wp.media.controller.Library
  113. * @augments wp.media.controller.State
  114. * @augments Backbone.Model
  115. *
  116. * @param {object} [attributes] The attributes hash passed to the state.
  117. * @param {string} attributes.title Title for the state. Displays in the media menu and the frame's title region.
  118. * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to edit.
  119. * If one is not supplied, an empty media.model.Selection collection is created.
  120. * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled.
  121. * @param {string} [attributes.content=browse] Initial mode for the content region.
  122. * @param {string} attributes.menu Initial mode for the menu region. @todo this needs a better explanation.
  123. * @param {boolean} [attributes.searchable=false] Whether the library is searchable.
  124. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  125. * @param {boolean} [attributes.date=true] Whether to show the date filter in the browser's toolbar.
  126. * @param {boolean} [attributes.describe=true] Whether to offer UI to describe the attachments - e.g. captioning images in a gallery.
  127. * @param {boolean} [attributes.dragInfo=true] Whether to show instructional text about the attachments being sortable.
  128. * @param {boolean} [attributes.dragInfoText] Instructional text about the attachments being sortable.
  129. * @param {int} [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments.
  130. * @param {boolean} [attributes.editing=false] Whether the gallery is being created, or editing an existing instance.
  131. * @param {int} [attributes.priority=60] The priority for the state link in the media menu.
  132. * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state.
  133. * Defaults to false for this state, because the library passed in *is* the selection.
  134. * @param {view} [attributes.SettingsView] The view to edit the collection instance settings (e.g. Playlist settings with "Show tracklist" checkbox).
  135. * @param {view} [attributes.AttachmentView] The single `Attachment` view to be used in the `Attachments`.
  136. * If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
  137. * @param {string} attributes.type The collection's media type. (e.g. 'video').
  138. * @param {string} attributes.collectionType The collection type. (e.g. 'playlist').
  139. */
  140. CollectionEdit = Library.extend(/** @lends wp.media.controller.CollectionEdit.prototype */{
  141. defaults: {
  142. multiple: false,
  143. sortable: true,
  144. date: false,
  145. searchable: false,
  146. content: 'browse',
  147. describe: true,
  148. dragInfo: true,
  149. idealColumnWidth: 170,
  150. editing: false,
  151. priority: 60,
  152. SettingsView: false,
  153. syncSelection: false
  154. },
  155. /**
  156. * @since 3.9.0
  157. */
  158. initialize: function() {
  159. var collectionType = this.get('collectionType');
  160. if ( 'video' === this.get( 'type' ) ) {
  161. collectionType = 'video-' + collectionType;
  162. }
  163. this.set( 'id', collectionType + '-edit' );
  164. this.set( 'toolbar', collectionType + '-edit' );
  165. // If we haven't been provided a `library`, create a `Selection`.
  166. if ( ! this.get('library') ) {
  167. this.set( 'library', new wp.media.model.Selection() );
  168. }
  169. // The single `Attachment` view to be used in the `Attachments` view.
  170. if ( ! this.get('AttachmentView') ) {
  171. this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
  172. }
  173. Library.prototype.initialize.apply( this, arguments );
  174. },
  175. /**
  176. * @since 3.9.0
  177. */
  178. activate: function() {
  179. var library = this.get('library');
  180. // Limit the library to images only.
  181. library.props.set( 'type', this.get( 'type' ) );
  182. // Watch for uploaded attachments.
  183. this.get('library').observe( wp.Uploader.queue );
  184. this.frame.on( 'content:render:browse', this.renderSettings, this );
  185. Library.prototype.activate.apply( this, arguments );
  186. },
  187. /**
  188. * @since 3.9.0
  189. */
  190. deactivate: function() {
  191. // Stop watching for uploaded attachments.
  192. this.get('library').unobserve( wp.Uploader.queue );
  193. this.frame.off( 'content:render:browse', this.renderSettings, this );
  194. Library.prototype.deactivate.apply( this, arguments );
  195. },
  196. /**
  197. * Render the collection embed settings view in the browser sidebar.
  198. *
  199. * @todo This is against the pattern elsewhere in media. Typically the frame
  200. * is responsible for adding region mode callbacks. Explain.
  201. *
  202. * @since 3.9.0
  203. *
  204. * @param {wp.media.view.attachmentsBrowser} The attachments browser view.
  205. */
  206. renderSettings: function( attachmentsBrowserView ) {
  207. var library = this.get('library'),
  208. collectionType = this.get('collectionType'),
  209. dragInfoText = this.get('dragInfoText'),
  210. SettingsView = this.get('SettingsView'),
  211. obj = {};
  212. if ( ! library || ! attachmentsBrowserView ) {
  213. return;
  214. }
  215. library[ collectionType ] = library[ collectionType ] || new Backbone.Model();
  216. obj[ collectionType ] = new SettingsView({
  217. controller: this,
  218. model: library[ collectionType ],
  219. priority: 40
  220. });
  221. attachmentsBrowserView.sidebar.set( obj );
  222. if ( dragInfoText ) {
  223. attachmentsBrowserView.toolbar.set( 'dragInfo', new wp.media.View({
  224. el: $( '<div class="instructions">' + dragInfoText + '</div>' )[0],
  225. priority: -40
  226. }) );
  227. }
  228. // Add the 'Reverse order' button to the toolbar.
  229. attachmentsBrowserView.toolbar.set( 'reverse', {
  230. text: l10n.reverseOrder,
  231. priority: 80,
  232. click: function() {
  233. library.reset( library.toArray().reverse() );
  234. }
  235. });
  236. }
  237. });
  238. module.exports = CollectionEdit;
  239. /***/ }),
  240. /***/ 2288:
  241. /***/ (function(module) {
  242. var l10n = wp.media.view.l10n,
  243. Cropper;
  244. /**
  245. * wp.media.controller.Cropper
  246. *
  247. * A class for cropping an image when called from the header media customization panel.
  248. *
  249. * @memberOf wp.media.controller
  250. *
  251. * @class
  252. * @augments wp.media.controller.State
  253. * @augments Backbone.Model
  254. */
  255. Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{
  256. defaults: {
  257. id: 'cropper',
  258. title: l10n.cropImage,
  259. // Region mode defaults.
  260. toolbar: 'crop',
  261. content: 'crop',
  262. router: false,
  263. canSkipCrop: false,
  264. // Default doCrop Ajax arguments to allow the Customizer (for example) to inject state.
  265. doCropArgs: {}
  266. },
  267. /**
  268. * Shows the crop image window when called from the Add new image button.
  269. *
  270. * @since 4.2.0
  271. *
  272. * @return {void}
  273. */
  274. activate: function() {
  275. this.frame.on( 'content:create:crop', this.createCropContent, this );
  276. this.frame.on( 'close', this.removeCropper, this );
  277. this.set('selection', new Backbone.Collection(this.frame._selection.single));
  278. },
  279. /**
  280. * Changes the state of the toolbar window to browse mode.
  281. *
  282. * @since 4.2.0
  283. *
  284. * @return {void}
  285. */
  286. deactivate: function() {
  287. this.frame.toolbar.mode('browse');
  288. },
  289. /**
  290. * Creates the crop image window.
  291. *
  292. * Initialized when clicking on the Select and Crop button.
  293. *
  294. * @since 4.2.0
  295. *
  296. * @fires crop window
  297. *
  298. * @return {void}
  299. */
  300. createCropContent: function() {
  301. this.cropperView = new wp.media.view.Cropper({
  302. controller: this,
  303. attachment: this.get('selection').first()
  304. });
  305. this.cropperView.on('image-loaded', this.createCropToolbar, this);
  306. this.frame.content.set(this.cropperView);
  307. },
  308. /**
  309. * Removes the image selection and closes the cropping window.
  310. *
  311. * @since 4.2.0
  312. *
  313. * @return {void}
  314. */
  315. removeCropper: function() {
  316. this.imgSelect.cancelSelection();
  317. this.imgSelect.setOptions({remove: true});
  318. this.imgSelect.update();
  319. this.cropperView.remove();
  320. },
  321. /**
  322. * Checks if cropping can be skipped and creates crop toolbar accordingly.
  323. *
  324. * @since 4.2.0
  325. *
  326. * @return {void}
  327. */
  328. createCropToolbar: function() {
  329. var canSkipCrop, toolbarOptions;
  330. canSkipCrop = this.get('canSkipCrop') || false;
  331. toolbarOptions = {
  332. controller: this.frame,
  333. items: {
  334. insert: {
  335. style: 'primary',
  336. text: l10n.cropImage,
  337. priority: 80,
  338. requires: { library: false, selection: false },
  339. click: function() {
  340. var controller = this.controller,
  341. selection;
  342. selection = controller.state().get('selection').first();
  343. selection.set({cropDetails: controller.state().imgSelect.getSelection()});
  344. this.$el.text(l10n.cropping);
  345. this.$el.attr('disabled', true);
  346. controller.state().doCrop( selection ).done( function( croppedImage ) {
  347. controller.trigger('cropped', croppedImage );
  348. controller.close();
  349. }).fail( function() {
  350. controller.trigger('content:error:crop');
  351. });
  352. }
  353. }
  354. }
  355. };
  356. if ( canSkipCrop ) {
  357. _.extend( toolbarOptions.items, {
  358. skip: {
  359. style: 'secondary',
  360. text: l10n.skipCropping,
  361. priority: 70,
  362. requires: { library: false, selection: false },
  363. click: function() {
  364. var selection = this.controller.state().get('selection').first();
  365. this.controller.state().cropperView.remove();
  366. this.controller.trigger('skippedcrop', selection);
  367. this.controller.close();
  368. }
  369. }
  370. });
  371. }
  372. this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) );
  373. },
  374. /**
  375. * Creates an object with the image attachment and crop properties.
  376. *
  377. * @since 4.2.0
  378. *
  379. * @return {$.promise} A jQuery promise with the custom header crop details.
  380. */
  381. doCrop: function( attachment ) {
  382. return wp.ajax.post( 'custom-header-crop', _.extend(
  383. {},
  384. this.defaults.doCropArgs,
  385. {
  386. nonce: attachment.get( 'nonces' ).edit,
  387. id: attachment.get( 'id' ),
  388. cropDetails: attachment.get( 'cropDetails' )
  389. }
  390. ) );
  391. }
  392. });
  393. module.exports = Cropper;
  394. /***/ }),
  395. /***/ 6934:
  396. /***/ (function(module) {
  397. var Controller = wp.media.controller,
  398. CustomizeImageCropper;
  399. /**
  400. * A state for cropping an image in the customizer.
  401. *
  402. * @since 4.3.0
  403. *
  404. * @constructs wp.media.controller.CustomizeImageCropper
  405. * @memberOf wp.media.controller
  406. * @augments wp.media.controller.CustomizeImageCropper.Cropper
  407. * @inheritDoc
  408. */
  409. CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{
  410. /**
  411. * Posts the crop details to the admin.
  412. *
  413. * Uses crop measurements when flexible in both directions.
  414. * Constrains flexible side based on image ratio and size of the fixed side.
  415. *
  416. * @since 4.3.0
  417. *
  418. * @param {Object} attachment The attachment to crop.
  419. *
  420. * @return {$.promise} A jQuery promise that represents the crop image request.
  421. */
  422. doCrop: function( attachment ) {
  423. var cropDetails = attachment.get( 'cropDetails' ),
  424. control = this.get( 'control' ),
  425. ratio = cropDetails.width / cropDetails.height;
  426. // Use crop measurements when flexible in both directions.
  427. if ( control.params.flex_width && control.params.flex_height ) {
  428. cropDetails.dst_width = cropDetails.width;
  429. cropDetails.dst_height = cropDetails.height;
  430. // Constrain flexible side based on image ratio and size of the fixed side.
  431. } else {
  432. cropDetails.dst_width = control.params.flex_width ? control.params.height * ratio : control.params.width;
  433. cropDetails.dst_height = control.params.flex_height ? control.params.width / ratio : control.params.height;
  434. }
  435. return wp.ajax.post( 'crop-image', {
  436. wp_customize: 'on',
  437. nonce: attachment.get( 'nonces' ).edit,
  438. id: attachment.get( 'id' ),
  439. context: control.id,
  440. cropDetails: cropDetails
  441. } );
  442. }
  443. });
  444. module.exports = CustomizeImageCropper;
  445. /***/ }),
  446. /***/ 7658:
  447. /***/ (function(module) {
  448. var l10n = wp.media.view.l10n,
  449. EditImage;
  450. /**
  451. * wp.media.controller.EditImage
  452. *
  453. * A state for editing (cropping, etc.) an image.
  454. *
  455. * @memberOf wp.media.controller
  456. *
  457. * @class
  458. * @augments wp.media.controller.State
  459. * @augments Backbone.Model
  460. *
  461. * @param {object} attributes The attributes hash passed to the state.
  462. * @param {wp.media.model.Attachment} attributes.model The attachment.
  463. * @param {string} [attributes.id=edit-image] Unique identifier.
  464. * @param {string} [attributes.title=Edit Image] Title for the state. Displays in the media menu and the frame's title region.
  465. * @param {string} [attributes.content=edit-image] Initial mode for the content region.
  466. * @param {string} [attributes.toolbar=edit-image] Initial mode for the toolbar region.
  467. * @param {string} [attributes.menu=false] Initial mode for the menu region.
  468. * @param {string} [attributes.url] Unused. @todo Consider removal.
  469. */
  470. EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{
  471. defaults: {
  472. id: 'edit-image',
  473. title: l10n.editImage,
  474. menu: false,
  475. toolbar: 'edit-image',
  476. content: 'edit-image',
  477. url: ''
  478. },
  479. /**
  480. * Activates a frame for editing a featured image.
  481. *
  482. * @since 3.9.0
  483. *
  484. * @return {void}
  485. */
  486. activate: function() {
  487. this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) );
  488. },
  489. /**
  490. * Deactivates a frame for editing a featured image.
  491. *
  492. * @since 3.9.0
  493. *
  494. * @return {void}
  495. */
  496. deactivate: function() {
  497. this.frame.off( 'toolbar:render:edit-image' );
  498. },
  499. /**
  500. * Adds a toolbar with a back button.
  501. *
  502. * When the back button is pressed it checks whether there is a previous state.
  503. * In case there is a previous state it sets that previous state otherwise it
  504. * closes the frame.
  505. *
  506. * @since 3.9.0
  507. *
  508. * @return {void}
  509. */
  510. toolbar: function() {
  511. var frame = this.frame,
  512. lastState = frame.lastState(),
  513. previous = lastState && lastState.id;
  514. frame.toolbar.set( new wp.media.view.Toolbar({
  515. controller: frame,
  516. items: {
  517. back: {
  518. style: 'primary',
  519. text: l10n.back,
  520. priority: 20,
  521. click: function() {
  522. if ( previous ) {
  523. frame.setState( previous );
  524. } else {
  525. frame.close();
  526. }
  527. }
  528. }
  529. }
  530. }) );
  531. }
  532. });
  533. module.exports = EditImage;
  534. /***/ }),
  535. /***/ 9067:
  536. /***/ (function(module) {
  537. var l10n = wp.media.view.l10n,
  538. $ = Backbone.$,
  539. Embed;
  540. /**
  541. * wp.media.controller.Embed
  542. *
  543. * A state for embedding media from a URL.
  544. *
  545. * @memberOf wp.media.controller
  546. *
  547. * @class
  548. * @augments wp.media.controller.State
  549. * @augments Backbone.Model
  550. *
  551. * @param {object} attributes The attributes hash passed to the state.
  552. * @param {string} [attributes.id=embed] Unique identifier.
  553. * @param {string} [attributes.title=Insert From URL] Title for the state. Displays in the media menu and the frame's title region.
  554. * @param {string} [attributes.content=embed] Initial mode for the content region.
  555. * @param {string} [attributes.menu=default] Initial mode for the menu region.
  556. * @param {string} [attributes.toolbar=main-embed] Initial mode for the toolbar region.
  557. * @param {string} [attributes.menu=false] Initial mode for the menu region.
  558. * @param {int} [attributes.priority=120] The priority for the state link in the media menu.
  559. * @param {string} [attributes.type=link] The type of embed. Currently only link is supported.
  560. * @param {string} [attributes.url] The embed URL.
  561. * @param {object} [attributes.metadata={}] Properties of the embed, which will override attributes.url if set.
  562. */
  563. Embed = wp.media.controller.State.extend(/** @lends wp.media.controller.Embed.prototype */{
  564. defaults: {
  565. id: 'embed',
  566. title: l10n.insertFromUrlTitle,
  567. content: 'embed',
  568. menu: 'default',
  569. toolbar: 'main-embed',
  570. priority: 120,
  571. type: 'link',
  572. url: '',
  573. metadata: {}
  574. },
  575. // The amount of time used when debouncing the scan.
  576. sensitivity: 400,
  577. initialize: function(options) {
  578. this.metadata = options.metadata;
  579. this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
  580. this.props = new Backbone.Model( this.metadata || { url: '' });
  581. this.props.on( 'change:url', this.debouncedScan, this );
  582. this.props.on( 'change:url', this.refresh, this );
  583. this.on( 'scan', this.scanImage, this );
  584. },
  585. /**
  586. * Trigger a scan of the embedded URL's content for metadata required to embed.
  587. *
  588. * @fires wp.media.controller.Embed#scan
  589. */
  590. scan: function() {
  591. var scanners,
  592. embed = this,
  593. attributes = {
  594. type: 'link',
  595. scanners: []
  596. };
  597. /*
  598. * Scan is triggered with the list of `attributes` to set on the
  599. * state, useful for the 'type' attribute and 'scanners' attribute,
  600. * an array of promise objects for asynchronous scan operations.
  601. */
  602. if ( this.props.get('url') ) {
  603. this.trigger( 'scan', attributes );
  604. }
  605. if ( attributes.scanners.length ) {
  606. scanners = attributes.scanners = $.when.apply( $, attributes.scanners );
  607. scanners.always( function() {
  608. if ( embed.get('scanners') === scanners ) {
  609. embed.set( 'loading', false );
  610. }
  611. });
  612. } else {
  613. attributes.scanners = null;
  614. }
  615. attributes.loading = !! attributes.scanners;
  616. this.set( attributes );
  617. },
  618. /**
  619. * Try scanning the embed as an image to discover its dimensions.
  620. *
  621. * @param {Object} attributes
  622. */
  623. scanImage: function( attributes ) {
  624. var frame = this.frame,
  625. state = this,
  626. url = this.props.get('url'),
  627. image = new Image(),
  628. deferred = $.Deferred();
  629. attributes.scanners.push( deferred.promise() );
  630. // Try to load the image and find its width/height.
  631. image.onload = function() {
  632. deferred.resolve();
  633. if ( state !== frame.state() || url !== state.props.get('url') ) {
  634. return;
  635. }
  636. state.set({
  637. type: 'image'
  638. });
  639. state.props.set({
  640. width: image.width,
  641. height: image.height
  642. });
  643. };
  644. image.onerror = deferred.reject;
  645. image.src = url;
  646. },
  647. refresh: function() {
  648. this.frame.toolbar.get().refresh();
  649. },
  650. reset: function() {
  651. this.props.clear().set({ url: '' });
  652. if ( this.active ) {
  653. this.refresh();
  654. }
  655. }
  656. });
  657. module.exports = Embed;
  658. /***/ }),
  659. /***/ 5095:
  660. /***/ (function(module) {
  661. var Attachment = wp.media.model.Attachment,
  662. Library = wp.media.controller.Library,
  663. l10n = wp.media.view.l10n,
  664. FeaturedImage;
  665. /**
  666. * wp.media.controller.FeaturedImage
  667. *
  668. * A state for selecting a featured image for a post.
  669. *
  670. * @memberOf wp.media.controller
  671. *
  672. * @class
  673. * @augments wp.media.controller.Library
  674. * @augments wp.media.controller.State
  675. * @augments Backbone.Model
  676. *
  677. * @param {object} [attributes] The attributes hash passed to the state.
  678. * @param {string} [attributes.id=featured-image] Unique identifier.
  679. * @param {string} [attributes.title=Set Featured Image] Title for the state. Displays in the media menu and the frame's title region.
  680. * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse.
  681. * If one is not supplied, a collection of all images will be created.
  682. * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled.
  683. * @param {string} [attributes.content=upload] Initial mode for the content region.
  684. * Overridden by persistent user setting if 'contentUserSetting' is true.
  685. * @param {string} [attributes.menu=default] Initial mode for the menu region.
  686. * @param {string} [attributes.router=browse] Initial mode for the router region.
  687. * @param {string} [attributes.toolbar=featured-image] Initial mode for the toolbar region.
  688. * @param {int} [attributes.priority=60] The priority for the state link in the media menu.
  689. * @param {boolean} [attributes.searchable=true] Whether the library is searchable.
  690. * @param {boolean|string} [attributes.filterable=false] Whether the library is filterable, and if so what filters should be shown.
  691. * Accepts 'all', 'uploaded', or 'unattached'.
  692. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  693. * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection.
  694. * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
  695. * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
  696. * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state.
  697. */
  698. FeaturedImage = Library.extend(/** @lends wp.media.controller.FeaturedImage.prototype */{
  699. defaults: _.defaults({
  700. id: 'featured-image',
  701. title: l10n.setFeaturedImageTitle,
  702. multiple: false,
  703. filterable: 'uploaded',
  704. toolbar: 'featured-image',
  705. priority: 60,
  706. syncSelection: true
  707. }, Library.prototype.defaults ),
  708. /**
  709. * @since 3.5.0
  710. */
  711. initialize: function() {
  712. var library, comparator;
  713. // If we haven't been provided a `library`, create a `Selection`.
  714. if ( ! this.get('library') ) {
  715. this.set( 'library', wp.media.query({ type: 'image' }) );
  716. }
  717. Library.prototype.initialize.apply( this, arguments );
  718. library = this.get('library');
  719. comparator = library.comparator;
  720. // Overload the library's comparator to push items that are not in
  721. // the mirrored query to the front of the aggregate collection.
  722. library.comparator = function( a, b ) {
  723. var aInQuery = !! this.mirroring.get( a.cid ),
  724. bInQuery = !! this.mirroring.get( b.cid );
  725. if ( ! aInQuery && bInQuery ) {
  726. return -1;
  727. } else if ( aInQuery && ! bInQuery ) {
  728. return 1;
  729. } else {
  730. return comparator.apply( this, arguments );
  731. }
  732. };
  733. // Add all items in the selection to the library, so any featured
  734. // images that are not initially loaded still appear.
  735. library.observe( this.get('selection') );
  736. },
  737. /**
  738. * @since 3.5.0
  739. */
  740. activate: function() {
  741. this.frame.on( 'open', this.updateSelection, this );
  742. Library.prototype.activate.apply( this, arguments );
  743. },
  744. /**
  745. * @since 3.5.0
  746. */
  747. deactivate: function() {
  748. this.frame.off( 'open', this.updateSelection, this );
  749. Library.prototype.deactivate.apply( this, arguments );
  750. },
  751. /**
  752. * @since 3.5.0
  753. */
  754. updateSelection: function() {
  755. var selection = this.get('selection'),
  756. id = wp.media.view.settings.post.featuredImageId,
  757. attachment;
  758. if ( '' !== id && -1 !== id ) {
  759. attachment = Attachment.get( id );
  760. attachment.fetch();
  761. }
  762. selection.reset( attachment ? [ attachment ] : [] );
  763. }
  764. });
  765. module.exports = FeaturedImage;
  766. /***/ }),
  767. /***/ 7323:
  768. /***/ (function(module) {
  769. var Selection = wp.media.model.Selection,
  770. Library = wp.media.controller.Library,
  771. l10n = wp.media.view.l10n,
  772. GalleryAdd;
  773. /**
  774. * wp.media.controller.GalleryAdd
  775. *
  776. * A state for selecting more images to add to a gallery.
  777. *
  778. * @since 3.5.0
  779. *
  780. * @class
  781. * @augments wp.media.controller.Library
  782. * @augments wp.media.controller.State
  783. * @augments Backbone.Model
  784. *
  785. * @memberof wp.media.controller
  786. *
  787. * @param {Object} [attributes] The attributes hash passed to the state.
  788. * @param {string} [attributes.id=gallery-library] Unique identifier.
  789. * @param {string} [attributes.title=Add to Gallery] Title for the state. Displays in the frame's title region.
  790. * @param {boolean} [attributes.multiple=add] Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
  791. * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse.
  792. * If one is not supplied, a collection of all images will be created.
  793. * @param {boolean|string} [attributes.filterable=uploaded] Whether the library is filterable, and if so what filters should be shown.
  794. * Accepts 'all', 'uploaded', or 'unattached'.
  795. * @param {string} [attributes.menu=gallery] Initial mode for the menu region.
  796. * @param {string} [attributes.content=upload] Initial mode for the content region.
  797. * Overridden by persistent user setting if 'contentUserSetting' is true.
  798. * @param {string} [attributes.router=browse] Initial mode for the router region.
  799. * @param {string} [attributes.toolbar=gallery-add] Initial mode for the toolbar region.
  800. * @param {boolean} [attributes.searchable=true] Whether the library is searchable.
  801. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  802. * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection.
  803. * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
  804. * @param {number} [attributes.priority=100] The priority for the state link in the media menu.
  805. * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state.
  806. * Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
  807. */
  808. GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{
  809. defaults: _.defaults({
  810. id: 'gallery-library',
  811. title: l10n.addToGalleryTitle,
  812. multiple: 'add',
  813. filterable: 'uploaded',
  814. menu: 'gallery',
  815. toolbar: 'gallery-add',
  816. priority: 100,
  817. syncSelection: false
  818. }, Library.prototype.defaults ),
  819. /**
  820. * Initializes the library. Creates a library of images if a library isn't supplied.
  821. *
  822. * @since 3.5.0
  823. *
  824. * @return {void}
  825. */
  826. initialize: function() {
  827. if ( ! this.get('library') ) {
  828. this.set( 'library', wp.media.query({ type: 'image' }) );
  829. }
  830. Library.prototype.initialize.apply( this, arguments );
  831. },
  832. /**
  833. * Activates the library.
  834. *
  835. * Removes all event listeners if in edit mode. Creates a validator to check an attachment.
  836. * Resets library and re-enables event listeners. Activates edit mode. Calls the parent's activate method.
  837. *
  838. * @since 3.5.0
  839. *
  840. * @return {void}
  841. */
  842. activate: function() {
  843. var library = this.get('library'),
  844. edit = this.frame.state('gallery-edit').get('library');
  845. if ( this.editLibrary && this.editLibrary !== edit ) {
  846. library.unobserve( this.editLibrary );
  847. }
  848. /*
  849. * Accept attachments that exist in the original library but
  850. * that do not exist in gallery's library yet.
  851. */
  852. library.validator = function( attachment ) {
  853. return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
  854. };
  855. /*
  856. * Reset the library to ensure that all attachments are re-added
  857. * to the collection. Do so silently, as calling `observe` will
  858. * trigger the `reset` event.
  859. */
  860. library.reset( library.mirroring.models, { silent: true });
  861. library.observe( edit );
  862. this.editLibrary = edit;
  863. Library.prototype.activate.apply( this, arguments );
  864. }
  865. });
  866. module.exports = GalleryAdd;
  867. /***/ }),
  868. /***/ 6328:
  869. /***/ (function(module) {
  870. var Library = wp.media.controller.Library,
  871. l10n = wp.media.view.l10n,
  872. GalleryEdit;
  873. /**
  874. * wp.media.controller.GalleryEdit
  875. *
  876. * A state for editing a gallery's images and settings.
  877. *
  878. * @since 3.5.0
  879. *
  880. * @class
  881. * @augments wp.media.controller.Library
  882. * @augments wp.media.controller.State
  883. * @augments Backbone.Model
  884. *
  885. * @memberOf wp.media.controller
  886. *
  887. * @param {Object} [attributes] The attributes hash passed to the state.
  888. * @param {string} [attributes.id=gallery-edit] Unique identifier.
  889. * @param {string} [attributes.title=Edit Gallery] Title for the state. Displays in the frame's title region.
  890. * @param {wp.media.model.Attachments} [attributes.library] The collection of attachments in the gallery.
  891. * If one is not supplied, an empty media.model.Selection collection is created.
  892. * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled.
  893. * @param {boolean} [attributes.searchable=false] Whether the library is searchable.
  894. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  895. * @param {boolean} [attributes.date=true] Whether to show the date filter in the browser's toolbar.
  896. * @param {string|false} [attributes.content=browse] Initial mode for the content region.
  897. * @param {string|false} [attributes.toolbar=image-details] Initial mode for the toolbar region.
  898. * @param {boolean} [attributes.describe=true] Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
  899. * @param {boolean} [attributes.displaySettings=true] Whether to show the attachment display settings interface.
  900. * @param {boolean} [attributes.dragInfo=true] Whether to show instructional text about the attachments being sortable.
  901. * @param {number} [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments.
  902. * @param {boolean} [attributes.editing=false] Whether the gallery is being created, or editing an existing instance.
  903. * @param {number} [attributes.priority=60] The priority for the state link in the media menu.
  904. * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state.
  905. * Defaults to false for this state, because the library passed in *is* the selection.
  906. * @param {view} [attributes.AttachmentView] The single `Attachment` view to be used in the `Attachments`.
  907. * If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
  908. */
  909. GalleryEdit = Library.extend(/** @lends wp.media.controller.GalleryEdit.prototype */{
  910. defaults: {
  911. id: 'gallery-edit',
  912. title: l10n.editGalleryTitle,
  913. multiple: false,
  914. searchable: false,
  915. sortable: true,
  916. date: false,
  917. display: false,
  918. content: 'browse',
  919. toolbar: 'gallery-edit',
  920. describe: true,
  921. displaySettings: true,
  922. dragInfo: true,
  923. idealColumnWidth: 170,
  924. editing: false,
  925. priority: 60,
  926. syncSelection: false
  927. },
  928. /**
  929. * Initializes the library.
  930. *
  931. * Creates a selection if a library isn't supplied and creates an attachment
  932. * view if no attachment view is supplied.
  933. *
  934. * @since 3.5.0
  935. *
  936. * @return {void}
  937. */
  938. initialize: function() {
  939. // If we haven't been provided a `library`, create a `Selection`.
  940. if ( ! this.get('library') ) {
  941. this.set( 'library', new wp.media.model.Selection() );
  942. }
  943. // The single `Attachment` view to be used in the `Attachments` view.
  944. if ( ! this.get('AttachmentView') ) {
  945. this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
  946. }
  947. Library.prototype.initialize.apply( this, arguments );
  948. },
  949. /**
  950. * Activates the library.
  951. *
  952. * Limits the library to images, watches for uploaded attachments. Watches for
  953. * the browse event on the frame and binds it to gallerySettings.
  954. *
  955. * @since 3.5.0
  956. *
  957. * @return {void}
  958. */
  959. activate: function() {
  960. var library = this.get('library');
  961. // Limit the library to images only.
  962. library.props.set( 'type', 'image' );
  963. // Watch for uploaded attachments.
  964. this.get('library').observe( wp.Uploader.queue );
  965. this.frame.on( 'content:render:browse', this.gallerySettings, this );
  966. Library.prototype.activate.apply( this, arguments );
  967. },
  968. /**
  969. * Deactivates the library.
  970. *
  971. * Stops watching for uploaded attachments and browse events.
  972. *
  973. * @since 3.5.0
  974. *
  975. * @return {void}
  976. */
  977. deactivate: function() {
  978. // Stop watching for uploaded attachments.
  979. this.get('library').unobserve( wp.Uploader.queue );
  980. this.frame.off( 'content:render:browse', this.gallerySettings, this );
  981. Library.prototype.deactivate.apply( this, arguments );
  982. },
  983. /**
  984. * Adds the gallery settings to the sidebar and adds a reverse button to the
  985. * toolbar.
  986. *
  987. * @since 3.5.0
  988. *
  989. * @param {wp.media.view.Frame} browser The file browser.
  990. *
  991. * @return {void}
  992. */
  993. gallerySettings: function( browser ) {
  994. if ( ! this.get('displaySettings') ) {
  995. return;
  996. }
  997. var library = this.get('library');
  998. if ( ! library || ! browser ) {
  999. return;
  1000. }
  1001. library.gallery = library.gallery || new Backbone.Model();
  1002. browser.sidebar.set({
  1003. gallery: new wp.media.view.Settings.Gallery({
  1004. controller: this,
  1005. model: library.gallery,
  1006. priority: 40
  1007. })
  1008. });
  1009. browser.toolbar.set( 'reverse', {
  1010. text: l10n.reverseOrder,
  1011. priority: 80,
  1012. click: function() {
  1013. library.reset( library.toArray().reverse() );
  1014. }
  1015. });
  1016. }
  1017. });
  1018. module.exports = GalleryEdit;
  1019. /***/ }),
  1020. /***/ 3849:
  1021. /***/ (function(module) {
  1022. var State = wp.media.controller.State,
  1023. Library = wp.media.controller.Library,
  1024. l10n = wp.media.view.l10n,
  1025. ImageDetails;
  1026. /**
  1027. * wp.media.controller.ImageDetails
  1028. *
  1029. * A state for editing the attachment display settings of an image that's been
  1030. * inserted into the editor.
  1031. *
  1032. * @memberOf wp.media.controller
  1033. *
  1034. * @class
  1035. * @augments wp.media.controller.State
  1036. * @augments Backbone.Model
  1037. *
  1038. * @param {object} [attributes] The attributes hash passed to the state.
  1039. * @param {string} [attributes.id=image-details] Unique identifier.
  1040. * @param {string} [attributes.title=Image Details] Title for the state. Displays in the frame's title region.
  1041. * @param {wp.media.model.Attachment} attributes.image The image's model.
  1042. * @param {string|false} [attributes.content=image-details] Initial mode for the content region.
  1043. * @param {string|false} [attributes.menu=false] Initial mode for the menu region.
  1044. * @param {string|false} [attributes.router=false] Initial mode for the router region.
  1045. * @param {string|false} [attributes.toolbar=image-details] Initial mode for the toolbar region.
  1046. * @param {boolean} [attributes.editing=false] Unused.
  1047. * @param {int} [attributes.priority=60] Unused.
  1048. *
  1049. * @todo This state inherits some defaults from media.controller.Library.prototype.defaults,
  1050. * however this may not do anything.
  1051. */
  1052. ImageDetails = State.extend(/** @lends wp.media.controller.ImageDetails.prototype */{
  1053. defaults: _.defaults({
  1054. id: 'image-details',
  1055. title: l10n.imageDetailsTitle,
  1056. content: 'image-details',
  1057. menu: false,
  1058. router: false,
  1059. toolbar: 'image-details',
  1060. editing: false,
  1061. priority: 60
  1062. }, Library.prototype.defaults ),
  1063. /**
  1064. * @since 3.9.0
  1065. *
  1066. * @param options Attributes
  1067. */
  1068. initialize: function( options ) {
  1069. this.image = options.image;
  1070. State.prototype.initialize.apply( this, arguments );
  1071. },
  1072. /**
  1073. * @since 3.9.0
  1074. */
  1075. activate: function() {
  1076. this.frame.modal.$el.addClass('image-details');
  1077. }
  1078. });
  1079. module.exports = ImageDetails;
  1080. /***/ }),
  1081. /***/ 9024:
  1082. /***/ (function(module) {
  1083. var l10n = wp.media.view.l10n,
  1084. getUserSetting = window.getUserSetting,
  1085. setUserSetting = window.setUserSetting,
  1086. Library;
  1087. /**
  1088. * wp.media.controller.Library
  1089. *
  1090. * A state for choosing an attachment or group of attachments from the media library.
  1091. *
  1092. * @memberOf wp.media.controller
  1093. *
  1094. * @class
  1095. * @augments wp.media.controller.State
  1096. * @augments Backbone.Model
  1097. * @mixes media.selectionSync
  1098. *
  1099. * @param {object} [attributes] The attributes hash passed to the state.
  1100. * @param {string} [attributes.id=library] Unique identifier.
  1101. * @param {string} [attributes.title=Media library] Title for the state. Displays in the media menu and the frame's title region.
  1102. * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse.
  1103. * If one is not supplied, a collection of all attachments will be created.
  1104. * @param {wp.media.model.Selection|object} [attributes.selection] A collection to contain attachment selections within the state.
  1105. * If the 'selection' attribute is a plain JS object,
  1106. * a Selection will be created using its values as the selection instance's `props` model.
  1107. * Otherwise, it will copy the library's `props` model.
  1108. * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled.
  1109. * @param {string} [attributes.content=upload] Initial mode for the content region.
  1110. * Overridden by persistent user setting if 'contentUserSetting' is true.
  1111. * @param {string} [attributes.menu=default] Initial mode for the menu region.
  1112. * @param {string} [attributes.router=browse] Initial mode for the router region.
  1113. * @param {string} [attributes.toolbar=select] Initial mode for the toolbar region.
  1114. * @param {boolean} [attributes.searchable=true] Whether the library is searchable.
  1115. * @param {boolean|string} [attributes.filterable=false] Whether the library is filterable, and if so what filters should be shown.
  1116. * Accepts 'all', 'uploaded', or 'unattached'.
  1117. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  1118. * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection.
  1119. * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
  1120. * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
  1121. * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state.
  1122. */
  1123. Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{
  1124. defaults: {
  1125. id: 'library',
  1126. title: l10n.mediaLibraryTitle,
  1127. multiple: false,
  1128. content: 'upload',
  1129. menu: 'default',
  1130. router: 'browse',
  1131. toolbar: 'select',
  1132. searchable: true,
  1133. filterable: false,
  1134. sortable: true,
  1135. autoSelect: true,
  1136. describe: false,
  1137. contentUserSetting: true,
  1138. syncSelection: true
  1139. },
  1140. /**
  1141. * If a library isn't provided, query all media items.
  1142. * If a selection instance isn't provided, create one.
  1143. *
  1144. * @since 3.5.0
  1145. */
  1146. initialize: function() {
  1147. var selection = this.get('selection'),
  1148. props;
  1149. if ( ! this.get('library') ) {
  1150. this.set( 'library', wp.media.query() );
  1151. }
  1152. if ( ! ( selection instanceof wp.media.model.Selection ) ) {
  1153. props = selection;
  1154. if ( ! props ) {
  1155. props = this.get('library').props.toJSON();
  1156. props = _.omit( props, 'orderby', 'query' );
  1157. }
  1158. this.set( 'selection', new wp.media.model.Selection( null, {
  1159. multiple: this.get('multiple'),
  1160. props: props
  1161. }) );
  1162. }
  1163. this.resetDisplays();
  1164. },
  1165. /**
  1166. * @since 3.5.0
  1167. */
  1168. activate: function() {
  1169. this.syncSelection();
  1170. wp.Uploader.queue.on( 'add', this.uploading, this );
  1171. this.get('selection').on( 'add remove reset', this.refreshContent, this );
  1172. if ( this.get( 'router' ) && this.get('contentUserSetting') ) {
  1173. this.frame.on( 'content:activate', this.saveContentMode, this );
  1174. this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
  1175. }
  1176. },
  1177. /**
  1178. * @since 3.5.0
  1179. */
  1180. deactivate: function() {
  1181. this.recordSelection();
  1182. this.frame.off( 'content:activate', this.saveContentMode, this );
  1183. // Unbind all event handlers that use this state as the context
  1184. // from the selection.
  1185. this.get('selection').off( null, null, this );
  1186. wp.Uploader.queue.off( null, null, this );
  1187. },
  1188. /**
  1189. * Reset the library to its initial state.
  1190. *
  1191. * @since 3.5.0
  1192. */
  1193. reset: function() {
  1194. this.get('selection').reset();
  1195. this.resetDisplays();
  1196. this.refreshContent();
  1197. },
  1198. /**
  1199. * Reset the attachment display settings defaults to the site options.
  1200. *
  1201. * If site options don't define them, fall back to a persistent user setting.
  1202. *
  1203. * @since 3.5.0
  1204. */
  1205. resetDisplays: function() {
  1206. var defaultProps = wp.media.view.settings.defaultProps;
  1207. this._displays = [];
  1208. this._defaultDisplaySettings = {
  1209. align: getUserSetting( 'align', defaultProps.align ) || 'none',
  1210. size: getUserSetting( 'imgsize', defaultProps.size ) || 'medium',
  1211. link: getUserSetting( 'urlbutton', defaultProps.link ) || 'none'
  1212. };
  1213. },
  1214. /**
  1215. * Create a model to represent display settings (alignment, etc.) for an attachment.
  1216. *
  1217. * @since 3.5.0
  1218. *
  1219. * @param {wp.media.model.Attachment} attachment
  1220. * @return {Backbone.Model}
  1221. */
  1222. display: function( attachment ) {
  1223. var displays = this._displays;
  1224. if ( ! displays[ attachment.cid ] ) {
  1225. displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
  1226. }
  1227. return displays[ attachment.cid ];
  1228. },
  1229. /**
  1230. * Given an attachment, create attachment display settings properties.
  1231. *
  1232. * @since 3.6.0
  1233. *
  1234. * @param {wp.media.model.Attachment} attachment
  1235. * @return {Object}
  1236. */
  1237. defaultDisplaySettings: function( attachment ) {
  1238. var settings = _.clone( this._defaultDisplaySettings );
  1239. settings.canEmbed = this.canEmbed( attachment );
  1240. if ( settings.canEmbed ) {
  1241. settings.link = 'embed';
  1242. } else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) {
  1243. settings.link = 'file';
  1244. }
  1245. return settings;
  1246. },
  1247. /**
  1248. * Whether an attachment is image.
  1249. *
  1250. * @since 4.4.1
  1251. *
  1252. * @param {wp.media.model.Attachment} attachment
  1253. * @return {boolean}
  1254. */
  1255. isImageAttachment: function( attachment ) {
  1256. // If uploading, we know the filename but not the mime type.
  1257. if ( attachment.get('uploading') ) {
  1258. return /\.(jpe?g|png|gif|webp)$/i.test( attachment.get('filename') );
  1259. }
  1260. return attachment.get('type') === 'image';
  1261. },
  1262. /**
  1263. * Whether an attachment can be embedded (audio or video).
  1264. *
  1265. * @since 3.6.0
  1266. *
  1267. * @param {wp.media.model.Attachment} attachment
  1268. * @return {boolean}
  1269. */
  1270. canEmbed: function( attachment ) {
  1271. // If uploading, we know the filename but not the mime type.
  1272. if ( ! attachment.get('uploading') ) {
  1273. var type = attachment.get('type');
  1274. if ( type !== 'audio' && type !== 'video' ) {
  1275. return false;
  1276. }
  1277. }
  1278. return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
  1279. },
  1280. /**
  1281. * If the state is active, no items are selected, and the current
  1282. * content mode is not an option in the state's router (provided
  1283. * the state has a router), reset the content mode to the default.
  1284. *
  1285. * @since 3.5.0
  1286. */
  1287. refreshContent: function() {
  1288. var selection = this.get('selection'),
  1289. frame = this.frame,
  1290. router = frame.router.get(),
  1291. mode = frame.content.mode();
  1292. if ( this.active && ! selection.length && router && ! router.get( mode ) ) {
  1293. this.frame.content.render( this.get('content') );
  1294. }
  1295. },
  1296. /**
  1297. * Callback handler when an attachment is uploaded.
  1298. *
  1299. * Switch to the Media Library if uploaded from the 'Upload Files' tab.
  1300. *
  1301. * Adds any uploading attachments to the selection.
  1302. *
  1303. * If the state only supports one attachment to be selected and multiple
  1304. * attachments are uploaded, the last attachment in the upload queue will
  1305. * be selected.
  1306. *
  1307. * @since 3.5.0
  1308. *
  1309. * @param {wp.media.model.Attachment} attachment
  1310. */
  1311. uploading: function( attachment ) {
  1312. var content = this.frame.content;
  1313. if ( 'upload' === content.mode() ) {
  1314. this.frame.content.mode('browse');
  1315. }
  1316. if ( this.get( 'autoSelect' ) ) {
  1317. this.get('selection').add( attachment );
  1318. this.frame.trigger( 'library:selection:add' );
  1319. }
  1320. },
  1321. /**
  1322. * Persist the mode of the content region as a user setting.
  1323. *
  1324. * @since 3.5.0
  1325. */
  1326. saveContentMode: function() {
  1327. if ( 'browse' !== this.get('router') ) {
  1328. return;
  1329. }
  1330. var mode = this.frame.content.mode(),
  1331. view = this.frame.router.get();
  1332. if ( view && view.get( mode ) ) {
  1333. setUserSetting( 'libraryContent', mode );
  1334. }
  1335. }
  1336. });
  1337. // Make selectionSync available on any Media Library state.
  1338. _.extend( Library.prototype, wp.media.selectionSync );
  1339. module.exports = Library;
  1340. /***/ }),
  1341. /***/ 3742:
  1342. /***/ (function(module) {
  1343. /**
  1344. * wp.media.controller.MediaLibrary
  1345. *
  1346. * @memberOf wp.media.controller
  1347. *
  1348. * @class
  1349. * @augments wp.media.controller.Library
  1350. * @augments wp.media.controller.State
  1351. * @augments Backbone.Model
  1352. */
  1353. var Library = wp.media.controller.Library,
  1354. MediaLibrary;
  1355. MediaLibrary = Library.extend(/** @lends wp.media.controller.MediaLibrary.prototype */{
  1356. defaults: _.defaults({
  1357. // Attachments browser defaults. @see media.view.AttachmentsBrowser
  1358. filterable: 'uploaded',
  1359. displaySettings: false,
  1360. priority: 80,
  1361. syncSelection: false
  1362. }, Library.prototype.defaults ),
  1363. /**
  1364. * @since 3.9.0
  1365. *
  1366. * @param options
  1367. */
  1368. initialize: function( options ) {
  1369. this.media = options.media;
  1370. this.type = options.type;
  1371. this.set( 'library', wp.media.query({ type: this.type }) );
  1372. Library.prototype.initialize.apply( this, arguments );
  1373. },
  1374. /**
  1375. * @since 3.9.0
  1376. */
  1377. activate: function() {
  1378. // @todo this should use this.frame.
  1379. if ( wp.media.frame.lastMime ) {
  1380. this.set( 'library', wp.media.query({ type: wp.media.frame.lastMime }) );
  1381. delete wp.media.frame.lastMime;
  1382. }
  1383. Library.prototype.activate.apply( this, arguments );
  1384. }
  1385. });
  1386. module.exports = MediaLibrary;
  1387. /***/ }),
  1388. /***/ 4903:
  1389. /***/ (function(module) {
  1390. /**
  1391. * wp.media.controller.Region
  1392. *
  1393. * A region is a persistent application layout area.
  1394. *
  1395. * A region assumes one mode at any time, and can be switched to another.
  1396. *
  1397. * When mode changes, events are triggered on the region's parent view.
  1398. * The parent view will listen to specific events and fill the region with an
  1399. * appropriate view depending on mode. For example, a frame listens for the
  1400. * 'browse' mode t be activated on the 'content' view and then fills the region
  1401. * with an AttachmentsBrowser view.
  1402. *
  1403. * @memberOf wp.media.controller
  1404. *
  1405. * @class
  1406. *
  1407. * @param {Object} options Options hash for the region.
  1408. * @param {string} options.id Unique identifier for the region.
  1409. * @param {Backbone.View} options.view A parent view the region exists within.
  1410. * @param {string} options.selector jQuery selector for the region within the parent view.
  1411. */
  1412. var Region = function( options ) {
  1413. _.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
  1414. };
  1415. // Use Backbone's self-propagating `extend` inheritance method.
  1416. Region.extend = Backbone.Model.extend;
  1417. _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{
  1418. /**
  1419. * Activate a mode.
  1420. *
  1421. * @since 3.5.0
  1422. *
  1423. * @param {string} mode
  1424. *
  1425. * @fires Region#activate
  1426. * @fires Region#deactivate
  1427. *
  1428. * @return {wp.media.controller.Region} Returns itself to allow chaining.
  1429. */
  1430. mode: function( mode ) {
  1431. if ( ! mode ) {
  1432. return this._mode;
  1433. }
  1434. // Bail if we're trying to change to the current mode.
  1435. if ( mode === this._mode ) {
  1436. return this;
  1437. }
  1438. /**
  1439. * Region mode deactivation event.
  1440. *
  1441. * @event wp.media.controller.Region#deactivate
  1442. */
  1443. this.trigger('deactivate');
  1444. this._mode = mode;
  1445. this.render( mode );
  1446. /**
  1447. * Region mode activation event.
  1448. *
  1449. * @event wp.media.controller.Region#activate
  1450. */
  1451. this.trigger('activate');
  1452. return this;
  1453. },
  1454. /**
  1455. * Render a mode.
  1456. *
  1457. * @since 3.5.0
  1458. *
  1459. * @param {string} mode
  1460. *
  1461. * @fires Region#create
  1462. * @fires Region#render
  1463. *
  1464. * @return {wp.media.controller.Region} Returns itself to allow chaining.
  1465. */
  1466. render: function( mode ) {
  1467. // If the mode isn't active, activate it.
  1468. if ( mode && mode !== this._mode ) {
  1469. return this.mode( mode );
  1470. }
  1471. var set = { view: null },
  1472. view;
  1473. /**
  1474. * Create region view event.
  1475. *
  1476. * Region view creation takes place in an event callback on the frame.
  1477. *
  1478. * @event wp.media.controller.Region#create
  1479. * @type {object}
  1480. * @property {object} view
  1481. */
  1482. this.trigger( 'create', set );
  1483. view = set.view;
  1484. /**
  1485. * Render region view event.
  1486. *
  1487. * Region view creation takes place in an event callback on the frame.
  1488. *
  1489. * @event wp.media.controller.Region#render
  1490. * @type {object}
  1491. */
  1492. this.trigger( 'render', view );
  1493. if ( view ) {
  1494. this.set( view );
  1495. }
  1496. return this;
  1497. },
  1498. /**
  1499. * Get the region's view.
  1500. *
  1501. * @since 3.5.0
  1502. *
  1503. * @return {wp.media.View}
  1504. */
  1505. get: function() {
  1506. return this.view.views.first( this.selector );
  1507. },
  1508. /**
  1509. * Set the region's view as a subview of the frame.
  1510. *
  1511. * @since 3.5.0
  1512. *
  1513. * @param {Array|Object} views
  1514. * @param {Object} [options={}]
  1515. * @return {wp.Backbone.Subviews} Subviews is returned to allow chaining.
  1516. */
  1517. set: function( views, options ) {
  1518. if ( options ) {
  1519. options.add = false;
  1520. }
  1521. return this.view.views.set( this.selector, views, options );
  1522. },
  1523. /**
  1524. * Trigger regional view events on the frame.
  1525. *
  1526. * @since 3.5.0
  1527. *
  1528. * @param {string} event
  1529. * @return {undefined|wp.media.controller.Region} Returns itself to allow chaining.
  1530. */
  1531. trigger: function( event ) {
  1532. var base, args;
  1533. if ( ! this._mode ) {
  1534. return;
  1535. }
  1536. args = _.toArray( arguments );
  1537. base = this.id + ':' + event;
  1538. // Trigger `{this.id}:{event}:{this._mode}` event on the frame.
  1539. args[0] = base + ':' + this._mode;
  1540. this.view.trigger.apply( this.view, args );
  1541. // Trigger `{this.id}:{event}` event on the frame.
  1542. args[0] = base;
  1543. this.view.trigger.apply( this.view, args );
  1544. return this;
  1545. }
  1546. });
  1547. module.exports = Region;
  1548. /***/ }),
  1549. /***/ 8493:
  1550. /***/ (function(module) {
  1551. var Library = wp.media.controller.Library,
  1552. l10n = wp.media.view.l10n,
  1553. ReplaceImage;
  1554. /**
  1555. * wp.media.controller.ReplaceImage
  1556. *
  1557. * A state for replacing an image.
  1558. *
  1559. * @memberOf wp.media.controller
  1560. *
  1561. * @class
  1562. * @augments wp.media.controller.Library
  1563. * @augments wp.media.controller.State
  1564. * @augments Backbone.Model
  1565. *
  1566. * @param {object} [attributes] The attributes hash passed to the state.
  1567. * @param {string} [attributes.id=replace-image] Unique identifier.
  1568. * @param {string} [attributes.title=Replace Image] Title for the state. Displays in the media menu and the frame's title region.
  1569. * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse.
  1570. * If one is not supplied, a collection of all images will be created.
  1571. * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled.
  1572. * @param {string} [attributes.content=upload] Initial mode for the content region.
  1573. * Overridden by persistent user setting if 'contentUserSetting' is true.
  1574. * @param {string} [attributes.menu=default] Initial mode for the menu region.
  1575. * @param {string} [attributes.router=browse] Initial mode for the router region.
  1576. * @param {string} [attributes.toolbar=replace] Initial mode for the toolbar region.
  1577. * @param {int} [attributes.priority=60] The priority for the state link in the media menu.
  1578. * @param {boolean} [attributes.searchable=true] Whether the library is searchable.
  1579. * @param {boolean|string} [attributes.filterable=uploaded] Whether the library is filterable, and if so what filters should be shown.
  1580. * Accepts 'all', 'uploaded', or 'unattached'.
  1581. * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
  1582. * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection.
  1583. * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
  1584. * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
  1585. * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state.
  1586. */
  1587. ReplaceImage = Library.extend(/** @lends wp.media.controller.ReplaceImage.prototype */{
  1588. defaults: _.defaults({
  1589. id: 'replace-image',
  1590. title: l10n.replaceImageTitle,
  1591. multiple: false,
  1592. filterable: 'uploaded',
  1593. toolbar: 'replace',
  1594. menu: false,
  1595. priority: 60,
  1596. syncSelection: true
  1597. }, Library.prototype.defaults ),
  1598. /**
  1599. * @since 3.9.0
  1600. *
  1601. * @param options
  1602. */
  1603. initialize: function( options ) {
  1604. var library, comparator;
  1605. this.image = options.image;
  1606. // If we haven't been provided a `library`, create a `Selection`.
  1607. if ( ! this.get('library') ) {
  1608. this.set( 'library', wp.media.query({ type: 'image' }) );
  1609. }
  1610. Library.prototype.initialize.apply( this, arguments );
  1611. library = this.get('library');
  1612. comparator = library.comparator;
  1613. // Overload the library's comparator to push items that are not in
  1614. // the mirrored query to the front of the aggregate collection.
  1615. library.comparator = function( a, b ) {
  1616. var aInQuery = !! this.mirroring.get( a.cid ),
  1617. bInQuery = !! this.mirroring.get( b.cid );
  1618. if ( ! aInQuery && bInQuery ) {
  1619. return -1;
  1620. } else if ( aInQuery && ! bInQuery ) {
  1621. return 1;
  1622. } else {
  1623. return comparator.apply( this, arguments );
  1624. }
  1625. };
  1626. // Add all items in the selection to the library, so any featured
  1627. // images that are not initially loaded still appear.
  1628. library.observe( this.get('selection') );
  1629. },
  1630. /**
  1631. * @since 3.9.0
  1632. */
  1633. activate: function() {
  1634. this.frame.on( 'content:render:browse', this.updateSelection, this );
  1635. Library.prototype.activate.apply( this, arguments );
  1636. },
  1637. /**
  1638. * @since 5.9.0
  1639. */
  1640. deactivate: function() {
  1641. this.frame.off( 'content:render:browse', this.updateSelection, this );
  1642. Library.prototype.deactivate.apply( this, arguments );
  1643. },
  1644. /**
  1645. * @since 3.9.0
  1646. */
  1647. updateSelection: function() {
  1648. var selection = this.get('selection'),
  1649. attachment = this.image.attachment;
  1650. selection.reset( attachment ? [ attachment ] : [] );
  1651. }
  1652. });
  1653. module.exports = ReplaceImage;
  1654. /***/ }),
  1655. /***/ 5274:
  1656. /***/ (function(module) {
  1657. var Controller = wp.media.controller,
  1658. SiteIconCropper;
  1659. /**
  1660. * wp.media.controller.SiteIconCropper
  1661. *
  1662. * A state for cropping a Site Icon.
  1663. *
  1664. * @memberOf wp.media.controller
  1665. *
  1666. * @class
  1667. * @augments wp.media.controller.Cropper
  1668. * @augments wp.media.controller.State
  1669. * @augments Backbone.Model
  1670. */
  1671. SiteIconCropper = Controller.Cropper.extend(/** @lends wp.media.controller.SiteIconCropper.prototype */{
  1672. activate: function() {
  1673. this.frame.on( 'content:create:crop', this.createCropContent, this );
  1674. this.frame.on( 'close', this.removeCropper, this );
  1675. this.set('selection', new Backbone.Collection(this.frame._selection.single));
  1676. },
  1677. createCropContent: function() {
  1678. this.cropperView = new wp.media.view.SiteIconCropper({
  1679. controller: this,
  1680. attachment: this.get('selection').first()
  1681. });
  1682. this.cropperView.on('image-loaded', this.createCropToolbar, this);
  1683. this.frame.content.set(this.cropperView);
  1684. },
  1685. doCrop: function( attachment ) {
  1686. var cropDetails = attachment.get( 'cropDetails' ),
  1687. control = this.get( 'control' );
  1688. cropDetails.dst_width = control.params.width;
  1689. cropDetails.dst_height = control.params.height;
  1690. return wp.ajax.post( 'crop-image', {
  1691. nonce: attachment.get( 'nonces' ).edit,
  1692. id: attachment.get( 'id' ),
  1693. context: 'site-icon',
  1694. cropDetails: cropDetails
  1695. } );
  1696. }
  1697. });
  1698. module.exports = SiteIconCropper;
  1699. /***/ }),
  1700. /***/ 5466:
  1701. /***/ (function(module) {
  1702. /**
  1703. * wp.media.controller.StateMachine
  1704. *
  1705. * A state machine keeps track of state. It is in one state at a time,
  1706. * and can change from one state to another.
  1707. *
  1708. * States are stored as models in a Backbone collection.
  1709. *
  1710. * @memberOf wp.media.controller
  1711. *
  1712. * @since 3.5.0
  1713. *
  1714. * @class
  1715. * @augments Backbone.Model
  1716. * @mixin
  1717. * @mixes Backbone.Events
  1718. */
  1719. var StateMachine = function() {
  1720. return {
  1721. // Use Backbone's self-propagating `extend` inheritance method.
  1722. extend: Backbone.Model.extend
  1723. };
  1724. };
  1725. _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{
  1726. /**
  1727. * Fetch a state.
  1728. *
  1729. * If no `id` is provided, returns the active state.
  1730. *
  1731. * Implicitly creates states.
  1732. *
  1733. * Ensure that the `states` collection exists so the `StateMachine`
  1734. * can be used as a mixin.
  1735. *
  1736. * @since 3.5.0
  1737. *
  1738. * @param {string} id
  1739. * @return {wp.media.controller.State} Returns a State model from
  1740. * the StateMachine collection.
  1741. */
  1742. state: function( id ) {
  1743. this.states = this.states || new Backbone.Collection();
  1744. // Default to the active state.
  1745. id = id || this._state;
  1746. if ( id && ! this.states.get( id ) ) {
  1747. this.states.add({ id: id });
  1748. }
  1749. return this.states.get( id );
  1750. },
  1751. /**
  1752. * Sets the active state.
  1753. *
  1754. * Bail if we're trying to select the current state, if we haven't
  1755. * created the `states` collection, or are trying to select a state
  1756. * that does not exist.
  1757. *
  1758. * @since 3.5.0
  1759. *
  1760. * @param {string} id
  1761. *
  1762. * @fires wp.media.controller.State#deactivate
  1763. * @fires wp.media.controller.State#activate
  1764. *
  1765. * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
  1766. */
  1767. setState: function( id ) {
  1768. var previous = this.state();
  1769. if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
  1770. return this;
  1771. }
  1772. if ( previous ) {
  1773. previous.trigger('deactivate');
  1774. this._lastState = previous.id;
  1775. }
  1776. this._state = id;
  1777. this.state().trigger('activate');
  1778. return this;
  1779. },
  1780. /**
  1781. * Returns the previous active state.
  1782. *
  1783. * Call the `state()` method with no parameters to retrieve the current
  1784. * active state.
  1785. *
  1786. * @since 3.5.0
  1787. *
  1788. * @return {wp.media.controller.State} Returns a State model from
  1789. * the StateMachine collection.
  1790. */
  1791. lastState: function() {
  1792. if ( this._lastState ) {
  1793. return this.state( this._lastState );
  1794. }
  1795. }
  1796. });
  1797. // Map all event binding and triggering on a StateMachine to its `states` collection.
  1798. _.each([ 'on', 'off', 'trigger' ], function( method ) {
  1799. /**
  1800. * @function on
  1801. * @memberOf wp.media.controller.StateMachine
  1802. * @instance
  1803. * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
  1804. */
  1805. /**
  1806. * @function off
  1807. * @memberOf wp.media.controller.StateMachine
  1808. * @instance
  1809. * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
  1810. */
  1811. /**
  1812. * @function trigger
  1813. * @memberOf wp.media.controller.StateMachine
  1814. * @instance
  1815. * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
  1816. */
  1817. StateMachine.prototype[ method ] = function() {
  1818. // Ensure that the `states` collection exists so the `StateMachine`
  1819. // can be used as a mixin.
  1820. this.states = this.states || new Backbone.Collection();
  1821. // Forward the method to the `states` collection.
  1822. this.states[ method ].apply( this.states, arguments );
  1823. return this;
  1824. };
  1825. });
  1826. module.exports = StateMachine;
  1827. /***/ }),
  1828. /***/ 5826:
  1829. /***/ (function(module) {
  1830. /**
  1831. * wp.media.controller.State
  1832. *
  1833. * A state is a step in a workflow that when set will trigger the controllers
  1834. * for the regions to be updated as specified in the frame.
  1835. *
  1836. * A state has an event-driven lifecycle:
  1837. *
  1838. * 'ready' triggers when a state is added to a state machine's collection.
  1839. * 'activate' triggers when a state is activated by a state machine.
  1840. * 'deactivate' triggers when a state is deactivated by a state machine.
  1841. * 'reset' is not triggered automatically. It should be invoked by the
  1842. * proper controller to reset the state to its default.
  1843. *
  1844. * @memberOf wp.media.controller
  1845. *
  1846. * @class
  1847. * @augments Backbone.Model
  1848. */
  1849. var State = Backbone.Model.extend(/** @lends wp.media.controller.State.prototype */{
  1850. /**
  1851. * Constructor.
  1852. *
  1853. * @since 3.5.0
  1854. */
  1855. constructor: function() {
  1856. this.on( 'activate', this._preActivate, this );
  1857. this.on( 'activate', this.activate, this );
  1858. this.on( 'activate', this._postActivate, this );
  1859. this.on( 'deactivate', this._deactivate, this );
  1860. this.on( 'deactivate', this.deactivate, this );
  1861. this.on( 'reset', this.reset, this );
  1862. this.on( 'ready', this._ready, this );
  1863. this.on( 'ready', this.ready, this );
  1864. /**
  1865. * Call parent constructor with passed arguments
  1866. */
  1867. Backbone.Model.apply( this, arguments );
  1868. this.on( 'change:menu', this._updateMenu, this );
  1869. },
  1870. /**
  1871. * Ready event callback.
  1872. *
  1873. * @abstract
  1874. * @since 3.5.0
  1875. */
  1876. ready: function() {},
  1877. /**
  1878. * Activate event callback.
  1879. *
  1880. * @abstract
  1881. * @since 3.5.0
  1882. */
  1883. activate: function() {},
  1884. /**
  1885. * Deactivate event callback.
  1886. *
  1887. * @abstract
  1888. * @since 3.5.0
  1889. */
  1890. deactivate: function() {},
  1891. /**
  1892. * Reset event callback.
  1893. *
  1894. * @abstract
  1895. * @since 3.5.0
  1896. */
  1897. reset: function() {},
  1898. /**
  1899. * @since 3.5.0
  1900. * @access private
  1901. */
  1902. _ready: function() {
  1903. this._updateMenu();
  1904. },
  1905. /**
  1906. * @since 3.5.0
  1907. * @access private
  1908. */
  1909. _preActivate: function() {
  1910. this.active = true;
  1911. },
  1912. /**
  1913. * @since 3.5.0
  1914. * @access private
  1915. */
  1916. _postActivate: function() {
  1917. this.on( 'change:menu', this._menu, this );
  1918. this.on( 'change:titleMode', this._title, this );
  1919. this.on( 'change:content', this._content, this );
  1920. this.on( 'change:toolbar', this._toolbar, this );
  1921. this.frame.on( 'title:render:default', this._renderTitle, this );
  1922. this._title();
  1923. this._menu();
  1924. this._toolbar();
  1925. this._content();
  1926. this._router();
  1927. },
  1928. /**
  1929. * @since 3.5.0
  1930. * @access private
  1931. */
  1932. _deactivate: function() {
  1933. this.active = false;
  1934. this.frame.off( 'title:render:default', this._renderTitle, this );
  1935. this.off( 'change:menu', this._menu, this );
  1936. this.off( 'change:titleMode', this._title, this );
  1937. this.off( 'change:content', this._content, this );
  1938. this.off( 'change:toolbar', this._toolbar, this );
  1939. },
  1940. /**
  1941. * @since 3.5.0
  1942. * @access private
  1943. */
  1944. _title: function() {
  1945. this.frame.title.render( this.get('titleMode') || 'default' );
  1946. },
  1947. /**
  1948. * @since 3.5.0
  1949. * @access private
  1950. */
  1951. _renderTitle: function( view ) {
  1952. view.$el.text( this.get('title') || '' );
  1953. },
  1954. /**
  1955. * @since 3.5.0
  1956. * @access private
  1957. */
  1958. _router: function() {
  1959. var router = this.frame.router,
  1960. mode = this.get('router'),
  1961. view;
  1962. this.frame.$el.toggleClass( 'hide-router', ! mode );
  1963. if ( ! mode ) {
  1964. return;
  1965. }
  1966. this.frame.router.render( mode );
  1967. view = router.get();
  1968. if ( view && view.select ) {
  1969. view.select( this.frame.content.mode() );
  1970. }
  1971. },
  1972. /**
  1973. * @since 3.5.0
  1974. * @access private
  1975. */
  1976. _menu: function() {
  1977. var menu = this.frame.menu,
  1978. mode = this.get('menu'),
  1979. view;
  1980. this.frame.$el.toggleClass( 'hide-menu', ! mode );
  1981. if ( ! mode ) {
  1982. return;
  1983. }
  1984. menu.mode( mode );
  1985. view = menu.get();
  1986. if ( view && view.select ) {
  1987. view.select( this.id );
  1988. }
  1989. },
  1990. /**
  1991. * @since 3.5.0
  1992. * @access private
  1993. */
  1994. _updateMenu: function() {
  1995. var previous = this.previous('menu'),
  1996. menu = this.get('menu');
  1997. if ( previous ) {
  1998. this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
  1999. }
  2000. if ( menu ) {
  2001. this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
  2002. }
  2003. },
  2004. /**
  2005. * Create a view in the media menu for the state.
  2006. *
  2007. * @since 3.5.0
  2008. * @access private
  2009. *
  2010. * @param {media.view.Menu} view The menu view.
  2011. */
  2012. _renderMenu: function( view ) {
  2013. var menuItem = this.get('menuItem'),
  2014. title = this.get('title'),
  2015. priority = this.get('priority');
  2016. if ( ! menuItem && title ) {
  2017. menuItem = { text: title };
  2018. if ( priority ) {
  2019. menuItem.priority = priority;
  2020. }
  2021. }
  2022. if ( ! menuItem ) {
  2023. return;
  2024. }
  2025. view.set( this.id, menuItem );
  2026. }
  2027. });
  2028. _.each(['toolbar','content'], function( region ) {
  2029. /**
  2030. * @access private
  2031. */
  2032. State.prototype[ '_' + region ] = function() {
  2033. var mode = this.get( region );
  2034. if ( mode ) {
  2035. this.frame[ region ].render( mode );
  2036. }
  2037. };
  2038. });
  2039. module.exports = State;
  2040. /***/ }),
  2041. /***/ 3526:
  2042. /***/ (function(module) {
  2043. /**
  2044. * wp.media.selectionSync
  2045. *
  2046. * Sync an attachments selection in a state with another state.
  2047. *
  2048. * Allows for selecting multiple images in the Add Media workflow, and then
  2049. * switching to the Insert Gallery workflow while preserving the attachments selection.
  2050. *
  2051. * @memberOf wp.media
  2052. *
  2053. * @mixin
  2054. */
  2055. var selectionSync = {
  2056. /**
  2057. * @since 3.5.0
  2058. */
  2059. syncSelection: function() {
  2060. var selection = this.get('selection'),
  2061. manager = this.frame._selection;
  2062. if ( ! this.get('syncSelection') || ! manager || ! selection ) {
  2063. return;
  2064. }
  2065. /*
  2066. * If the selection supports multiple items, validate the stored
  2067. * attachments based on the new selection's conditions. Record
  2068. * the attachments that are not included; we'll maintain a
  2069. * reference to those. Other attachments are considered in flux.
  2070. */
  2071. if ( selection.multiple ) {
  2072. selection.reset( [], { silent: true });
  2073. selection.validateAll( manager.attachments );
  2074. manager.difference = _.difference( manager.attachments.models, selection.models );
  2075. }
  2076. // Sync the selection's single item with the master.
  2077. selection.single( manager.single );
  2078. },
  2079. /**
  2080. * Record the currently active attachments, which is a combination
  2081. * of the selection's attachments and the set of selected
  2082. * attachments that this specific selection considered invalid.
  2083. * Reset the difference and record the single attachment.
  2084. *
  2085. * @since 3.5.0
  2086. */
  2087. recordSelection: function() {
  2088. var selection = this.get('selection'),
  2089. manager = this.frame._selection;
  2090. if ( ! this.get('syncSelection') || ! manager || ! selection ) {
  2091. return;
  2092. }
  2093. if ( selection.multiple ) {
  2094. manager.attachments.reset( selection.toArray().concat( manager.difference ) );
  2095. manager.difference = [];
  2096. } else {
  2097. manager.attachments.add( selection.toArray() );
  2098. }
  2099. manager.single = selection._single;
  2100. }
  2101. };
  2102. module.exports = selectionSync;
  2103. /***/ }),
  2104. /***/ 8093:
  2105. /***/ (function(module) {
  2106. var View = wp.media.View,
  2107. AttachmentCompat;
  2108. /**
  2109. * wp.media.view.AttachmentCompat
  2110. *
  2111. * A view to display fields added via the `attachment_fields_to_edit` filter.
  2112. *
  2113. * @memberOf wp.media.view
  2114. *
  2115. * @class
  2116. * @augments wp.media.View
  2117. * @augments wp.Backbone.View
  2118. * @augments Backbone.View
  2119. */
  2120. AttachmentCompat = View.extend(/** @lends wp.media.view.AttachmentCompat.prototype */{
  2121. tagName: 'form',
  2122. className: 'compat-item',
  2123. events: {
  2124. 'submit': 'preventDefault',
  2125. 'change input': 'save',
  2126. 'change select': 'save',
  2127. 'change textarea': 'save'
  2128. },
  2129. initialize: function() {
  2130. this.listenTo( this.model, 'change:compat', this.render );
  2131. },
  2132. /**
  2133. * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
  2134. */
  2135. dispose: function() {
  2136. if ( this.$(':focus').length ) {
  2137. this.save();
  2138. }
  2139. /**
  2140. * call 'dispose' directly on the parent class
  2141. */
  2142. return View.prototype.dispose.apply( this, arguments );
  2143. },
  2144. /**
  2145. * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
  2146. */
  2147. render: function() {
  2148. var compat = this.model.get('compat');
  2149. if ( ! compat || ! compat.item ) {
  2150. return;
  2151. }
  2152. this.views.detach();
  2153. this.$el.html( compat.item );
  2154. this.views.render();
  2155. return this;
  2156. },
  2157. /**
  2158. * @param {Object} event
  2159. */
  2160. preventDefault: function( event ) {
  2161. event.preventDefault();
  2162. },
  2163. /**
  2164. * @param {Object} event
  2165. */
  2166. save: function( event ) {
  2167. var data = {};
  2168. if ( event ) {
  2169. event.preventDefault();
  2170. }
  2171. _.each( this.$el.serializeArray(), function( pair ) {
  2172. data[ pair.name ] = pair.value;
  2173. });
  2174. this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
  2175. this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
  2176. },
  2177. postSave: function() {
  2178. this.controller.trigger( 'attachment:compat:ready', ['ready'] );
  2179. }
  2180. });
  2181. module.exports = AttachmentCompat;
  2182. /***/ }),
  2183. /***/ 4906:
  2184. /***/ (function(module) {
  2185. var $ = jQuery,
  2186. AttachmentFilters;
  2187. /**
  2188. * wp.media.view.AttachmentFilters
  2189. *
  2190. * @memberOf wp.media.view
  2191. *
  2192. * @class
  2193. * @augments wp.media.View
  2194. * @augments wp.Backbone.View
  2195. * @augments Backbone.View
  2196. */
  2197. AttachmentFilters = wp.media.View.extend(/** @lends wp.media.view.AttachmentFilters.prototype */{
  2198. tagName: 'select',
  2199. className: 'attachment-filters',
  2200. id: 'media-attachment-filters',
  2201. events: {
  2202. change: 'change'
  2203. },
  2204. keys: [],
  2205. initialize: function() {
  2206. this.createFilters();
  2207. _.extend( this.filters, this.options.filters );
  2208. // Build `<option>` elements.
  2209. this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
  2210. return {
  2211. el: $( '<option></option>' ).val( value ).html( filter.text )[0],
  2212. priority: filter.priority || 50
  2213. };
  2214. }, this ).sortBy('priority').pluck('el').value() );
  2215. this.listenTo( this.model, 'change', this.select );
  2216. this.select();
  2217. },
  2218. /**
  2219. * @abstract
  2220. */
  2221. createFilters: function() {
  2222. this.filters = {};
  2223. },
  2224. /**
  2225. * When the selected filter changes, update the Attachment Query properties to match.
  2226. */
  2227. change: function() {
  2228. var filter = this.filters[ this.el.value ];
  2229. if ( filter ) {
  2230. this.model.set( filter.props );
  2231. }
  2232. },
  2233. select: function() {
  2234. var model = this.model,
  2235. value = 'all',
  2236. props = model.toJSON();
  2237. _.find( this.filters, function( filter, id ) {
  2238. var equal = _.all( filter.props, function( prop, key ) {
  2239. return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
  2240. });
  2241. if ( equal ) {
  2242. return value = id;
  2243. }
  2244. });
  2245. this.$el.val( value );
  2246. }
  2247. });
  2248. module.exports = AttachmentFilters;
  2249. /***/ }),
  2250. /***/ 2868:
  2251. /***/ (function(module) {
  2252. var l10n = wp.media.view.l10n,
  2253. All;
  2254. /**
  2255. * wp.media.view.AttachmentFilters.All
  2256. *
  2257. * @memberOf wp.media.view.AttachmentFilters
  2258. *
  2259. * @class
  2260. * @augments wp.media.view.AttachmentFilters
  2261. * @augments wp.media.View
  2262. * @augments wp.Backbone.View
  2263. * @augments Backbone.View
  2264. */
  2265. All = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.All.prototype */{
  2266. createFilters: function() {
  2267. var filters = {},
  2268. uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0;
  2269. _.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
  2270. filters[ key ] = {
  2271. text: text,
  2272. props: {
  2273. status: null,
  2274. type: key,
  2275. uploadedTo: null,
  2276. orderby: 'date',
  2277. order: 'DESC',
  2278. author: null
  2279. }
  2280. };
  2281. });
  2282. filters.all = {
  2283. text: l10n.allMediaItems,
  2284. props: {
  2285. status: null,
  2286. type: null,
  2287. uploadedTo: null,
  2288. orderby: 'date',
  2289. order: 'DESC',
  2290. author: null
  2291. },
  2292. priority: 10
  2293. };
  2294. if ( wp.media.view.settings.post.id ) {
  2295. filters.uploaded = {
  2296. text: l10n.uploadedToThisPost,
  2297. props: {
  2298. status: null,
  2299. type: null,
  2300. uploadedTo: wp.media.view.settings.post.id,
  2301. orderby: 'menuOrder',
  2302. order: 'ASC',
  2303. author: null
  2304. },
  2305. priority: 20
  2306. };
  2307. }
  2308. filters.unattached = {
  2309. text: l10n.unattached,
  2310. props: {
  2311. status: null,
  2312. uploadedTo: 0,
  2313. type: null,
  2314. orderby: 'menuOrder',
  2315. order: 'ASC',
  2316. author: null
  2317. },
  2318. priority: 50
  2319. };
  2320. if ( uid ) {
  2321. filters.mine = {
  2322. text: l10n.mine,
  2323. props: {
  2324. status: null,
  2325. type: null,
  2326. uploadedTo: null,
  2327. orderby: 'date',
  2328. order: 'DESC',
  2329. author: uid
  2330. },
  2331. priority: 50
  2332. };
  2333. }
  2334. if ( wp.media.view.settings.mediaTrash &&
  2335. this.controller.isModeActive( 'grid' ) ) {
  2336. filters.trash = {
  2337. text: l10n.trash,
  2338. props: {
  2339. uploadedTo: null,
  2340. status: 'trash',
  2341. type: null,
  2342. orderby: 'date',
  2343. order: 'DESC',
  2344. author: null
  2345. },
  2346. priority: 50
  2347. };
  2348. }
  2349. this.filters = filters;
  2350. }
  2351. });
  2352. module.exports = All;
  2353. /***/ }),
  2354. /***/ 9663:
  2355. /***/ (function(module) {
  2356. var l10n = wp.media.view.l10n,
  2357. DateFilter;
  2358. /**
  2359. * A filter dropdown for month/dates.
  2360. *
  2361. * @memberOf wp.media.view.AttachmentFilters
  2362. *
  2363. * @class
  2364. * @augments wp.media.view.AttachmentFilters
  2365. * @augments wp.media.View
  2366. * @augments wp.Backbone.View
  2367. * @augments Backbone.View
  2368. */
  2369. DateFilter = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Date.prototype */{
  2370. id: 'media-attachment-date-filters',
  2371. createFilters: function() {
  2372. var filters = {};
  2373. _.each( wp.media.view.settings.months || {}, function( value, index ) {
  2374. filters[ index ] = {
  2375. text: value.text,
  2376. props: {
  2377. year: value.year,
  2378. monthnum: value.month
  2379. }
  2380. };
  2381. });
  2382. filters.all = {
  2383. text: l10n.allDates,
  2384. props: {
  2385. monthnum: false,
  2386. year: false
  2387. },
  2388. priority: 10
  2389. };
  2390. this.filters = filters;
  2391. }
  2392. });
  2393. module.exports = DateFilter;
  2394. /***/ }),
  2395. /***/ 7040:
  2396. /***/ (function(module) {
  2397. var l10n = wp.media.view.l10n,
  2398. Uploaded;
  2399. /**
  2400. * wp.media.view.AttachmentFilters.Uploaded
  2401. *
  2402. * @memberOf wp.media.view.AttachmentFilters
  2403. *
  2404. * @class
  2405. * @augments wp.media.view.AttachmentFilters
  2406. * @augments wp.media.View
  2407. * @augments wp.Backbone.View
  2408. * @augments Backbone.View
  2409. */
  2410. Uploaded = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Uploaded.prototype */{
  2411. createFilters: function() {
  2412. var type = this.model.get('type'),
  2413. types = wp.media.view.settings.mimeTypes,
  2414. uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0,
  2415. text;
  2416. if ( types && type ) {
  2417. text = types[ type ];
  2418. }
  2419. this.filters = {
  2420. all: {
  2421. text: text || l10n.allMediaItems,
  2422. props: {
  2423. uploadedTo: null,
  2424. orderby: 'date',
  2425. order: 'DESC',
  2426. author: null
  2427. },
  2428. priority: 10
  2429. },
  2430. uploaded: {
  2431. text: l10n.uploadedToThisPost,
  2432. props: {
  2433. uploadedTo: wp.media.view.settings.post.id,
  2434. orderby: 'menuOrder',
  2435. order: 'ASC',
  2436. author: null
  2437. },
  2438. priority: 20
  2439. },
  2440. unattached: {
  2441. text: l10n.unattached,
  2442. props: {
  2443. uploadedTo: 0,
  2444. orderby: 'menuOrder',
  2445. order: 'ASC',
  2446. author: null
  2447. },
  2448. priority: 50
  2449. }
  2450. };
  2451. if ( uid ) {
  2452. this.filters.mine = {
  2453. text: l10n.mine,
  2454. props: {
  2455. orderby: 'date',
  2456. order: 'DESC',
  2457. author: uid
  2458. },
  2459. priority: 50
  2460. };
  2461. }
  2462. }
  2463. });
  2464. module.exports = Uploaded;
  2465. /***/ }),
  2466. /***/ 5019:
  2467. /***/ (function(module) {
  2468. var View = wp.media.View,
  2469. $ = jQuery,
  2470. Attachment;
  2471. /**
  2472. * wp.media.view.Attachment
  2473. *
  2474. * @memberOf wp.media.view
  2475. *
  2476. * @class
  2477. * @augments wp.media.View
  2478. * @augments wp.Backbone.View
  2479. * @augments Backbone.View
  2480. */
  2481. Attachment = View.extend(/** @lends wp.media.view.Attachment.prototype */{
  2482. tagName: 'li',
  2483. className: 'attachment',
  2484. template: wp.template('attachment'),
  2485. attributes: function() {
  2486. return {
  2487. 'tabIndex': 0,
  2488. 'role': 'checkbox',
  2489. 'aria-label': this.model.get( 'title' ),
  2490. 'aria-checked': false,
  2491. 'data-id': this.model.get( 'id' )
  2492. };
  2493. },
  2494. events: {
  2495. 'click': 'toggleSelectionHandler',
  2496. 'change [data-setting]': 'updateSetting',
  2497. 'change [data-setting] input': 'updateSetting',
  2498. 'change [data-setting] select': 'updateSetting',
  2499. 'change [data-setting] textarea': 'updateSetting',
  2500. 'click .attachment-close': 'removeFromLibrary',
  2501. 'click .check': 'checkClickHandler',
  2502. 'keydown': 'toggleSelectionHandler'
  2503. },
  2504. buttons: {},
  2505. initialize: function() {
  2506. var selection = this.options.selection,
  2507. options = _.defaults( this.options, {
  2508. rerenderOnModelChange: true
  2509. } );
  2510. if ( options.rerenderOnModelChange ) {
  2511. this.listenTo( this.model, 'change', this.render );
  2512. } else {
  2513. this.listenTo( this.model, 'change:percent', this.progress );
  2514. }
  2515. this.listenTo( this.model, 'change:title', this._syncTitle );
  2516. this.listenTo( this.model, 'change:caption', this._syncCaption );
  2517. this.listenTo( this.model, 'change:artist', this._syncArtist );
  2518. this.listenTo( this.model, 'change:album', this._syncAlbum );
  2519. // Update the selection.
  2520. this.listenTo( this.model, 'add', this.select );
  2521. this.listenTo( this.model, 'remove', this.deselect );
  2522. if ( selection ) {
  2523. selection.on( 'reset', this.updateSelect, this );
  2524. // Update the model's details view.
  2525. this.listenTo( this.model, 'selection:single selection:unsingle', this.details );
  2526. this.details( this.model, this.controller.state().get('selection') );
  2527. }
  2528. this.listenTo( this.controller.states, 'attachment:compat:waiting attachment:compat:ready', this.updateSave );
  2529. },
  2530. /**
  2531. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2532. */
  2533. dispose: function() {
  2534. var selection = this.options.selection;
  2535. // Make sure all settings are saved before removing the view.
  2536. this.updateAll();
  2537. if ( selection ) {
  2538. selection.off( null, null, this );
  2539. }
  2540. /**
  2541. * call 'dispose' directly on the parent class
  2542. */
  2543. View.prototype.dispose.apply( this, arguments );
  2544. return this;
  2545. },
  2546. /**
  2547. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2548. */
  2549. render: function() {
  2550. var options = _.defaults( this.model.toJSON(), {
  2551. orientation: 'landscape',
  2552. uploading: false,
  2553. type: '',
  2554. subtype: '',
  2555. icon: '',
  2556. filename: '',
  2557. caption: '',
  2558. title: '',
  2559. dateFormatted: '',
  2560. width: '',
  2561. height: '',
  2562. compat: false,
  2563. alt: '',
  2564. description: ''
  2565. }, this.options );
  2566. options.buttons = this.buttons;
  2567. options.describe = this.controller.state().get('describe');
  2568. if ( 'image' === options.type ) {
  2569. options.size = this.imageSize();
  2570. }
  2571. options.can = {};
  2572. if ( options.nonces ) {
  2573. options.can.remove = !! options.nonces['delete'];
  2574. options.can.save = !! options.nonces.update;
  2575. }
  2576. if ( this.controller.state().get('allowLocalEdits') ) {
  2577. options.allowLocalEdits = true;
  2578. }
  2579. if ( options.uploading && ! options.percent ) {
  2580. options.percent = 0;
  2581. }
  2582. this.views.detach();
  2583. this.$el.html( this.template( options ) );
  2584. this.$el.toggleClass( 'uploading', options.uploading );
  2585. if ( options.uploading ) {
  2586. this.$bar = this.$('.media-progress-bar div');
  2587. } else {
  2588. delete this.$bar;
  2589. }
  2590. // Check if the model is selected.
  2591. this.updateSelect();
  2592. // Update the save status.
  2593. this.updateSave();
  2594. this.views.render();
  2595. return this;
  2596. },
  2597. progress: function() {
  2598. if ( this.$bar && this.$bar.length ) {
  2599. this.$bar.width( this.model.get('percent') + '%' );
  2600. }
  2601. },
  2602. /**
  2603. * @param {Object} event
  2604. */
  2605. toggleSelectionHandler: function( event ) {
  2606. var method;
  2607. // Don't do anything inside inputs and on the attachment check and remove buttons.
  2608. if ( 'INPUT' === event.target.nodeName || 'BUTTON' === event.target.nodeName ) {
  2609. return;
  2610. }
  2611. // Catch arrow events.
  2612. if ( 37 === event.keyCode || 38 === event.keyCode || 39 === event.keyCode || 40 === event.keyCode ) {
  2613. this.controller.trigger( 'attachment:keydown:arrow', event );
  2614. return;
  2615. }
  2616. // Catch enter and space events.
  2617. if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
  2618. return;
  2619. }
  2620. event.preventDefault();
  2621. // In the grid view, bubble up an edit:attachment event to the controller.
  2622. if ( this.controller.isModeActive( 'grid' ) ) {
  2623. if ( this.controller.isModeActive( 'edit' ) ) {
  2624. // Pass the current target to restore focus when closing.
  2625. this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
  2626. return;
  2627. }
  2628. if ( this.controller.isModeActive( 'select' ) ) {
  2629. method = 'toggle';
  2630. }
  2631. }
  2632. if ( event.shiftKey ) {
  2633. method = 'between';
  2634. } else if ( event.ctrlKey || event.metaKey ) {
  2635. method = 'toggle';
  2636. }
  2637. this.toggleSelection({
  2638. method: method
  2639. });
  2640. this.controller.trigger( 'selection:toggle' );
  2641. },
  2642. /**
  2643. * @param {Object} options
  2644. */
  2645. toggleSelection: function( options ) {
  2646. var collection = this.collection,
  2647. selection = this.options.selection,
  2648. model = this.model,
  2649. method = options && options.method,
  2650. single, models, singleIndex, modelIndex;
  2651. if ( ! selection ) {
  2652. return;
  2653. }
  2654. single = selection.single();
  2655. method = _.isUndefined( method ) ? selection.multiple : method;
  2656. // If the `method` is set to `between`, select all models that
  2657. // exist between the current and the selected model.
  2658. if ( 'between' === method && single && selection.multiple ) {
  2659. // If the models are the same, short-circuit.
  2660. if ( single === model ) {
  2661. return;
  2662. }
  2663. singleIndex = collection.indexOf( single );
  2664. modelIndex = collection.indexOf( this.model );
  2665. if ( singleIndex < modelIndex ) {
  2666. models = collection.models.slice( singleIndex, modelIndex + 1 );
  2667. } else {
  2668. models = collection.models.slice( modelIndex, singleIndex + 1 );
  2669. }
  2670. selection.add( models );
  2671. selection.single( model );
  2672. return;
  2673. // If the `method` is set to `toggle`, just flip the selection
  2674. // status, regardless of whether the model is the single model.
  2675. } else if ( 'toggle' === method ) {
  2676. selection[ this.selected() ? 'remove' : 'add' ]( model );
  2677. selection.single( model );
  2678. return;
  2679. } else if ( 'add' === method ) {
  2680. selection.add( model );
  2681. selection.single( model );
  2682. return;
  2683. }
  2684. // Fixes bug that loses focus when selecting a featured image.
  2685. if ( ! method ) {
  2686. method = 'add';
  2687. }
  2688. if ( method !== 'add' ) {
  2689. method = 'reset';
  2690. }
  2691. if ( this.selected() ) {
  2692. /*
  2693. * If the model is the single model, remove it.
  2694. * If it is not the same as the single model,
  2695. * it now becomes the single model.
  2696. */
  2697. selection[ single === model ? 'remove' : 'single' ]( model );
  2698. } else {
  2699. /*
  2700. * If the model is not selected, run the `method` on the
  2701. * selection. By default, we `reset` the selection, but the
  2702. * `method` can be set to `add` the model to the selection.
  2703. */
  2704. selection[ method ]( model );
  2705. selection.single( model );
  2706. }
  2707. },
  2708. updateSelect: function() {
  2709. this[ this.selected() ? 'select' : 'deselect' ]();
  2710. },
  2711. /**
  2712. * @return {unresolved|boolean}
  2713. */
  2714. selected: function() {
  2715. var selection = this.options.selection;
  2716. if ( selection ) {
  2717. return !! selection.get( this.model.cid );
  2718. }
  2719. },
  2720. /**
  2721. * @param {Backbone.Model} model
  2722. * @param {Backbone.Collection} collection
  2723. */
  2724. select: function( model, collection ) {
  2725. var selection = this.options.selection,
  2726. controller = this.controller;
  2727. /*
  2728. * Check if a selection exists and if it's the collection provided.
  2729. * If they're not the same collection, bail; we're in another
  2730. * selection's event loop.
  2731. */
  2732. if ( ! selection || ( collection && collection !== selection ) ) {
  2733. return;
  2734. }
  2735. // Bail if the model is already selected.
  2736. if ( this.$el.hasClass( 'selected' ) ) {
  2737. return;
  2738. }
  2739. // Add 'selected' class to model, set aria-checked to true.
  2740. this.$el.addClass( 'selected' ).attr( 'aria-checked', true );
  2741. // Make the checkbox tabable, except in media grid (bulk select mode).
  2742. if ( ! ( controller.isModeActive( 'grid' ) && controller.isModeActive( 'select' ) ) ) {
  2743. this.$( '.check' ).attr( 'tabindex', '0' );
  2744. }
  2745. },
  2746. /**
  2747. * @param {Backbone.Model} model
  2748. * @param {Backbone.Collection} collection
  2749. */
  2750. deselect: function( model, collection ) {
  2751. var selection = this.options.selection;
  2752. /*
  2753. * Check if a selection exists and if it's the collection provided.
  2754. * If they're not the same collection, bail; we're in another
  2755. * selection's event loop.
  2756. */
  2757. if ( ! selection || ( collection && collection !== selection ) ) {
  2758. return;
  2759. }
  2760. this.$el.removeClass( 'selected' ).attr( 'aria-checked', false )
  2761. .find( '.check' ).attr( 'tabindex', '-1' );
  2762. },
  2763. /**
  2764. * @param {Backbone.Model} model
  2765. * @param {Backbone.Collection} collection
  2766. */
  2767. details: function( model, collection ) {
  2768. var selection = this.options.selection,
  2769. details;
  2770. if ( selection !== collection ) {
  2771. return;
  2772. }
  2773. details = selection.single();
  2774. this.$el.toggleClass( 'details', details === this.model );
  2775. },
  2776. /**
  2777. * @param {string} size
  2778. * @return {Object}
  2779. */
  2780. imageSize: function( size ) {
  2781. var sizes = this.model.get('sizes'), matched = false;
  2782. size = size || 'medium';
  2783. // Use the provided image size if possible.
  2784. if ( sizes ) {
  2785. if ( sizes[ size ] ) {
  2786. matched = sizes[ size ];
  2787. } else if ( sizes.large ) {
  2788. matched = sizes.large;
  2789. } else if ( sizes.thumbnail ) {
  2790. matched = sizes.thumbnail;
  2791. } else if ( sizes.full ) {
  2792. matched = sizes.full;
  2793. }
  2794. if ( matched ) {
  2795. return _.clone( matched );
  2796. }
  2797. }
  2798. return {
  2799. url: this.model.get('url'),
  2800. width: this.model.get('width'),
  2801. height: this.model.get('height'),
  2802. orientation: this.model.get('orientation')
  2803. };
  2804. },
  2805. /**
  2806. * @param {Object} event
  2807. */
  2808. updateSetting: function( event ) {
  2809. var $setting = $( event.target ).closest('[data-setting]'),
  2810. setting, value;
  2811. if ( ! $setting.length ) {
  2812. return;
  2813. }
  2814. setting = $setting.data('setting');
  2815. value = event.target.value;
  2816. if ( this.model.get( setting ) !== value ) {
  2817. this.save( setting, value );
  2818. }
  2819. },
  2820. /**
  2821. * Pass all the arguments to the model's save method.
  2822. *
  2823. * Records the aggregate status of all save requests and updates the
  2824. * view's classes accordingly.
  2825. */
  2826. save: function() {
  2827. var view = this,
  2828. save = this._save = this._save || { status: 'ready' },
  2829. request = this.model.save.apply( this.model, arguments ),
  2830. requests = save.requests ? $.when( request, save.requests ) : request;
  2831. // If we're waiting to remove 'Saved.', stop.
  2832. if ( save.savedTimer ) {
  2833. clearTimeout( save.savedTimer );
  2834. }
  2835. this.updateSave('waiting');
  2836. save.requests = requests;
  2837. requests.always( function() {
  2838. // If we've performed another request since this one, bail.
  2839. if ( save.requests !== requests ) {
  2840. return;
  2841. }
  2842. view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' );
  2843. save.savedTimer = setTimeout( function() {
  2844. view.updateSave('ready');
  2845. delete save.savedTimer;
  2846. }, 2000 );
  2847. });
  2848. },
  2849. /**
  2850. * @param {string} status
  2851. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2852. */
  2853. updateSave: function( status ) {
  2854. var save = this._save = this._save || { status: 'ready' };
  2855. if ( status && status !== save.status ) {
  2856. this.$el.removeClass( 'save-' + save.status );
  2857. save.status = status;
  2858. }
  2859. this.$el.addClass( 'save-' + save.status );
  2860. return this;
  2861. },
  2862. updateAll: function() {
  2863. var $settings = this.$('[data-setting]'),
  2864. model = this.model,
  2865. changed;
  2866. changed = _.chain( $settings ).map( function( el ) {
  2867. var $input = $('input, textarea, select, [value]', el ),
  2868. setting, value;
  2869. if ( ! $input.length ) {
  2870. return;
  2871. }
  2872. setting = $(el).data('setting');
  2873. value = $input.val();
  2874. // Record the value if it changed.
  2875. if ( model.get( setting ) !== value ) {
  2876. return [ setting, value ];
  2877. }
  2878. }).compact().object().value();
  2879. if ( ! _.isEmpty( changed ) ) {
  2880. model.save( changed );
  2881. }
  2882. },
  2883. /**
  2884. * @param {Object} event
  2885. */
  2886. removeFromLibrary: function( event ) {
  2887. // Catch enter and space events.
  2888. if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
  2889. return;
  2890. }
  2891. // Stop propagation so the model isn't selected.
  2892. event.stopPropagation();
  2893. this.collection.remove( this.model );
  2894. },
  2895. /**
  2896. * Add the model if it isn't in the selection, if it is in the selection,
  2897. * remove it.
  2898. *
  2899. * @param {[type]} event [description]
  2900. * @return {[type]} [description]
  2901. */
  2902. checkClickHandler: function ( event ) {
  2903. var selection = this.options.selection;
  2904. if ( ! selection ) {
  2905. return;
  2906. }
  2907. event.stopPropagation();
  2908. if ( selection.where( { id: this.model.get( 'id' ) } ).length ) {
  2909. selection.remove( this.model );
  2910. // Move focus back to the attachment tile (from the check).
  2911. this.$el.focus();
  2912. } else {
  2913. selection.add( this.model );
  2914. }
  2915. // Trigger an action button update.
  2916. this.controller.trigger( 'selection:toggle' );
  2917. }
  2918. });
  2919. // Ensure settings remain in sync between attachment views.
  2920. _.each({
  2921. caption: '_syncCaption',
  2922. title: '_syncTitle',
  2923. artist: '_syncArtist',
  2924. album: '_syncAlbum'
  2925. }, function( method, setting ) {
  2926. /**
  2927. * @function _syncCaption
  2928. * @memberOf wp.media.view.Attachment
  2929. * @instance
  2930. *
  2931. * @param {Backbone.Model} model
  2932. * @param {string} value
  2933. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2934. */
  2935. /**
  2936. * @function _syncTitle
  2937. * @memberOf wp.media.view.Attachment
  2938. * @instance
  2939. *
  2940. * @param {Backbone.Model} model
  2941. * @param {string} value
  2942. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2943. */
  2944. /**
  2945. * @function _syncArtist
  2946. * @memberOf wp.media.view.Attachment
  2947. * @instance
  2948. *
  2949. * @param {Backbone.Model} model
  2950. * @param {string} value
  2951. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2952. */
  2953. /**
  2954. * @function _syncAlbum
  2955. * @memberOf wp.media.view.Attachment
  2956. * @instance
  2957. *
  2958. * @param {Backbone.Model} model
  2959. * @param {string} value
  2960. * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  2961. */
  2962. Attachment.prototype[ method ] = function( model, value ) {
  2963. var $setting = this.$('[data-setting="' + setting + '"]');
  2964. if ( ! $setting.length ) {
  2965. return this;
  2966. }
  2967. /*
  2968. * If the updated value is in sync with the value in the DOM, there
  2969. * is no need to re-render. If we're currently editing the value,
  2970. * it will automatically be in sync, suppressing the re-render for
  2971. * the view we're editing, while updating any others.
  2972. */
  2973. if ( value === $setting.find('input, textarea, select, [value]').val() ) {
  2974. return this;
  2975. }
  2976. return this.render();
  2977. };
  2978. });
  2979. module.exports = Attachment;
  2980. /***/ }),
  2981. /***/ 7274:
  2982. /***/ (function(module) {
  2983. /* global ClipboardJS */
  2984. var Attachment = wp.media.view.Attachment,
  2985. l10n = wp.media.view.l10n,
  2986. $ = jQuery,
  2987. Details,
  2988. __ = wp.i18n.__;
  2989. Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
  2990. tagName: 'div',
  2991. className: 'attachment-details',
  2992. template: wp.template('attachment-details'),
  2993. /*
  2994. * Reset all the attributes inherited from Attachment including role=checkbox,
  2995. * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
  2996. */
  2997. attributes: {},
  2998. events: {
  2999. 'change [data-setting]': 'updateSetting',
  3000. 'change [data-setting] input': 'updateSetting',
  3001. 'change [data-setting] select': 'updateSetting',
  3002. 'change [data-setting] textarea': 'updateSetting',
  3003. 'click .delete-attachment': 'deleteAttachment',
  3004. 'click .trash-attachment': 'trashAttachment',
  3005. 'click .untrash-attachment': 'untrashAttachment',
  3006. 'click .edit-attachment': 'editAttachment',
  3007. 'keydown': 'toggleSelectionHandler'
  3008. },
  3009. /**
  3010. * Copies the attachment URL to the clipboard.
  3011. *
  3012. * @since 5.5.0
  3013. *
  3014. * @param {MouseEvent} event A click event.
  3015. *
  3016. * @return {void}
  3017. */
  3018. copyAttachmentDetailsURLClipboard: function() {
  3019. var clipboard = new ClipboardJS( '.copy-attachment-url' ),
  3020. successTimeout;
  3021. clipboard.on( 'success', function( event ) {
  3022. var triggerElement = $( event.trigger ),
  3023. successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
  3024. // Clear the selection and move focus back to the trigger.
  3025. event.clearSelection();
  3026. // Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
  3027. triggerElement.trigger( 'focus' );
  3028. // Show success visual feedback.
  3029. clearTimeout( successTimeout );
  3030. successElement.removeClass( 'hidden' );
  3031. // Hide success visual feedback after 3 seconds since last success.
  3032. successTimeout = setTimeout( function() {
  3033. successElement.addClass( 'hidden' );
  3034. }, 3000 );
  3035. // Handle success audible feedback.
  3036. wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
  3037. } );
  3038. },
  3039. /**
  3040. * Shows the details of an attachment.
  3041. *
  3042. * @since 3.5.0
  3043. *
  3044. * @constructs wp.media.view.Attachment.Details
  3045. * @augments wp.media.view.Attachment
  3046. *
  3047. * @return {void}
  3048. */
  3049. initialize: function() {
  3050. this.options = _.defaults( this.options, {
  3051. rerenderOnModelChange: false
  3052. });
  3053. // Call 'initialize' directly on the parent class.
  3054. Attachment.prototype.initialize.apply( this, arguments );
  3055. this.copyAttachmentDetailsURLClipboard();
  3056. },
  3057. /**
  3058. * Gets the focusable elements to move focus to.
  3059. *
  3060. * @since 5.3.0
  3061. */
  3062. getFocusableElements: function() {
  3063. var editedAttachment = $( 'li[data-id="' + this.model.id + '"]' );
  3064. this.previousAttachment = editedAttachment.prev();
  3065. this.nextAttachment = editedAttachment.next();
  3066. },
  3067. /**
  3068. * Moves focus to the previous or next attachment in the grid.
  3069. * Fallbacks to the upload button or media frame when there are no attachments.
  3070. *
  3071. * @since 5.3.0
  3072. */
  3073. moveFocus: function() {
  3074. if ( this.previousAttachment.length ) {
  3075. this.previousAttachment.trigger( 'focus' );
  3076. return;
  3077. }
  3078. if ( this.nextAttachment.length ) {
  3079. this.nextAttachment.trigger( 'focus' );
  3080. return;
  3081. }
  3082. // Fallback: move focus to the "Select Files" button in the media modal.
  3083. if ( this.controller.uploader && this.controller.uploader.$browser ) {
  3084. this.controller.uploader.$browser.trigger( 'focus' );
  3085. return;
  3086. }
  3087. // Last fallback.
  3088. this.moveFocusToLastFallback();
  3089. },
  3090. /**
  3091. * Moves focus to the media frame as last fallback.
  3092. *
  3093. * @since 5.3.0
  3094. */
  3095. moveFocusToLastFallback: function() {
  3096. // Last fallback: make the frame focusable and move focus to it.
  3097. $( '.media-frame' )
  3098. .attr( 'tabindex', '-1' )
  3099. .trigger( 'focus' );
  3100. },
  3101. /**
  3102. * Deletes an attachment.
  3103. *
  3104. * Deletes an attachment after asking for confirmation. After deletion,
  3105. * keeps focus in the modal.
  3106. *
  3107. * @since 3.5.0
  3108. *
  3109. * @param {MouseEvent} event A click event.
  3110. *
  3111. * @return {void}
  3112. */
  3113. deleteAttachment: function( event ) {
  3114. event.preventDefault();
  3115. this.getFocusableElements();
  3116. if ( window.confirm( l10n.warnDelete ) ) {
  3117. this.model.destroy( {
  3118. wait: true,
  3119. error: function() {
  3120. window.alert( l10n.errorDeleting );
  3121. }
  3122. } );
  3123. this.moveFocus();
  3124. }
  3125. },
  3126. /**
  3127. * Sets the Trash state on an attachment, or destroys the model itself.
  3128. *
  3129. * If the mediaTrash setting is set to true, trashes the attachment.
  3130. * Otherwise, the model itself is destroyed.
  3131. *
  3132. * @since 3.9.0
  3133. *
  3134. * @param {MouseEvent} event A click event.
  3135. *
  3136. * @return {void}
  3137. */
  3138. trashAttachment: function( event ) {
  3139. var library = this.controller.library,
  3140. self = this;
  3141. event.preventDefault();
  3142. this.getFocusableElements();
  3143. // When in the Media Library and the Media Trash is enabled.
  3144. if ( wp.media.view.settings.mediaTrash &&
  3145. 'edit-metadata' === this.controller.content.mode() ) {
  3146. this.model.set( 'status', 'trash' );
  3147. this.model.save().done( function() {
  3148. library._requery( true );
  3149. /*
  3150. * @todo We need to move focus back to the previous, next, or first
  3151. * attachment but the library gets re-queried and refreshed.
  3152. * Thus, the references to the previous attachments are lost.
  3153. * We need an alternate method.
  3154. */
  3155. self.moveFocusToLastFallback();
  3156. } );
  3157. } else {
  3158. this.model.destroy();
  3159. this.moveFocus();
  3160. }
  3161. },
  3162. /**
  3163. * Untrashes an attachment.
  3164. *
  3165. * @since 4.0.0
  3166. *
  3167. * @param {MouseEvent} event A click event.
  3168. *
  3169. * @return {void}
  3170. */
  3171. untrashAttachment: function( event ) {
  3172. var library = this.controller.library;
  3173. event.preventDefault();
  3174. this.model.set( 'status', 'inherit' );
  3175. this.model.save().done( function() {
  3176. library._requery( true );
  3177. } );
  3178. },
  3179. /**
  3180. * Opens the edit page for a specific attachment.
  3181. *
  3182. * @since 3.5.0
  3183. *
  3184. * @param {MouseEvent} event A click event.
  3185. *
  3186. * @return {void}
  3187. */
  3188. editAttachment: function( event ) {
  3189. var editState = this.controller.states.get( 'edit-image' );
  3190. if ( window.imageEdit && editState ) {
  3191. event.preventDefault();
  3192. editState.set( 'image', this.model );
  3193. this.controller.setState( 'edit-image' );
  3194. } else {
  3195. this.$el.addClass('needs-refresh');
  3196. }
  3197. },
  3198. /**
  3199. * Triggers an event on the controller when reverse tabbing (shift+tab).
  3200. *
  3201. * This event can be used to make sure to move the focus correctly.
  3202. *
  3203. * @since 4.0.0
  3204. *
  3205. * @fires wp.media.controller.MediaLibrary#attachment:details:shift-tab
  3206. * @fires wp.media.controller.MediaLibrary#attachment:keydown:arrow
  3207. *
  3208. * @param {KeyboardEvent} event A keyboard event.
  3209. *
  3210. * @return {boolean|void} Returns false or undefined.
  3211. */
  3212. toggleSelectionHandler: function( event ) {
  3213. if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
  3214. this.controller.trigger( 'attachment:details:shift-tab', event );
  3215. return false;
  3216. }
  3217. },
  3218. render: function() {
  3219. Attachment.prototype.render.apply( this, arguments );
  3220. wp.media.mixin.removeAllPlayers();
  3221. this.$( 'audio, video' ).each( function (i, elem) {
  3222. var el = wp.media.view.MediaDetails.prepareSrc( elem );
  3223. new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
  3224. } );
  3225. }
  3226. });
  3227. module.exports = Details;
  3228. /***/ }),
  3229. /***/ 4640:
  3230. /***/ (function(module) {
  3231. /**
  3232. * wp.media.view.Attachment.EditLibrary
  3233. *
  3234. * @memberOf wp.media.view.Attachment
  3235. *
  3236. * @class
  3237. * @augments wp.media.view.Attachment
  3238. * @augments wp.media.View
  3239. * @augments wp.Backbone.View
  3240. * @augments Backbone.View
  3241. */
  3242. var EditLibrary = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.EditLibrary.prototype */{
  3243. buttons: {
  3244. close: true
  3245. }
  3246. });
  3247. module.exports = EditLibrary;
  3248. /***/ }),
  3249. /***/ 1009:
  3250. /***/ (function(module) {
  3251. /**
  3252. * wp.media.view.Attachment.EditSelection
  3253. *
  3254. * @memberOf wp.media.view.Attachment
  3255. *
  3256. * @class
  3257. * @augments wp.media.view.Attachment.Selection
  3258. * @augments wp.media.view.Attachment
  3259. * @augments wp.media.View
  3260. * @augments wp.Backbone.View
  3261. * @augments Backbone.View
  3262. */
  3263. var EditSelection = wp.media.view.Attachment.Selection.extend(/** @lends wp.media.view.Attachment.EditSelection.prototype */{
  3264. buttons: {
  3265. close: true
  3266. }
  3267. });
  3268. module.exports = EditSelection;
  3269. /***/ }),
  3270. /***/ 9254:
  3271. /***/ (function(module) {
  3272. /**
  3273. * wp.media.view.Attachment.Library
  3274. *
  3275. * @memberOf wp.media.view.Attachment
  3276. *
  3277. * @class
  3278. * @augments wp.media.view.Attachment
  3279. * @augments wp.media.View
  3280. * @augments wp.Backbone.View
  3281. * @augments Backbone.View
  3282. */
  3283. var Library = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Library.prototype */{
  3284. buttons: {
  3285. check: true
  3286. }
  3287. });
  3288. module.exports = Library;
  3289. /***/ }),
  3290. /***/ 9003:
  3291. /***/ (function(module) {
  3292. /**
  3293. * wp.media.view.Attachment.Selection
  3294. *
  3295. * @memberOf wp.media.view.Attachment
  3296. *
  3297. * @class
  3298. * @augments wp.media.view.Attachment
  3299. * @augments wp.media.View
  3300. * @augments wp.Backbone.View
  3301. * @augments Backbone.View
  3302. */
  3303. var Selection = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Selection.prototype */{
  3304. className: 'attachment selection',
  3305. // On click, just select the model, instead of removing the model from
  3306. // the selection.
  3307. toggleSelection: function() {
  3308. this.options.selection.single( this.model );
  3309. }
  3310. });
  3311. module.exports = Selection;
  3312. /***/ }),
  3313. /***/ 8408:
  3314. /***/ (function(module) {
  3315. var View = wp.media.View,
  3316. $ = jQuery,
  3317. Attachments,
  3318. infiniteScrolling = wp.media.view.settings.infiniteScrolling;
  3319. Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
  3320. tagName: 'ul',
  3321. className: 'attachments',
  3322. attributes: {
  3323. tabIndex: -1
  3324. },
  3325. /**
  3326. * Represents the overview of attachments in the Media Library.
  3327. *
  3328. * The constructor binds events to the collection this view represents when
  3329. * adding or removing attachments or resetting the entire collection.
  3330. *
  3331. * @since 3.5.0
  3332. *
  3333. * @constructs
  3334. * @memberof wp.media.view
  3335. *
  3336. * @augments wp.media.View
  3337. *
  3338. * @listens collection:add
  3339. * @listens collection:remove
  3340. * @listens collection:reset
  3341. * @listens controller:library:selection:add
  3342. * @listens scrollElement:scroll
  3343. * @listens this:ready
  3344. * @listens controller:open
  3345. */
  3346. initialize: function() {
  3347. this.el.id = _.uniqueId('__attachments-view-');
  3348. /**
  3349. * @since 5.8.0 Added the `infiniteScrolling` parameter.
  3350. *
  3351. * @param infiniteScrolling Whether to enable infinite scrolling or use
  3352. * the default "load more" button.
  3353. * @param refreshSensitivity The time in milliseconds to throttle the scroll
  3354. * handler.
  3355. * @param refreshThreshold The amount of pixels that should be scrolled before
  3356. * loading more attachments from the server.
  3357. * @param AttachmentView The view class to be used for models in the
  3358. * collection.
  3359. * @param sortable A jQuery sortable options object
  3360. * ( http://api.jqueryui.com/sortable/ ).
  3361. * @param resize A boolean indicating whether or not to listen to
  3362. * resize events.
  3363. * @param idealColumnWidth The width in pixels which a column should have when
  3364. * calculating the total number of columns.
  3365. */
  3366. _.defaults( this.options, {
  3367. infiniteScrolling: infiniteScrolling || false,
  3368. refreshSensitivity: wp.media.isTouchDevice ? 300 : 200,
  3369. refreshThreshold: 3,
  3370. AttachmentView: wp.media.view.Attachment,
  3371. sortable: false,
  3372. resize: true,
  3373. idealColumnWidth: $( window ).width() < 640 ? 135 : 150
  3374. });
  3375. this._viewsByCid = {};
  3376. this.$window = $( window );
  3377. this.resizeEvent = 'resize.media-modal-columns';
  3378. this.collection.on( 'add', function( attachment ) {
  3379. this.views.add( this.createAttachmentView( attachment ), {
  3380. at: this.collection.indexOf( attachment )
  3381. });
  3382. }, this );
  3383. /*
  3384. * Find the view to be removed, delete it and call the remove function to clear
  3385. * any set event handlers.
  3386. */
  3387. this.collection.on( 'remove', function( attachment ) {
  3388. var view = this._viewsByCid[ attachment.cid ];
  3389. delete this._viewsByCid[ attachment.cid ];
  3390. if ( view ) {
  3391. view.remove();
  3392. }
  3393. }, this );
  3394. this.collection.on( 'reset', this.render, this );
  3395. this.controller.on( 'library:selection:add', this.attachmentFocus, this );
  3396. if ( this.options.infiniteScrolling ) {
  3397. // Throttle the scroll handler and bind this.
  3398. this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
  3399. this.options.scrollElement = this.options.scrollElement || this.el;
  3400. $( this.options.scrollElement ).on( 'scroll', this.scroll );
  3401. }
  3402. this.initSortable();
  3403. _.bindAll( this, 'setColumns' );
  3404. if ( this.options.resize ) {
  3405. this.on( 'ready', this.bindEvents );
  3406. this.controller.on( 'open', this.setColumns );
  3407. /*
  3408. * Call this.setColumns() after this view has been rendered in the
  3409. * DOM so attachments get proper width applied.
  3410. */
  3411. _.defer( this.setColumns, this );
  3412. }
  3413. },
  3414. /**
  3415. * Listens to the resizeEvent on the window.
  3416. *
  3417. * Adjusts the amount of columns accordingly. First removes any existing event
  3418. * handlers to prevent duplicate listeners.
  3419. *
  3420. * @since 4.0.0
  3421. *
  3422. * @listens window:resize
  3423. *
  3424. * @return {void}
  3425. */
  3426. bindEvents: function() {
  3427. this.$window.off( this.resizeEvent ).on( this.resizeEvent, _.debounce( this.setColumns, 50 ) );
  3428. },
  3429. /**
  3430. * Focuses the first item in the collection.
  3431. *
  3432. * @since 4.0.0
  3433. *
  3434. * @return {void}
  3435. */
  3436. attachmentFocus: function() {
  3437. /*
  3438. * @todo When uploading new attachments, this tries to move focus to
  3439. * the attachments grid. Actually, a progress bar gets initially displayed
  3440. * and then updated when uploading completes, so focus is lost.
  3441. * Additionally: this view is used for both the attachments list and
  3442. * the list of selected attachments in the bottom media toolbar. Thus, when
  3443. * uploading attachments, it is called twice and returns two different `this`.
  3444. * `this.columns` is truthy within the modal.
  3445. */
  3446. if ( this.columns ) {
  3447. // Move focus to the grid list within the modal.
  3448. this.$el.focus();
  3449. }
  3450. },
  3451. /**
  3452. * Restores focus to the selected item in the collection.
  3453. *
  3454. * Moves focus back to the first selected attachment in the grid. Used when
  3455. * tabbing backwards from the attachment details sidebar.
  3456. * See media.view.AttachmentsBrowser.
  3457. *
  3458. * @since 4.0.0
  3459. *
  3460. * @return {void}
  3461. */
  3462. restoreFocus: function() {
  3463. this.$( 'li.selected:first' ).focus();
  3464. },
  3465. /**
  3466. * Handles events for arrow key presses.
  3467. *
  3468. * Focuses the attachment in the direction of the used arrow key if it exists.
  3469. *
  3470. * @since 4.0.0
  3471. *
  3472. * @param {KeyboardEvent} event The keyboard event that triggered this function.
  3473. *
  3474. * @return {void}
  3475. */
  3476. arrowEvent: function( event ) {
  3477. var attachments = this.$el.children( 'li' ),
  3478. perRow = this.columns,
  3479. index = attachments.filter( ':focus' ).index(),
  3480. row = ( index + 1 ) <= perRow ? 1 : Math.ceil( ( index + 1 ) / perRow );
  3481. if ( index === -1 ) {
  3482. return;
  3483. }
  3484. // Left arrow = 37.
  3485. if ( 37 === event.keyCode ) {
  3486. if ( 0 === index ) {
  3487. return;
  3488. }
  3489. attachments.eq( index - 1 ).focus();
  3490. }
  3491. // Up arrow = 38.
  3492. if ( 38 === event.keyCode ) {
  3493. if ( 1 === row ) {
  3494. return;
  3495. }
  3496. attachments.eq( index - perRow ).focus();
  3497. }
  3498. // Right arrow = 39.
  3499. if ( 39 === event.keyCode ) {
  3500. if ( attachments.length === index ) {
  3501. return;
  3502. }
  3503. attachments.eq( index + 1 ).focus();
  3504. }
  3505. // Down arrow = 40.
  3506. if ( 40 === event.keyCode ) {
  3507. if ( Math.ceil( attachments.length / perRow ) === row ) {
  3508. return;
  3509. }
  3510. attachments.eq( index + perRow ).focus();
  3511. }
  3512. },
  3513. /**
  3514. * Clears any set event handlers.
  3515. *
  3516. * @since 3.5.0
  3517. *
  3518. * @return {void}
  3519. */
  3520. dispose: function() {
  3521. this.collection.props.off( null, null, this );
  3522. if ( this.options.resize ) {
  3523. this.$window.off( this.resizeEvent );
  3524. }
  3525. // Call 'dispose' directly on the parent class.
  3526. View.prototype.dispose.apply( this, arguments );
  3527. },
  3528. /**
  3529. * Calculates the amount of columns.
  3530. *
  3531. * Calculates the amount of columns and sets it on the data-columns attribute
  3532. * of .media-frame-content.
  3533. *
  3534. * @since 4.0.0
  3535. *
  3536. * @return {void}
  3537. */
  3538. setColumns: function() {
  3539. var prev = this.columns,
  3540. width = this.$el.width();
  3541. if ( width ) {
  3542. this.columns = Math.min( Math.round( width / this.options.idealColumnWidth ), 12 ) || 1;
  3543. if ( ! prev || prev !== this.columns ) {
  3544. this.$el.closest( '.media-frame-content' ).attr( 'data-columns', this.columns );
  3545. }
  3546. }
  3547. },
  3548. /**
  3549. * Initializes jQuery sortable on the attachment list.
  3550. *
  3551. * Fails gracefully if jQuery sortable doesn't exist or isn't passed
  3552. * in the options.
  3553. *
  3554. * @since 3.5.0
  3555. *
  3556. * @fires collection:reset
  3557. *
  3558. * @return {void}
  3559. */
  3560. initSortable: function() {
  3561. var collection = this.collection;
  3562. if ( ! this.options.sortable || ! $.fn.sortable ) {
  3563. return;
  3564. }
  3565. this.$el.sortable( _.extend({
  3566. // If the `collection` has a `comparator`, disable sorting.
  3567. disabled: !! collection.comparator,
  3568. /*
  3569. * Change the position of the attachment as soon as the mouse pointer
  3570. * overlaps a thumbnail.
  3571. */
  3572. tolerance: 'pointer',
  3573. // Record the initial `index` of the dragged model.
  3574. start: function( event, ui ) {
  3575. ui.item.data('sortableIndexStart', ui.item.index());
  3576. },
  3577. /*
  3578. * Update the model's index in the collection. Do so silently, as the view
  3579. * is already accurate.
  3580. */
  3581. update: function( event, ui ) {
  3582. var model = collection.at( ui.item.data('sortableIndexStart') ),
  3583. comparator = collection.comparator;
  3584. // Temporarily disable the comparator to prevent `add`
  3585. // from re-sorting.
  3586. delete collection.comparator;
  3587. // Silently shift the model to its new index.
  3588. collection.remove( model, {
  3589. silent: true
  3590. });
  3591. collection.add( model, {
  3592. silent: true,
  3593. at: ui.item.index()
  3594. });
  3595. // Restore the comparator.
  3596. collection.comparator = comparator;
  3597. // Fire the `reset` event to ensure other collections sync.
  3598. collection.trigger( 'reset', collection );
  3599. // If the collection is sorted by menu order, update the menu order.
  3600. collection.saveMenuOrder();
  3601. }
  3602. }, this.options.sortable ) );
  3603. /*
  3604. * If the `orderby` property is changed on the `collection`,
  3605. * check to see if we have a `comparator`. If so, disable sorting.
  3606. */
  3607. collection.props.on( 'change:orderby', function() {
  3608. this.$el.sortable( 'option', 'disabled', !! collection.comparator );
  3609. }, this );
  3610. this.collection.props.on( 'change:orderby', this.refreshSortable, this );
  3611. this.refreshSortable();
  3612. },
  3613. /**
  3614. * Disables jQuery sortable if collection has a comparator or collection.orderby
  3615. * equals menuOrder.
  3616. *
  3617. * @since 3.5.0
  3618. *
  3619. * @return {void}
  3620. */
  3621. refreshSortable: function() {
  3622. if ( ! this.options.sortable || ! $.fn.sortable ) {
  3623. return;
  3624. }
  3625. var collection = this.collection,
  3626. orderby = collection.props.get('orderby'),
  3627. enabled = 'menuOrder' === orderby || ! collection.comparator;
  3628. this.$el.sortable( 'option', 'disabled', ! enabled );
  3629. },
  3630. /**
  3631. * Creates a new view for an attachment and adds it to _viewsByCid.
  3632. *
  3633. * @since 3.5.0
  3634. *
  3635. * @param {wp.media.model.Attachment} attachment
  3636. *
  3637. * @return {wp.media.View} The created view.
  3638. */
  3639. createAttachmentView: function( attachment ) {
  3640. var view = new this.options.AttachmentView({
  3641. controller: this.controller,
  3642. model: attachment,
  3643. collection: this.collection,
  3644. selection: this.options.selection
  3645. });
  3646. return this._viewsByCid[ attachment.cid ] = view;
  3647. },
  3648. /**
  3649. * Prepares view for display.
  3650. *
  3651. * Creates views for every attachment in collection if the collection is not
  3652. * empty, otherwise clears all views and loads more attachments.
  3653. *
  3654. * @since 3.5.0
  3655. *
  3656. * @return {void}
  3657. */
  3658. prepare: function() {
  3659. if ( this.collection.length ) {
  3660. this.views.set( this.collection.map( this.createAttachmentView, this ) );
  3661. } else {
  3662. this.views.unset();
  3663. if ( this.options.infiniteScrolling ) {
  3664. this.collection.more().done( this.scroll );
  3665. }
  3666. }
  3667. },
  3668. /**
  3669. * Triggers the scroll function to check if we should query for additional
  3670. * attachments right away.
  3671. *
  3672. * @since 3.5.0
  3673. *
  3674. * @return {void}
  3675. */
  3676. ready: function() {
  3677. if ( this.options.infiniteScrolling ) {
  3678. this.scroll();
  3679. }
  3680. },
  3681. /**
  3682. * Handles scroll events.
  3683. *
  3684. * Shows the spinner if we're close to the bottom. Loads more attachments from
  3685. * server if we're {refreshThreshold} times away from the bottom.
  3686. *
  3687. * @since 3.5.0
  3688. *
  3689. * @return {void}
  3690. */
  3691. scroll: function() {
  3692. var view = this,
  3693. el = this.options.scrollElement,
  3694. scrollTop = el.scrollTop,
  3695. toolbar;
  3696. /*
  3697. * The scroll event occurs on the document, but the element that should be
  3698. * checked is the document body.
  3699. */
  3700. if ( el === document ) {
  3701. el = document.body;
  3702. scrollTop = $(document).scrollTop();
  3703. }
  3704. if ( ! $(el).is(':visible') || ! this.collection.hasMore() ) {
  3705. return;
  3706. }
  3707. toolbar = this.views.parent.toolbar;
  3708. // Show the spinner only if we are close to the bottom.
  3709. if ( el.scrollHeight - ( scrollTop + el.clientHeight ) < el.clientHeight / 3 ) {
  3710. toolbar.get('spinner').show();
  3711. }
  3712. if ( el.scrollHeight < scrollTop + ( el.clientHeight * this.options.refreshThreshold ) ) {
  3713. this.collection.more().done(function() {
  3714. view.scroll();
  3715. toolbar.get('spinner').hide();
  3716. });
  3717. }
  3718. }
  3719. });
  3720. module.exports = Attachments;
  3721. /***/ }),
  3722. /***/ 9239:
  3723. /***/ (function(module) {
  3724. var View = wp.media.View,
  3725. mediaTrash = wp.media.view.settings.mediaTrash,
  3726. l10n = wp.media.view.l10n,
  3727. $ = jQuery,
  3728. AttachmentsBrowser,
  3729. infiniteScrolling = wp.media.view.settings.infiniteScrolling,
  3730. __ = wp.i18n.__,
  3731. sprintf = wp.i18n.sprintf;
  3732. /**
  3733. * wp.media.view.AttachmentsBrowser
  3734. *
  3735. * @memberOf wp.media.view
  3736. *
  3737. * @class
  3738. * @augments wp.media.View
  3739. * @augments wp.Backbone.View
  3740. * @augments Backbone.View
  3741. *
  3742. * @param {object} [options] The options hash passed to the view.
  3743. * @param {boolean|string} [options.filters=false] Which filters to show in the browser's toolbar.
  3744. * Accepts 'uploaded' and 'all'.
  3745. * @param {boolean} [options.search=true] Whether to show the search interface in the
  3746. * browser's toolbar.
  3747. * @param {boolean} [options.date=true] Whether to show the date filter in the
  3748. * browser's toolbar.
  3749. * @param {boolean} [options.display=false] Whether to show the attachments display settings
  3750. * view in the sidebar.
  3751. * @param {boolean|string} [options.sidebar=true] Whether to create a sidebar for the browser.
  3752. * Accepts true, false, and 'errors'.
  3753. */
  3754. AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.prototype */{
  3755. tagName: 'div',
  3756. className: 'attachments-browser',
  3757. initialize: function() {
  3758. _.defaults( this.options, {
  3759. filters: false,
  3760. search: true,
  3761. date: true,
  3762. display: false,
  3763. sidebar: true,
  3764. AttachmentView: wp.media.view.Attachment.Library
  3765. });
  3766. this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
  3767. this.controller.on( 'edit:selection', this.editSelection );
  3768. // In the Media Library, the sidebar is used to display errors before the attachments grid.
  3769. if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
  3770. this.createSidebar();
  3771. }
  3772. /*
  3773. * In the grid mode (the Media Library), place the Inline Uploader before
  3774. * other sections so that the visual order and the DOM order match. This way,
  3775. * the Inline Uploader in the Media Library is right after the "Add New"
  3776. * button, see ticket #37188.
  3777. */
  3778. if ( this.controller.isModeActive( 'grid' ) ) {
  3779. this.createUploader();
  3780. /*
  3781. * Create a multi-purpose toolbar. Used as main toolbar in the Media Library
  3782. * and also for other things, for example the "Drag and drop to reorder" and
  3783. * "Suggested dimensions" info in the media modal.
  3784. */
  3785. this.createToolbar();
  3786. } else {
  3787. this.createToolbar();
  3788. this.createUploader();
  3789. }
  3790. // Add a heading before the attachments list.
  3791. this.createAttachmentsHeading();
  3792. // Create the attachments wrapper view.
  3793. this.createAttachmentsWrapperView();
  3794. if ( ! infiniteScrolling ) {
  3795. this.$el.addClass( 'has-load-more' );
  3796. this.createLoadMoreView();
  3797. }
  3798. // For accessibility reasons, place the normal sidebar after the attachments, see ticket #36909.
  3799. if ( this.options.sidebar && 'errors' !== this.options.sidebar ) {
  3800. this.createSidebar();
  3801. }
  3802. this.updateContent();
  3803. if ( ! infiniteScrolling ) {
  3804. this.updateLoadMoreView();
  3805. }
  3806. if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
  3807. this.$el.addClass( 'hide-sidebar' );
  3808. if ( 'errors' === this.options.sidebar ) {
  3809. this.$el.addClass( 'sidebar-for-errors' );
  3810. }
  3811. }
  3812. this.collection.on( 'add remove reset', this.updateContent, this );
  3813. if ( ! infiniteScrolling ) {
  3814. this.collection.on( 'add remove reset', this.updateLoadMoreView, this );
  3815. }
  3816. // The non-cached or cached attachments query has completed.
  3817. this.collection.on( 'attachments:received', this.announceSearchResults, this );
  3818. },
  3819. /**
  3820. * Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
  3821. * the number of search results to screen reader users. This function is
  3822. * debounced because the collection updates multiple times.
  3823. *
  3824. * @since 5.3.0
  3825. *
  3826. * @return {void}
  3827. */
  3828. announceSearchResults: _.debounce( function() {
  3829. var count,
  3830. /* translators: Accessibility text. %d: Number of attachments found in a search. */
  3831. mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Click load more for more results.' );
  3832. if ( infiniteScrolling ) {
  3833. /* translators: Accessibility text. %d: Number of attachments found in a search. */
  3834. mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Scroll the page for more results.' );
  3835. }
  3836. if ( this.collection.mirroring && this.collection.mirroring.args.s ) {
  3837. count = this.collection.length;
  3838. if ( 0 === count ) {
  3839. wp.a11y.speak( l10n.noMediaTryNewSearch );
  3840. return;
  3841. }
  3842. if ( this.collection.hasMore() ) {
  3843. wp.a11y.speak( mediaFoundHasMoreResultsMessage.replace( '%d', count ) );
  3844. return;
  3845. }
  3846. wp.a11y.speak( l10n.mediaFound.replace( '%d', count ) );
  3847. }
  3848. }, 200 ),
  3849. editSelection: function( modal ) {
  3850. // When editing a selection, move focus to the "Go to library" button.
  3851. modal.$( '.media-button-backToLibrary' ).focus();
  3852. },
  3853. /**
  3854. * @return {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining.
  3855. */
  3856. dispose: function() {
  3857. this.options.selection.off( null, null, this );
  3858. View.prototype.dispose.apply( this, arguments );
  3859. return this;
  3860. },
  3861. createToolbar: function() {
  3862. var LibraryViewSwitcher, Filters, toolbarOptions,
  3863. showFilterByType = -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] );
  3864. toolbarOptions = {
  3865. controller: this.controller
  3866. };
  3867. if ( this.controller.isModeActive( 'grid' ) ) {
  3868. toolbarOptions.className = 'media-toolbar wp-filter';
  3869. }
  3870. /**
  3871. * @member {wp.media.view.Toolbar}
  3872. */
  3873. this.toolbar = new wp.media.view.Toolbar( toolbarOptions );
  3874. this.views.add( this.toolbar );
  3875. this.toolbar.set( 'spinner', new wp.media.view.Spinner({
  3876. priority: -20
  3877. }) );
  3878. if ( showFilterByType || this.options.date ) {
  3879. /*
  3880. * Create a h2 heading before the select elements that filter attachments.
  3881. * This heading is visible in the modal and visually hidden in the grid.
  3882. */
  3883. this.toolbar.set( 'filters-heading', new wp.media.view.Heading( {
  3884. priority: -100,
  3885. text: l10n.filterAttachments,
  3886. level: 'h2',
  3887. className: 'media-attachments-filter-heading'
  3888. }).render() );
  3889. }
  3890. if ( showFilterByType ) {
  3891. // "Filters" is a <select>, a visually hidden label element needs to be rendered before.
  3892. this.toolbar.set( 'filtersLabel', new wp.media.view.Label({
  3893. value: l10n.filterByType,
  3894. attributes: {
  3895. 'for': 'media-attachment-filters'
  3896. },
  3897. priority: -80
  3898. }).render() );
  3899. if ( 'uploaded' === this.options.filters ) {
  3900. this.toolbar.set( 'filters', new wp.media.view.AttachmentFilters.Uploaded({
  3901. controller: this.controller,
  3902. model: this.collection.props,
  3903. priority: -80
  3904. }).render() );
  3905. } else {
  3906. Filters = new wp.media.view.AttachmentFilters.All({
  3907. controller: this.controller,
  3908. model: this.collection.props,
  3909. priority: -80
  3910. });
  3911. this.toolbar.set( 'filters', Filters.render() );
  3912. }
  3913. }
  3914. /*
  3915. * Feels odd to bring the global media library switcher into the Attachment browser view.
  3916. * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
  3917. * which the controller can tap into and add this view?
  3918. */
  3919. if ( this.controller.isModeActive( 'grid' ) ) {
  3920. LibraryViewSwitcher = View.extend({
  3921. className: 'view-switch media-grid-view-switch',
  3922. template: wp.template( 'media-library-view-switcher')
  3923. });
  3924. this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
  3925. controller: this.controller,
  3926. priority: -90
  3927. }).render() );
  3928. // DateFilter is a <select>, a visually hidden label element needs to be rendered before.
  3929. this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
  3930. value: l10n.filterByDate,
  3931. attributes: {
  3932. 'for': 'media-attachment-date-filters'
  3933. },
  3934. priority: -75
  3935. }).render() );
  3936. this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
  3937. controller: this.controller,
  3938. model: this.collection.props,
  3939. priority: -75
  3940. }).render() );
  3941. // BulkSelection is a <div> with subviews, including screen reader text.
  3942. this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
  3943. text: l10n.bulkSelect,
  3944. controller: this.controller,
  3945. priority: -70
  3946. }).render() );
  3947. this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
  3948. filters: Filters,
  3949. style: 'primary',
  3950. disabled: true,
  3951. text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
  3952. controller: this.controller,
  3953. priority: -80,
  3954. click: function() {
  3955. var changed = [], removed = [],
  3956. selection = this.controller.state().get( 'selection' ),
  3957. library = this.controller.state().get( 'library' );
  3958. if ( ! selection.length ) {
  3959. return;
  3960. }
  3961. if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
  3962. return;
  3963. }
  3964. if ( mediaTrash &&
  3965. 'trash' !== selection.at( 0 ).get( 'status' ) &&
  3966. ! window.confirm( l10n.warnBulkTrash ) ) {
  3967. return;
  3968. }
  3969. selection.each( function( model ) {
  3970. if ( ! model.get( 'nonces' )['delete'] ) {
  3971. removed.push( model );
  3972. return;
  3973. }
  3974. if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
  3975. model.set( 'status', 'inherit' );
  3976. changed.push( model.save() );
  3977. removed.push( model );
  3978. } else if ( mediaTrash ) {
  3979. model.set( 'status', 'trash' );
  3980. changed.push( model.save() );
  3981. removed.push( model );
  3982. } else {
  3983. model.destroy({wait: true});
  3984. }
  3985. } );
  3986. if ( changed.length ) {
  3987. selection.remove( removed );
  3988. $.when.apply( null, changed ).then( _.bind( function() {
  3989. library._requery( true );
  3990. this.controller.trigger( 'selection:action:done' );
  3991. }, this ) );
  3992. } else {
  3993. this.controller.trigger( 'selection:action:done' );
  3994. }
  3995. }
  3996. }).render() );
  3997. if ( mediaTrash ) {
  3998. this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
  3999. filters: Filters,
  4000. style: 'link button-link-delete',
  4001. disabled: true,
  4002. text: l10n.deletePermanently,
  4003. controller: this.controller,
  4004. priority: -55,
  4005. click: function() {
  4006. var removed = [],
  4007. destroy = [],
  4008. selection = this.controller.state().get( 'selection' );
  4009. if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
  4010. return;
  4011. }
  4012. selection.each( function( model ) {
  4013. if ( ! model.get( 'nonces' )['delete'] ) {
  4014. removed.push( model );
  4015. return;
  4016. }
  4017. destroy.push( model );
  4018. } );
  4019. if ( removed.length ) {
  4020. selection.remove( removed );
  4021. }
  4022. if ( destroy.length ) {
  4023. $.when.apply( null, destroy.map( function (item) {
  4024. return item.destroy();
  4025. } ) ).then( _.bind( function() {
  4026. this.controller.trigger( 'selection:action:done' );
  4027. }, this ) );
  4028. }
  4029. }
  4030. }).render() );
  4031. }
  4032. } else if ( this.options.date ) {
  4033. // DateFilter is a <select>, a visually hidden label element needs to be rendered before.
  4034. this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
  4035. value: l10n.filterByDate,
  4036. attributes: {
  4037. 'for': 'media-attachment-date-filters'
  4038. },
  4039. priority: -75
  4040. }).render() );
  4041. this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
  4042. controller: this.controller,
  4043. model: this.collection.props,
  4044. priority: -75
  4045. }).render() );
  4046. }
  4047. if ( this.options.search ) {
  4048. // Search is an input, a visually hidden label element needs to be rendered before.
  4049. this.toolbar.set( 'searchLabel', new wp.media.view.Label({
  4050. value: l10n.searchLabel,
  4051. className: 'media-search-input-label',
  4052. attributes: {
  4053. 'for': 'media-search-input'
  4054. },
  4055. priority: 60
  4056. }).render() );
  4057. this.toolbar.set( 'search', new wp.media.view.Search({
  4058. controller: this.controller,
  4059. model: this.collection.props,
  4060. priority: 60
  4061. }).render() );
  4062. }
  4063. if ( this.options.dragInfo ) {
  4064. this.toolbar.set( 'dragInfo', new View({
  4065. el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
  4066. priority: -40
  4067. }) );
  4068. }
  4069. if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
  4070. this.toolbar.set( 'suggestedDimensions', new View({
  4071. el: $( '<div class="instructions">' + l10n.suggestedDimensions.replace( '%1$s', this.options.suggestedWidth ).replace( '%2$s', this.options.suggestedHeight ) + '</div>' )[0],
  4072. priority: -40
  4073. }) );
  4074. }
  4075. },
  4076. updateContent: function() {
  4077. var view = this,
  4078. noItemsView;
  4079. if ( this.controller.isModeActive( 'grid' ) ) {
  4080. // Usually the media library.
  4081. noItemsView = view.attachmentsNoResults;
  4082. } else {
  4083. // Usually the media modal.
  4084. noItemsView = view.uploader;
  4085. }
  4086. if ( ! this.collection.length ) {
  4087. this.toolbar.get( 'spinner' ).show();
  4088. this.dfd = this.collection.more().done( function() {
  4089. if ( ! view.collection.length ) {
  4090. noItemsView.$el.removeClass( 'hidden' );
  4091. } else {
  4092. noItemsView.$el.addClass( 'hidden' );
  4093. }
  4094. view.toolbar.get( 'spinner' ).hide();
  4095. } );
  4096. } else {
  4097. noItemsView.$el.addClass( 'hidden' );
  4098. view.toolbar.get( 'spinner' ).hide();
  4099. }
  4100. },
  4101. createUploader: function() {
  4102. this.uploader = new wp.media.view.UploaderInline({
  4103. controller: this.controller,
  4104. status: false,
  4105. message: this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
  4106. canClose: this.controller.isModeActive( 'grid' )
  4107. });
  4108. this.uploader.$el.addClass( 'hidden' );
  4109. this.views.add( this.uploader );
  4110. },
  4111. toggleUploader: function() {
  4112. if ( this.uploader.$el.hasClass( 'hidden' ) ) {
  4113. this.uploader.show();
  4114. } else {
  4115. this.uploader.hide();
  4116. }
  4117. },
  4118. /**
  4119. * Creates the Attachments wrapper view.
  4120. *
  4121. * @since 5.8.0
  4122. *
  4123. * @return {void}
  4124. */
  4125. createAttachmentsWrapperView: function() {
  4126. this.attachmentsWrapper = new wp.media.View( {
  4127. className: 'attachments-wrapper'
  4128. } );
  4129. // Create the list of attachments.
  4130. this.views.add( this.attachmentsWrapper );
  4131. this.createAttachments();
  4132. },
  4133. createAttachments: function() {
  4134. this.attachments = new wp.media.view.Attachments({
  4135. controller: this.controller,
  4136. collection: this.collection,
  4137. selection: this.options.selection,
  4138. model: this.model,
  4139. sortable: this.options.sortable,
  4140. scrollElement: this.options.scrollElement,
  4141. idealColumnWidth: this.options.idealColumnWidth,
  4142. // The single `Attachment` view to be used in the `Attachments` view.
  4143. AttachmentView: this.options.AttachmentView
  4144. });
  4145. // Add keydown listener to the instance of the Attachments view.
  4146. this.controller.on( 'attachment:keydown:arrow', _.bind( this.attachments.arrowEvent, this.attachments ) );
  4147. this.controller.on( 'attachment:details:shift-tab', _.bind( this.attachments.restoreFocus, this.attachments ) );
  4148. this.views.add( '.attachments-wrapper', this.attachments );
  4149. if ( this.controller.isModeActive( 'grid' ) ) {
  4150. this.attachmentsNoResults = new View({
  4151. controller: this.controller,
  4152. tagName: 'p'
  4153. });
  4154. this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
  4155. this.attachmentsNoResults.$el.html( l10n.noMedia );
  4156. this.views.add( this.attachmentsNoResults );
  4157. }
  4158. },
  4159. /**
  4160. * Creates the load more button and attachments counter view.
  4161. *
  4162. * @since 5.8.0
  4163. *
  4164. * @return {void}
  4165. */
  4166. createLoadMoreView: function() {
  4167. var view = this;
  4168. this.loadMoreWrapper = new View( {
  4169. controller: this.controller,
  4170. className: 'load-more-wrapper'
  4171. } );
  4172. this.loadMoreCount = new View( {
  4173. controller: this.controller,
  4174. tagName: 'p',
  4175. className: 'load-more-count hidden'
  4176. } );
  4177. this.loadMoreButton = new wp.media.view.Button( {
  4178. text: __( 'Load more' ),
  4179. className: 'load-more hidden',
  4180. style: 'primary',
  4181. size: '',
  4182. click: function() {
  4183. view.loadMoreAttachments();
  4184. }
  4185. } );
  4186. this.loadMoreSpinner = new wp.media.view.Spinner();
  4187. this.loadMoreJumpToFirst = new wp.media.view.Button( {
  4188. text: __( 'Jump to first loaded item' ),
  4189. className: 'load-more-jump hidden',
  4190. size: '',
  4191. click: function() {
  4192. view.jumpToFirstAddedItem();
  4193. }
  4194. } );
  4195. this.views.add( '.attachments-wrapper', this.loadMoreWrapper );
  4196. this.views.add( '.load-more-wrapper', this.loadMoreSpinner );
  4197. this.views.add( '.load-more-wrapper', this.loadMoreCount );
  4198. this.views.add( '.load-more-wrapper', this.loadMoreButton );
  4199. this.views.add( '.load-more-wrapper', this.loadMoreJumpToFirst );
  4200. },
  4201. /**
  4202. * Updates the Load More view. This function is debounced because the
  4203. * collection updates multiple times at the add, remove, and reset events.
  4204. * We need it to run only once, after all attachments are added or removed.
  4205. *
  4206. * @since 5.8.0
  4207. *
  4208. * @return {void}
  4209. */
  4210. updateLoadMoreView: _.debounce( function() {
  4211. // Ensure the load more view elements are initially hidden at each update.
  4212. this.loadMoreButton.$el.addClass( 'hidden' );
  4213. this.loadMoreCount.$el.addClass( 'hidden' );
  4214. this.loadMoreJumpToFirst.$el.addClass( 'hidden' ).prop( 'disabled', true );
  4215. if ( ! this.collection.getTotalAttachments() ) {
  4216. return;
  4217. }
  4218. if ( this.collection.length ) {
  4219. this.loadMoreCount.$el.text(
  4220. /* translators: 1: Number of displayed attachments, 2: Number of total attachments. */
  4221. sprintf(
  4222. __( 'Showing %1$s of %2$s media items' ),
  4223. this.collection.length,
  4224. this.collection.getTotalAttachments()
  4225. )
  4226. );
  4227. this.loadMoreCount.$el.removeClass( 'hidden' );
  4228. }
  4229. /*
  4230. * Notice that while the collection updates multiple times hasMore() may
  4231. * return true when it's actually not true.
  4232. */
  4233. if ( this.collection.hasMore() ) {
  4234. this.loadMoreButton.$el.removeClass( 'hidden' );
  4235. }
  4236. // Find the media item to move focus to. The jQuery `eq()` index is zero-based.
  4237. this.firstAddedMediaItem = this.$el.find( '.attachment' ).eq( this.firstAddedMediaItemIndex );
  4238. // If there's a media item to move focus to, make the "Jump to" button available.
  4239. if ( this.firstAddedMediaItem.length ) {
  4240. this.firstAddedMediaItem.addClass( 'new-media' );
  4241. this.loadMoreJumpToFirst.$el.removeClass( 'hidden' ).prop( 'disabled', false );
  4242. }
  4243. // If there are new items added, but no more to be added, move focus to Jump button.
  4244. if ( this.firstAddedMediaItem.length && ! this.collection.hasMore() ) {
  4245. this.loadMoreJumpToFirst.$el.trigger( 'focus' );
  4246. }
  4247. }, 10 ),
  4248. /**
  4249. * Loads more attachments.
  4250. *
  4251. * @since 5.8.0
  4252. *
  4253. * @return {void}
  4254. */
  4255. loadMoreAttachments: function() {
  4256. var view = this;
  4257. if ( ! this.collection.hasMore() ) {
  4258. return;
  4259. }
  4260. /*
  4261. * The collection index is zero-based while the length counts the actual
  4262. * amount of items. Thus the length is equivalent to the position of the
  4263. * first added item.
  4264. */
  4265. this.firstAddedMediaItemIndex = this.collection.length;
  4266. this.$el.addClass( 'more-loaded' );
  4267. this.collection.each( function( attachment ) {
  4268. var attach_id = attachment.attributes.id;
  4269. $( '[data-id="' + attach_id + '"]' ).addClass( 'found-media' );
  4270. });
  4271. view.loadMoreSpinner.show();
  4272. this.collection.once( 'attachments:received', function() {
  4273. view.loadMoreSpinner.hide();
  4274. } );
  4275. this.collection.more();
  4276. },
  4277. /**
  4278. * Moves focus to the first new added item. .
  4279. *
  4280. * @since 5.8.0
  4281. *
  4282. * @return {void}
  4283. */
  4284. jumpToFirstAddedItem: function() {
  4285. // Set focus on first added item.
  4286. this.firstAddedMediaItem.focus();
  4287. },
  4288. createAttachmentsHeading: function() {
  4289. this.attachmentsHeading = new wp.media.view.Heading( {
  4290. text: l10n.attachmentsList,
  4291. level: 'h2',
  4292. className: 'media-views-heading screen-reader-text'
  4293. } );
  4294. this.views.add( this.attachmentsHeading );
  4295. },
  4296. createSidebar: function() {
  4297. var options = this.options,
  4298. selection = options.selection,
  4299. sidebar = this.sidebar = new wp.media.view.Sidebar({
  4300. controller: this.controller
  4301. });
  4302. this.views.add( sidebar );
  4303. if ( this.controller.uploader ) {
  4304. sidebar.set( 'uploads', new wp.media.view.UploaderStatus({
  4305. controller: this.controller,
  4306. priority: 40
  4307. }) );
  4308. }
  4309. selection.on( 'selection:single', this.createSingle, this );
  4310. selection.on( 'selection:unsingle', this.disposeSingle, this );
  4311. if ( selection.single() ) {
  4312. this.createSingle();
  4313. }
  4314. },
  4315. createSingle: function() {
  4316. var sidebar = this.sidebar,
  4317. single = this.options.selection.single();
  4318. sidebar.set( 'details', new wp.media.view.Attachment.Details({
  4319. controller: this.controller,
  4320. model: single,
  4321. priority: 80
  4322. }) );
  4323. sidebar.set( 'compat', new wp.media.view.AttachmentCompat({
  4324. controller: this.controller,
  4325. model: single,
  4326. priority: 120
  4327. }) );
  4328. if ( this.options.display ) {
  4329. sidebar.set( 'display', new wp.media.view.Settings.AttachmentDisplay({
  4330. controller: this.controller,
  4331. model: this.model.display( single ),
  4332. attachment: single,
  4333. priority: 160,
  4334. userSettings: this.model.get('displayUserSettings')
  4335. }) );
  4336. }
  4337. // Show the sidebar on mobile.
  4338. if ( this.model.id === 'insert' ) {
  4339. sidebar.$el.addClass( 'visible' );
  4340. }
  4341. },
  4342. disposeSingle: function() {
  4343. var sidebar = this.sidebar;
  4344. sidebar.unset('details');
  4345. sidebar.unset('compat');
  4346. sidebar.unset('display');
  4347. // Hide the sidebar on mobile.
  4348. sidebar.$el.removeClass( 'visible' );
  4349. }
  4350. });
  4351. module.exports = AttachmentsBrowser;
  4352. /***/ }),
  4353. /***/ 1223:
  4354. /***/ (function(module) {
  4355. var Attachments = wp.media.view.Attachments,
  4356. Selection;
  4357. /**
  4358. * wp.media.view.Attachments.Selection
  4359. *
  4360. * @memberOf wp.media.view.Attachments
  4361. *
  4362. * @class
  4363. * @augments wp.media.view.Attachments
  4364. * @augments wp.media.View
  4365. * @augments wp.Backbone.View
  4366. * @augments Backbone.View
  4367. */
  4368. Selection = Attachments.extend(/** @lends wp.media.view.Attachments.Selection.prototype */{
  4369. events: {},
  4370. initialize: function() {
  4371. _.defaults( this.options, {
  4372. sortable: false,
  4373. resize: false,
  4374. // The single `Attachment` view to be used in the `Attachments` view.
  4375. AttachmentView: wp.media.view.Attachment.Selection
  4376. });
  4377. // Call 'initialize' directly on the parent class.
  4378. return Attachments.prototype.initialize.apply( this, arguments );
  4379. }
  4380. });
  4381. module.exports = Selection;
  4382. /***/ }),
  4383. /***/ 4094:
  4384. /***/ (function(module) {
  4385. var $ = Backbone.$,
  4386. ButtonGroup;
  4387. /**
  4388. * wp.media.view.ButtonGroup
  4389. *
  4390. * @memberOf wp.media.view
  4391. *
  4392. * @class
  4393. * @augments wp.media.View
  4394. * @augments wp.Backbone.View
  4395. * @augments Backbone.View
  4396. */
  4397. ButtonGroup = wp.media.View.extend(/** @lends wp.media.view.ButtonGroup.prototype */{
  4398. tagName: 'div',
  4399. className: 'button-group button-large media-button-group',
  4400. initialize: function() {
  4401. /**
  4402. * @member {wp.media.view.Button[]}
  4403. */
  4404. this.buttons = _.map( this.options.buttons || [], function( button ) {
  4405. if ( button instanceof Backbone.View ) {
  4406. return button;
  4407. } else {
  4408. return new wp.media.view.Button( button ).render();
  4409. }
  4410. });
  4411. delete this.options.buttons;
  4412. if ( this.options.classes ) {
  4413. this.$el.addClass( this.options.classes );
  4414. }
  4415. },
  4416. /**
  4417. * @return {wp.media.view.ButtonGroup}
  4418. */
  4419. render: function() {
  4420. this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
  4421. return this;
  4422. }
  4423. });
  4424. module.exports = ButtonGroup;
  4425. /***/ }),
  4426. /***/ 3157:
  4427. /***/ (function(module) {
  4428. /**
  4429. * wp.media.view.Button
  4430. *
  4431. * @memberOf wp.media.view
  4432. *
  4433. * @class
  4434. * @augments wp.media.View
  4435. * @augments wp.Backbone.View
  4436. * @augments Backbone.View
  4437. */
  4438. var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{
  4439. tagName: 'button',
  4440. className: 'media-button',
  4441. attributes: { type: 'button' },
  4442. events: {
  4443. 'click': 'click'
  4444. },
  4445. defaults: {
  4446. text: '',
  4447. style: '',
  4448. size: 'large',
  4449. disabled: false
  4450. },
  4451. initialize: function() {
  4452. /**
  4453. * Create a model with the provided `defaults`.
  4454. *
  4455. * @member {Backbone.Model}
  4456. */
  4457. this.model = new Backbone.Model( this.defaults );
  4458. // If any of the `options` have a key from `defaults`, apply its
  4459. // value to the `model` and remove it from the `options object.
  4460. _.each( this.defaults, function( def, key ) {
  4461. var value = this.options[ key ];
  4462. if ( _.isUndefined( value ) ) {
  4463. return;
  4464. }
  4465. this.model.set( key, value );
  4466. delete this.options[ key ];
  4467. }, this );
  4468. this.listenTo( this.model, 'change', this.render );
  4469. },
  4470. /**
  4471. * @return {wp.media.view.Button} Returns itself to allow chaining.
  4472. */
  4473. render: function() {
  4474. var classes = [ 'button', this.className ],
  4475. model = this.model.toJSON();
  4476. if ( model.style ) {
  4477. classes.push( 'button-' + model.style );
  4478. }
  4479. if ( model.size ) {
  4480. classes.push( 'button-' + model.size );
  4481. }
  4482. classes = _.uniq( classes.concat( this.options.classes ) );
  4483. this.el.className = classes.join(' ');
  4484. this.$el.attr( 'disabled', model.disabled );
  4485. this.$el.text( this.model.get('text') );
  4486. return this;
  4487. },
  4488. /**
  4489. * @param {Object} event
  4490. */
  4491. click: function( event ) {
  4492. if ( '#' === this.attributes.href ) {
  4493. event.preventDefault();
  4494. }
  4495. if ( this.options.click && ! this.model.get('disabled') ) {
  4496. this.options.click.apply( this, arguments );
  4497. }
  4498. }
  4499. });
  4500. module.exports = Button;
  4501. /***/ }),
  4502. /***/ 7137:
  4503. /***/ (function(module) {
  4504. var View = wp.media.View,
  4505. UploaderStatus = wp.media.view.UploaderStatus,
  4506. l10n = wp.media.view.l10n,
  4507. $ = jQuery,
  4508. Cropper;
  4509. /**
  4510. * wp.media.view.Cropper
  4511. *
  4512. * Uses the imgAreaSelect plugin to allow a user to crop an image.
  4513. *
  4514. * Takes imgAreaSelect options from
  4515. * wp.customize.HeaderControl.calculateImageSelectOptions via
  4516. * wp.customize.HeaderControl.openMM.
  4517. *
  4518. * @memberOf wp.media.view
  4519. *
  4520. * @class
  4521. * @augments wp.media.View
  4522. * @augments wp.Backbone.View
  4523. * @augments Backbone.View
  4524. */
  4525. Cropper = View.extend(/** @lends wp.media.view.Cropper.prototype */{
  4526. className: 'crop-content',
  4527. template: wp.template('crop-content'),
  4528. initialize: function() {
  4529. _.bindAll(this, 'onImageLoad');
  4530. },
  4531. ready: function() {
  4532. this.controller.frame.on('content:error:crop', this.onError, this);
  4533. this.$image = this.$el.find('.crop-image');
  4534. this.$image.on('load', this.onImageLoad);
  4535. $(window).on('resize.cropper', _.debounce(this.onImageLoad, 250));
  4536. },
  4537. remove: function() {
  4538. $(window).off('resize.cropper');
  4539. this.$el.remove();
  4540. this.$el.off();
  4541. View.prototype.remove.apply(this, arguments);
  4542. },
  4543. prepare: function() {
  4544. return {
  4545. title: l10n.cropYourImage,
  4546. url: this.options.attachment.get('url')
  4547. };
  4548. },
  4549. onImageLoad: function() {
  4550. var imgOptions = this.controller.get('imgSelectOptions'),
  4551. imgSelect;
  4552. if (typeof imgOptions === 'function') {
  4553. imgOptions = imgOptions(this.options.attachment, this.controller);
  4554. }
  4555. imgOptions = _.extend(imgOptions, {
  4556. parent: this.$el,
  4557. onInit: function() {
  4558. // Store the set ratio.
  4559. var setRatio = imgSelect.getOptions().aspectRatio;
  4560. // On mousedown, if no ratio is set and the Shift key is down, use a 1:1 ratio.
  4561. this.parent.children().on( 'mousedown touchstart', function( e ) {
  4562. // If no ratio is set and the shift key is down, use a 1:1 ratio.
  4563. if ( ! setRatio && e.shiftKey ) {
  4564. imgSelect.setOptions( {
  4565. aspectRatio: '1:1'
  4566. } );
  4567. }
  4568. } );
  4569. this.parent.children().on( 'mouseup touchend', function() {
  4570. // Restore the set ratio.
  4571. imgSelect.setOptions( {
  4572. aspectRatio: setRatio ? setRatio : false
  4573. } );
  4574. } );
  4575. }
  4576. } );
  4577. this.trigger('image-loaded');
  4578. imgSelect = this.controller.imgSelect = this.$image.imgAreaSelect(imgOptions);
  4579. },
  4580. onError: function() {
  4581. var filename = this.options.attachment.get('filename');
  4582. this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
  4583. filename: UploaderStatus.prototype.filename(filename),
  4584. message: window._wpMediaViewsL10n.cropError
  4585. }), { at: 0 });
  4586. }
  4587. });
  4588. module.exports = Cropper;
  4589. /***/ }),
  4590. /***/ 5970:
  4591. /***/ (function(module) {
  4592. var View = wp.media.View,
  4593. EditImage;
  4594. /**
  4595. * wp.media.view.EditImage
  4596. *
  4597. * @memberOf wp.media.view
  4598. *
  4599. * @class
  4600. * @augments wp.media.View
  4601. * @augments wp.Backbone.View
  4602. * @augments Backbone.View
  4603. */
  4604. EditImage = View.extend(/** @lends wp.media.view.EditImage.prototype */{
  4605. className: 'image-editor',
  4606. template: wp.template('image-editor'),
  4607. initialize: function( options ) {
  4608. this.editor = window.imageEdit;
  4609. this.controller = options.controller;
  4610. View.prototype.initialize.apply( this, arguments );
  4611. },
  4612. prepare: function() {
  4613. return this.model.toJSON();
  4614. },
  4615. loadEditor: function() {
  4616. this.editor.open( this.model.get( 'id' ), this.model.get( 'nonces' ).edit, this );
  4617. },
  4618. back: function() {
  4619. var lastState = this.controller.lastState();
  4620. this.controller.setState( lastState );
  4621. },
  4622. refresh: function() {
  4623. this.model.fetch();
  4624. },
  4625. save: function() {
  4626. var lastState = this.controller.lastState();
  4627. this.model.fetch().done( _.bind( function() {
  4628. this.controller.setState( lastState );
  4629. }, this ) );
  4630. }
  4631. });
  4632. module.exports = EditImage;
  4633. /***/ }),
  4634. /***/ 5138:
  4635. /***/ (function(module) {
  4636. /**
  4637. * wp.media.view.Embed
  4638. *
  4639. * @memberOf wp.media.view
  4640. *
  4641. * @class
  4642. * @augments wp.media.View
  4643. * @augments wp.Backbone.View
  4644. * @augments Backbone.View
  4645. */
  4646. var Embed = wp.media.View.extend(/** @lends wp.media.view.Ember.prototype */{
  4647. className: 'media-embed',
  4648. initialize: function() {
  4649. /**
  4650. * @member {wp.media.view.EmbedUrl}
  4651. */
  4652. this.url = new wp.media.view.EmbedUrl({
  4653. controller: this.controller,
  4654. model: this.model.props
  4655. }).render();
  4656. this.views.set([ this.url ]);
  4657. this.refresh();
  4658. this.listenTo( this.model, 'change:type', this.refresh );
  4659. this.listenTo( this.model, 'change:loading', this.loading );
  4660. },
  4661. /**
  4662. * @param {Object} view
  4663. */
  4664. settings: function( view ) {
  4665. if ( this._settings ) {
  4666. this._settings.remove();
  4667. }
  4668. this._settings = view;
  4669. this.views.add( view );
  4670. },
  4671. refresh: function() {
  4672. var type = this.model.get('type'),
  4673. constructor;
  4674. if ( 'image' === type ) {
  4675. constructor = wp.media.view.EmbedImage;
  4676. } else if ( 'link' === type ) {
  4677. constructor = wp.media.view.EmbedLink;
  4678. } else {
  4679. return;
  4680. }
  4681. this.settings( new constructor({
  4682. controller: this.controller,
  4683. model: this.model.props,
  4684. priority: 40
  4685. }) );
  4686. },
  4687. loading: function() {
  4688. this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
  4689. }
  4690. });
  4691. module.exports = Embed;
  4692. /***/ }),
  4693. /***/ 1338:
  4694. /***/ (function(module) {
  4695. var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
  4696. EmbedImage;
  4697. /**
  4698. * wp.media.view.EmbedImage
  4699. *
  4700. * @memberOf wp.media.view
  4701. *
  4702. * @class
  4703. * @augments wp.media.view.Settings.AttachmentDisplay
  4704. * @augments wp.media.view.Settings
  4705. * @augments wp.media.View
  4706. * @augments wp.Backbone.View
  4707. * @augments Backbone.View
  4708. */
  4709. EmbedImage = AttachmentDisplay.extend(/** @lends wp.media.view.EmbedImage.prototype */{
  4710. className: 'embed-media-settings',
  4711. template: wp.template('embed-image-settings'),
  4712. initialize: function() {
  4713. /**
  4714. * Call `initialize` directly on parent class with passed arguments
  4715. */
  4716. AttachmentDisplay.prototype.initialize.apply( this, arguments );
  4717. this.listenTo( this.model, 'change:url', this.updateImage );
  4718. },
  4719. updateImage: function() {
  4720. this.$('img').attr( 'src', this.model.get('url') );
  4721. }
  4722. });
  4723. module.exports = EmbedImage;
  4724. /***/ }),
  4725. /***/ 6959:
  4726. /***/ (function(module) {
  4727. var $ = jQuery,
  4728. EmbedLink;
  4729. /**
  4730. * wp.media.view.EmbedLink
  4731. *
  4732. * @memberOf wp.media.view
  4733. *
  4734. * @class
  4735. * @augments wp.media.view.Settings
  4736. * @augments wp.media.View
  4737. * @augments wp.Backbone.View
  4738. * @augments Backbone.View
  4739. */
  4740. EmbedLink = wp.media.view.Settings.extend(/** @lends wp.media.view.EmbedLink.prototype */{
  4741. className: 'embed-link-settings',
  4742. template: wp.template('embed-link-settings'),
  4743. initialize: function() {
  4744. this.listenTo( this.model, 'change:url', this.updateoEmbed );
  4745. },
  4746. updateoEmbed: _.debounce( function() {
  4747. var url = this.model.get( 'url' );
  4748. // Clear out previous results.
  4749. this.$('.embed-container').hide().find('.embed-preview').empty();
  4750. this.$( '.setting' ).hide();
  4751. // Only proceed with embed if the field contains more than 11 characters.
  4752. // Example: http://a.io is 11 chars
  4753. if ( url && ( url.length < 11 || ! url.match(/^http(s)?:\/\//) ) ) {
  4754. return;
  4755. }
  4756. this.fetch();
  4757. }, wp.media.controller.Embed.sensitivity ),
  4758. fetch: function() {
  4759. var url = this.model.get( 'url' ), re, youTubeEmbedMatch;
  4760. // Check if they haven't typed in 500 ms.
  4761. if ( $('#embed-url-field').val() !== url ) {
  4762. return;
  4763. }
  4764. if ( this.dfd && 'pending' === this.dfd.state() ) {
  4765. this.dfd.abort();
  4766. }
  4767. // Support YouTube embed urls, since they work once in the editor.
  4768. re = /https?:\/\/www\.youtube\.com\/embed\/([^/]+)/;
  4769. youTubeEmbedMatch = re.exec( url );
  4770. if ( youTubeEmbedMatch ) {
  4771. url = 'https://www.youtube.com/watch?v=' + youTubeEmbedMatch[ 1 ];
  4772. }
  4773. this.dfd = wp.apiRequest({
  4774. url: wp.media.view.settings.oEmbedProxyUrl,
  4775. data: {
  4776. url: url,
  4777. maxwidth: this.model.get( 'width' ),
  4778. maxheight: this.model.get( 'height' )
  4779. },
  4780. type: 'GET',
  4781. dataType: 'json',
  4782. context: this
  4783. })
  4784. .done( function( response ) {
  4785. this.renderoEmbed( {
  4786. data: {
  4787. body: response.html || ''
  4788. }
  4789. } );
  4790. } )
  4791. .fail( this.renderFail );
  4792. },
  4793. renderFail: function ( response, status ) {
  4794. if ( 'abort' === status ) {
  4795. return;
  4796. }
  4797. this.$( '.link-text' ).show();
  4798. },
  4799. renderoEmbed: function( response ) {
  4800. var html = ( response && response.data && response.data.body ) || '';
  4801. if ( html ) {
  4802. this.$('.embed-container').show().find('.embed-preview').html( html );
  4803. } else {
  4804. this.renderFail();
  4805. }
  4806. }
  4807. });
  4808. module.exports = EmbedLink;
  4809. /***/ }),
  4810. /***/ 4848:
  4811. /***/ (function(module) {
  4812. var View = wp.media.View,
  4813. $ = jQuery,
  4814. l10n = wp.media.view.l10n,
  4815. EmbedUrl;
  4816. /**
  4817. * wp.media.view.EmbedUrl
  4818. *
  4819. * @memberOf wp.media.view
  4820. *
  4821. * @class
  4822. * @augments wp.media.View
  4823. * @augments wp.Backbone.View
  4824. * @augments Backbone.View
  4825. */
  4826. EmbedUrl = View.extend(/** @lends wp.media.view.EmbedUrl.prototype */{
  4827. tagName: 'span',
  4828. className: 'embed-url',
  4829. events: {
  4830. 'input': 'url'
  4831. },
  4832. initialize: function() {
  4833. this.$input = $( '<input id="embed-url-field" type="url" />' )
  4834. .attr( 'aria-label', l10n.insertFromUrlTitle )
  4835. .val( this.model.get('url') );
  4836. this.input = this.$input[0];
  4837. this.spinner = $('<span class="spinner" />')[0];
  4838. this.$el.append([ this.input, this.spinner ]);
  4839. this.listenTo( this.model, 'change:url', this.render );
  4840. if ( this.model.get( 'url' ) ) {
  4841. _.delay( _.bind( function () {
  4842. this.model.trigger( 'change:url' );
  4843. }, this ), 500 );
  4844. }
  4845. },
  4846. /**
  4847. * @return {wp.media.view.EmbedUrl} Returns itself to allow chaining.
  4848. */
  4849. render: function() {
  4850. var $input = this.$input;
  4851. if ( $input.is(':focus') ) {
  4852. return;
  4853. }
  4854. this.input.value = this.model.get('url') || 'http://';
  4855. /**
  4856. * Call `render` directly on parent class with passed arguments
  4857. */
  4858. View.prototype.render.apply( this, arguments );
  4859. return this;
  4860. },
  4861. url: function( event ) {
  4862. var url = event.target.value || '';
  4863. this.model.set( 'url', url.trim() );
  4864. }
  4865. });
  4866. module.exports = EmbedUrl;
  4867. /***/ }),
  4868. /***/ 6557:
  4869. /***/ (function(module) {
  4870. var $ = jQuery;
  4871. /**
  4872. * wp.media.view.FocusManager
  4873. *
  4874. * @memberOf wp.media.view
  4875. *
  4876. * @class
  4877. * @augments wp.media.View
  4878. * @augments wp.Backbone.View
  4879. * @augments Backbone.View
  4880. */
  4881. var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
  4882. events: {
  4883. 'keydown': 'focusManagementMode'
  4884. },
  4885. /**
  4886. * Initializes the Focus Manager.
  4887. *
  4888. * @param {Object} options The Focus Manager options.
  4889. *
  4890. * @since 5.3.0
  4891. *
  4892. * @return {void}
  4893. */
  4894. initialize: function( options ) {
  4895. this.mode = options.mode || 'constrainTabbing';
  4896. this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
  4897. },
  4898. /**
  4899. * Determines which focus management mode to use.
  4900. *
  4901. * @since 5.3.0
  4902. *
  4903. * @param {Object} event jQuery event object.
  4904. *
  4905. * @return {void}
  4906. */
  4907. focusManagementMode: function( event ) {
  4908. if ( this.mode === 'constrainTabbing' ) {
  4909. this.constrainTabbing( event );
  4910. }
  4911. if ( this.mode === 'tabsNavigation' ) {
  4912. this.tabsNavigation( event );
  4913. }
  4914. },
  4915. /**
  4916. * Gets all the tabbable elements.
  4917. *
  4918. * @since 5.3.0
  4919. *
  4920. * @return {Object} A jQuery collection of tabbable elements.
  4921. */
  4922. getTabbables: function() {
  4923. // Skip the file input added by Plupload.
  4924. return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
  4925. },
  4926. /**
  4927. * Moves focus to the modal dialog.
  4928. *
  4929. * @since 3.5.0
  4930. *
  4931. * @return {void}
  4932. */
  4933. focus: function() {
  4934. this.$( '.media-modal' ).trigger( 'focus' );
  4935. },
  4936. /**
  4937. * Constrains navigation with the Tab key within the media view element.
  4938. *
  4939. * @since 4.0.0
  4940. *
  4941. * @param {Object} event A keydown jQuery event.
  4942. *
  4943. * @return {void}
  4944. */
  4945. constrainTabbing: function( event ) {
  4946. var tabbables;
  4947. // Look for the tab key.
  4948. if ( 9 !== event.keyCode ) {
  4949. return;
  4950. }
  4951. tabbables = this.getTabbables();
  4952. // Keep tab focus within media modal while it's open.
  4953. if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
  4954. tabbables.first().focus();
  4955. return false;
  4956. } else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
  4957. tabbables.last().focus();
  4958. return false;
  4959. }
  4960. },
  4961. /**
  4962. * Hides from assistive technologies all the body children.
  4963. *
  4964. * Sets an `aria-hidden="true"` attribute on all the body children except
  4965. * the provided element and other elements that should not be hidden.
  4966. *
  4967. * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
  4968. * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
  4969. * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
  4970. * of the modal dialog and get hidden from assistive technologies.
  4971. *
  4972. * @since 5.2.3
  4973. *
  4974. * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
  4975. *
  4976. * @return {void}
  4977. */
  4978. setAriaHiddenOnBodyChildren: function( visibleElement ) {
  4979. var bodyChildren,
  4980. self = this;
  4981. if ( this.isBodyAriaHidden ) {
  4982. return;
  4983. }
  4984. // Get all the body children.
  4985. bodyChildren = document.body.children;
  4986. // Loop through the body children and hide the ones that should be hidden.
  4987. _.each( bodyChildren, function( element ) {
  4988. // Don't hide the modal element.
  4989. if ( element === visibleElement[0] ) {
  4990. return;
  4991. }
  4992. // Determine the body children to hide.
  4993. if ( self.elementShouldBeHidden( element ) ) {
  4994. element.setAttribute( 'aria-hidden', 'true' );
  4995. // Store the hidden elements.
  4996. self.ariaHiddenElements.push( element );
  4997. }
  4998. } );
  4999. this.isBodyAriaHidden = true;
  5000. },
  5001. /**
  5002. * Unhides from assistive technologies all the body children.
  5003. *
  5004. * Makes visible again to assistive technologies all the body children
  5005. * previously hidden and stored in this.ariaHiddenElements.
  5006. *
  5007. * @since 5.2.3
  5008. *
  5009. * @return {void}
  5010. */
  5011. removeAriaHiddenFromBodyChildren: function() {
  5012. _.each( this.ariaHiddenElements, function( element ) {
  5013. element.removeAttribute( 'aria-hidden' );
  5014. } );
  5015. this.ariaHiddenElements = [];
  5016. this.isBodyAriaHidden = false;
  5017. },
  5018. /**
  5019. * Determines if the passed element should not be hidden from assistive technologies.
  5020. *
  5021. * @since 5.2.3
  5022. *
  5023. * @param {Object} element The DOM element that should be checked.
  5024. *
  5025. * @return {boolean} Whether the element should not be hidden from assistive technologies.
  5026. */
  5027. elementShouldBeHidden: function( element ) {
  5028. var role = element.getAttribute( 'role' ),
  5029. liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
  5030. /*
  5031. * Don't hide scripts, elements that already have `aria-hidden`, and
  5032. * ARIA live regions.
  5033. */
  5034. return ! (
  5035. element.tagName === 'SCRIPT' ||
  5036. element.hasAttribute( 'aria-hidden' ) ||
  5037. element.hasAttribute( 'aria-live' ) ||
  5038. liveRegionsRoles.indexOf( role ) !== -1
  5039. );
  5040. },
  5041. /**
  5042. * Whether the body children are hidden from assistive technologies.
  5043. *
  5044. * @since 5.2.3
  5045. */
  5046. isBodyAriaHidden: false,
  5047. /**
  5048. * Stores an array of DOM elements that should be hidden from assistive
  5049. * technologies, for example when the media modal dialog opens.
  5050. *
  5051. * @since 5.2.3
  5052. */
  5053. ariaHiddenElements: [],
  5054. /**
  5055. * Holds the jQuery collection of ARIA tabs.
  5056. *
  5057. * @since 5.3.0
  5058. */
  5059. tabs: $(),
  5060. /**
  5061. * Sets up tabs in an ARIA tabbed interface.
  5062. *
  5063. * @since 5.3.0
  5064. *
  5065. * @param {Object} event jQuery event object.
  5066. *
  5067. * @return {void}
  5068. */
  5069. setupAriaTabs: function() {
  5070. this.tabs = this.$( '[role="tab"]' );
  5071. // Set up initial attributes.
  5072. this.tabs.attr( {
  5073. 'aria-selected': 'false',
  5074. tabIndex: '-1'
  5075. } );
  5076. // Set up attributes on the initially active tab.
  5077. this.tabs.filter( '.active' )
  5078. .removeAttr( 'tabindex' )
  5079. .attr( 'aria-selected', 'true' );
  5080. },
  5081. /**
  5082. * Enables arrows navigation within the ARIA tabbed interface.
  5083. *
  5084. * @since 5.3.0
  5085. *
  5086. * @param {Object} event jQuery event object.
  5087. *
  5088. * @return {void}
  5089. */
  5090. tabsNavigation: function( event ) {
  5091. var orientation = 'horizontal',
  5092. keys = [ 32, 35, 36, 37, 38, 39, 40 ];
  5093. // Return if not Spacebar, End, Home, or Arrow keys.
  5094. if ( keys.indexOf( event.which ) === -1 ) {
  5095. return;
  5096. }
  5097. // Determine navigation direction.
  5098. if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
  5099. orientation = 'vertical';
  5100. }
  5101. // Make Up and Down arrow keys do nothing with horizontal tabs.
  5102. if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
  5103. return;
  5104. }
  5105. // Make Left and Right arrow keys do nothing with vertical tabs.
  5106. if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
  5107. return;
  5108. }
  5109. this.switchTabs( event, this.tabs );
  5110. },
  5111. /**
  5112. * Switches tabs in the ARIA tabbed interface.
  5113. *
  5114. * @since 5.3.0
  5115. *
  5116. * @param {Object} event jQuery event object.
  5117. *
  5118. * @return {void}
  5119. */
  5120. switchTabs: function( event ) {
  5121. var key = event.which,
  5122. index = this.tabs.index( $( event.target ) ),
  5123. newIndex;
  5124. switch ( key ) {
  5125. // Space bar: Activate current targeted tab.
  5126. case 32: {
  5127. this.activateTab( this.tabs[ index ] );
  5128. break;
  5129. }
  5130. // End key: Activate last tab.
  5131. case 35: {
  5132. event.preventDefault();
  5133. this.activateTab( this.tabs[ this.tabs.length - 1 ] );
  5134. break;
  5135. }
  5136. // Home key: Activate first tab.
  5137. case 36: {
  5138. event.preventDefault();
  5139. this.activateTab( this.tabs[ 0 ] );
  5140. break;
  5141. }
  5142. // Left and up keys: Activate previous tab.
  5143. case 37:
  5144. case 38: {
  5145. event.preventDefault();
  5146. newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
  5147. this.activateTab( this.tabs[ newIndex ] );
  5148. break;
  5149. }
  5150. // Right and down keys: Activate next tab.
  5151. case 39:
  5152. case 40: {
  5153. event.preventDefault();
  5154. newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
  5155. this.activateTab( this.tabs[ newIndex ] );
  5156. break;
  5157. }
  5158. }
  5159. },
  5160. /**
  5161. * Sets a single tab to be focusable and semantically selected.
  5162. *
  5163. * @since 5.3.0
  5164. *
  5165. * @param {Object} tab The tab DOM element.
  5166. *
  5167. * @return {void}
  5168. */
  5169. activateTab: function( tab ) {
  5170. if ( ! tab ) {
  5171. return;
  5172. }
  5173. // The tab is a DOM element: no need for jQuery methods.
  5174. tab.focus();
  5175. // Handle automatic activation.
  5176. if ( this.tabsAutomaticActivation ) {
  5177. tab.removeAttribute( 'tabindex' );
  5178. tab.setAttribute( 'aria-selected', 'true' );
  5179. tab.click();
  5180. return;
  5181. }
  5182. // Handle manual activation.
  5183. $( tab ).on( 'click', function() {
  5184. tab.removeAttribute( 'tabindex' );
  5185. tab.setAttribute( 'aria-selected', 'true' );
  5186. } );
  5187. }
  5188. });
  5189. module.exports = FocusManager;
  5190. /***/ }),
  5191. /***/ 3647:
  5192. /***/ (function(module) {
  5193. /**
  5194. * wp.media.view.Frame
  5195. *
  5196. * A frame is a composite view consisting of one or more regions and one or more
  5197. * states.
  5198. *
  5199. * @memberOf wp.media.view
  5200. *
  5201. * @see wp.media.controller.State
  5202. * @see wp.media.controller.Region
  5203. *
  5204. * @class
  5205. * @augments wp.media.View
  5206. * @augments wp.Backbone.View
  5207. * @augments Backbone.View
  5208. * @mixes wp.media.controller.StateMachine
  5209. */
  5210. var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
  5211. initialize: function() {
  5212. _.defaults( this.options, {
  5213. mode: [ 'select' ]
  5214. });
  5215. this._createRegions();
  5216. this._createStates();
  5217. this._createModes();
  5218. },
  5219. _createRegions: function() {
  5220. // Clone the regions array.
  5221. this.regions = this.regions ? this.regions.slice() : [];
  5222. // Initialize regions.
  5223. _.each( this.regions, function( region ) {
  5224. this[ region ] = new wp.media.controller.Region({
  5225. view: this,
  5226. id: region,
  5227. selector: '.media-frame-' + region
  5228. });
  5229. }, this );
  5230. },
  5231. /**
  5232. * Create the frame's states.
  5233. *
  5234. * @see wp.media.controller.State
  5235. * @see wp.media.controller.StateMachine
  5236. *
  5237. * @fires wp.media.controller.State#ready
  5238. */
  5239. _createStates: function() {
  5240. // Create the default `states` collection.
  5241. this.states = new Backbone.Collection( null, {
  5242. model: wp.media.controller.State
  5243. });
  5244. // Ensure states have a reference to the frame.
  5245. this.states.on( 'add', function( model ) {
  5246. model.frame = this;
  5247. model.trigger('ready');
  5248. }, this );
  5249. if ( this.options.states ) {
  5250. this.states.add( this.options.states );
  5251. }
  5252. },
  5253. /**
  5254. * A frame can be in a mode or multiple modes at one time.
  5255. *
  5256. * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
  5257. */
  5258. _createModes: function() {
  5259. // Store active "modes" that the frame is in. Unrelated to region modes.
  5260. this.activeModes = new Backbone.Collection();
  5261. this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
  5262. _.each( this.options.mode, function( mode ) {
  5263. this.activateMode( mode );
  5264. }, this );
  5265. },
  5266. /**
  5267. * Reset all states on the frame to their defaults.
  5268. *
  5269. * @return {wp.media.view.Frame} Returns itself to allow chaining.
  5270. */
  5271. reset: function() {
  5272. this.states.invoke( 'trigger', 'reset' );
  5273. return this;
  5274. },
  5275. /**
  5276. * Map activeMode collection events to the frame.
  5277. */
  5278. triggerModeEvents: function( model, collection, options ) {
  5279. var collectionEvent,
  5280. modeEventMap = {
  5281. add: 'activate',
  5282. remove: 'deactivate'
  5283. },
  5284. eventToTrigger;
  5285. // Probably a better way to do this.
  5286. _.each( options, function( value, key ) {
  5287. if ( value ) {
  5288. collectionEvent = key;
  5289. }
  5290. } );
  5291. if ( ! _.has( modeEventMap, collectionEvent ) ) {
  5292. return;
  5293. }
  5294. eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
  5295. this.trigger( eventToTrigger );
  5296. },
  5297. /**
  5298. * Activate a mode on the frame.
  5299. *
  5300. * @param string mode Mode ID.
  5301. * @return {this} Returns itself to allow chaining.
  5302. */
  5303. activateMode: function( mode ) {
  5304. // Bail if the mode is already active.
  5305. if ( this.isModeActive( mode ) ) {
  5306. return;
  5307. }
  5308. this.activeModes.add( [ { id: mode } ] );
  5309. // Add a CSS class to the frame so elements can be styled for the mode.
  5310. this.$el.addClass( 'mode-' + mode );
  5311. return this;
  5312. },
  5313. /**
  5314. * Deactivate a mode on the frame.
  5315. *
  5316. * @param string mode Mode ID.
  5317. * @return {this} Returns itself to allow chaining.
  5318. */
  5319. deactivateMode: function( mode ) {
  5320. // Bail if the mode isn't active.
  5321. if ( ! this.isModeActive( mode ) ) {
  5322. return this;
  5323. }
  5324. this.activeModes.remove( this.activeModes.where( { id: mode } ) );
  5325. this.$el.removeClass( 'mode-' + mode );
  5326. /**
  5327. * Frame mode deactivation event.
  5328. *
  5329. * @event wp.media.view.Frame#{mode}:deactivate
  5330. */
  5331. this.trigger( mode + ':deactivate' );
  5332. return this;
  5333. },
  5334. /**
  5335. * Check if a mode is enabled on the frame.
  5336. *
  5337. * @param string mode Mode ID.
  5338. * @return bool
  5339. */
  5340. isModeActive: function( mode ) {
  5341. return Boolean( this.activeModes.where( { id: mode } ).length );
  5342. }
  5343. });
  5344. // Make the `Frame` a `StateMachine`.
  5345. _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
  5346. module.exports = Frame;
  5347. /***/ }),
  5348. /***/ 9142:
  5349. /***/ (function(module) {
  5350. var Select = wp.media.view.MediaFrame.Select,
  5351. l10n = wp.media.view.l10n,
  5352. ImageDetails;
  5353. /**
  5354. * wp.media.view.MediaFrame.ImageDetails
  5355. *
  5356. * A media frame for manipulating an image that's already been inserted
  5357. * into a post.
  5358. *
  5359. * @memberOf wp.media.view.MediaFrame
  5360. *
  5361. * @class
  5362. * @augments wp.media.view.MediaFrame.Select
  5363. * @augments wp.media.view.MediaFrame
  5364. * @augments wp.media.view.Frame
  5365. * @augments wp.media.View
  5366. * @augments wp.Backbone.View
  5367. * @augments Backbone.View
  5368. * @mixes wp.media.controller.StateMachine
  5369. */
  5370. ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
  5371. defaults: {
  5372. id: 'image',
  5373. url: '',
  5374. menu: 'image-details',
  5375. content: 'image-details',
  5376. toolbar: 'image-details',
  5377. type: 'link',
  5378. title: l10n.imageDetailsTitle,
  5379. priority: 120
  5380. },
  5381. initialize: function( options ) {
  5382. this.image = new wp.media.model.PostImage( options.metadata );
  5383. this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
  5384. Select.prototype.initialize.apply( this, arguments );
  5385. },
  5386. bindHandlers: function() {
  5387. Select.prototype.bindHandlers.apply( this, arguments );
  5388. this.on( 'menu:create:image-details', this.createMenu, this );
  5389. this.on( 'content:create:image-details', this.imageDetailsContent, this );
  5390. this.on( 'content:render:edit-image', this.editImageContent, this );
  5391. this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
  5392. // Override the select toolbar.
  5393. this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
  5394. },
  5395. createStates: function() {
  5396. this.states.add([
  5397. new wp.media.controller.ImageDetails({
  5398. image: this.image,
  5399. editable: false
  5400. }),
  5401. new wp.media.controller.ReplaceImage({
  5402. id: 'replace-image',
  5403. library: wp.media.query( { type: 'image' } ),
  5404. image: this.image,
  5405. multiple: false,
  5406. title: l10n.imageReplaceTitle,
  5407. toolbar: 'replace',
  5408. priority: 80,
  5409. displaySettings: true
  5410. }),
  5411. new wp.media.controller.EditImage( {
  5412. image: this.image,
  5413. selection: this.options.selection
  5414. } )
  5415. ]);
  5416. },
  5417. imageDetailsContent: function( options ) {
  5418. options.view = new wp.media.view.ImageDetails({
  5419. controller: this,
  5420. model: this.state().image,
  5421. attachment: this.state().image.attachment
  5422. });
  5423. },
  5424. editImageContent: function() {
  5425. var state = this.state(),
  5426. model = state.get('image'),
  5427. view;
  5428. if ( ! model ) {
  5429. return;
  5430. }
  5431. view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
  5432. this.content.set( view );
  5433. // After bringing in the frame, load the actual editor via an Ajax call.
  5434. view.loadEditor();
  5435. },
  5436. renderImageDetailsToolbar: function() {
  5437. this.toolbar.set( new wp.media.view.Toolbar({
  5438. controller: this,
  5439. items: {
  5440. select: {
  5441. style: 'primary',
  5442. text: l10n.update,
  5443. priority: 80,
  5444. click: function() {
  5445. var controller = this.controller,
  5446. state = controller.state();
  5447. controller.close();
  5448. // Not sure if we want to use wp.media.string.image which will create a shortcode or
  5449. // perhaps wp.html.string to at least to build the <img />.
  5450. state.trigger( 'update', controller.image.toJSON() );
  5451. // Restore and reset the default state.
  5452. controller.setState( controller.options.state );
  5453. controller.reset();
  5454. }
  5455. }
  5456. }
  5457. }) );
  5458. },
  5459. renderReplaceImageToolbar: function() {
  5460. var frame = this,
  5461. lastState = frame.lastState(),
  5462. previous = lastState && lastState.id;
  5463. this.toolbar.set( new wp.media.view.Toolbar({
  5464. controller: this,
  5465. items: {
  5466. back: {
  5467. text: l10n.back,
  5468. priority: 80,
  5469. click: function() {
  5470. if ( previous ) {
  5471. frame.setState( previous );
  5472. } else {
  5473. frame.close();
  5474. }
  5475. }
  5476. },
  5477. replace: {
  5478. style: 'primary',
  5479. text: l10n.replace,
  5480. priority: 20,
  5481. requires: { selection: true },
  5482. click: function() {
  5483. var controller = this.controller,
  5484. state = controller.state(),
  5485. selection = state.get( 'selection' ),
  5486. attachment = selection.single();
  5487. controller.close();
  5488. controller.image.changeAttachment( attachment, state.display( attachment ) );
  5489. // Not sure if we want to use wp.media.string.image which will create a shortcode or
  5490. // perhaps wp.html.string to at least to build the <img />.
  5491. state.trigger( 'replace', controller.image.toJSON() );
  5492. // Restore and reset the default state.
  5493. controller.setState( controller.options.state );
  5494. controller.reset();
  5495. }
  5496. }
  5497. }
  5498. }) );
  5499. }
  5500. });
  5501. module.exports = ImageDetails;
  5502. /***/ }),
  5503. /***/ 9075:
  5504. /***/ (function(module) {
  5505. var Select = wp.media.view.MediaFrame.Select,
  5506. Library = wp.media.controller.Library,
  5507. l10n = wp.media.view.l10n,
  5508. Post;
  5509. /**
  5510. * wp.media.view.MediaFrame.Post
  5511. *
  5512. * The frame for manipulating media on the Edit Post page.
  5513. *
  5514. * @memberOf wp.media.view.MediaFrame
  5515. *
  5516. * @class
  5517. * @augments wp.media.view.MediaFrame.Select
  5518. * @augments wp.media.view.MediaFrame
  5519. * @augments wp.media.view.Frame
  5520. * @augments wp.media.View
  5521. * @augments wp.Backbone.View
  5522. * @augments Backbone.View
  5523. * @mixes wp.media.controller.StateMachine
  5524. */
  5525. Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
  5526. initialize: function() {
  5527. this.counts = {
  5528. audio: {
  5529. count: wp.media.view.settings.attachmentCounts.audio,
  5530. state: 'playlist'
  5531. },
  5532. video: {
  5533. count: wp.media.view.settings.attachmentCounts.video,
  5534. state: 'video-playlist'
  5535. }
  5536. };
  5537. _.defaults( this.options, {
  5538. multiple: true,
  5539. editing: false,
  5540. state: 'insert',
  5541. metadata: {}
  5542. });
  5543. // Call 'initialize' directly on the parent class.
  5544. Select.prototype.initialize.apply( this, arguments );
  5545. this.createIframeStates();
  5546. },
  5547. /**
  5548. * Create the default states.
  5549. */
  5550. createStates: function() {
  5551. var options = this.options;
  5552. this.states.add([
  5553. // Main states.
  5554. new Library({
  5555. id: 'insert',
  5556. title: l10n.insertMediaTitle,
  5557. priority: 20,
  5558. toolbar: 'main-insert',
  5559. filterable: 'all',
  5560. library: wp.media.query( options.library ),
  5561. multiple: options.multiple ? 'reset' : false,
  5562. editable: true,
  5563. // If the user isn't allowed to edit fields,
  5564. // can they still edit it locally?
  5565. allowLocalEdits: true,
  5566. // Show the attachment display settings.
  5567. displaySettings: true,
  5568. // Update user settings when users adjust the
  5569. // attachment display settings.
  5570. displayUserSettings: true
  5571. }),
  5572. new Library({
  5573. id: 'gallery',
  5574. title: l10n.createGalleryTitle,
  5575. priority: 40,
  5576. toolbar: 'main-gallery',
  5577. filterable: 'uploaded',
  5578. multiple: 'add',
  5579. editable: false,
  5580. library: wp.media.query( _.defaults({
  5581. type: 'image'
  5582. }, options.library ) )
  5583. }),
  5584. // Embed states.
  5585. new wp.media.controller.Embed( { metadata: options.metadata } ),
  5586. new wp.media.controller.EditImage( { model: options.editImage } ),
  5587. // Gallery states.
  5588. new wp.media.controller.GalleryEdit({
  5589. library: options.selection,
  5590. editing: options.editing,
  5591. menu: 'gallery'
  5592. }),
  5593. new wp.media.controller.GalleryAdd(),
  5594. new Library({
  5595. id: 'playlist',
  5596. title: l10n.createPlaylistTitle,
  5597. priority: 60,
  5598. toolbar: 'main-playlist',
  5599. filterable: 'uploaded',
  5600. multiple: 'add',
  5601. editable: false,
  5602. library: wp.media.query( _.defaults({
  5603. type: 'audio'
  5604. }, options.library ) )
  5605. }),
  5606. // Playlist states.
  5607. new wp.media.controller.CollectionEdit({
  5608. type: 'audio',
  5609. collectionType: 'playlist',
  5610. title: l10n.editPlaylistTitle,
  5611. SettingsView: wp.media.view.Settings.Playlist,
  5612. library: options.selection,
  5613. editing: options.editing,
  5614. menu: 'playlist',
  5615. dragInfoText: l10n.playlistDragInfo,
  5616. dragInfo: false
  5617. }),
  5618. new wp.media.controller.CollectionAdd({
  5619. type: 'audio',
  5620. collectionType: 'playlist',
  5621. title: l10n.addToPlaylistTitle
  5622. }),
  5623. new Library({
  5624. id: 'video-playlist',
  5625. title: l10n.createVideoPlaylistTitle,
  5626. priority: 60,
  5627. toolbar: 'main-video-playlist',
  5628. filterable: 'uploaded',
  5629. multiple: 'add',
  5630. editable: false,
  5631. library: wp.media.query( _.defaults({
  5632. type: 'video'
  5633. }, options.library ) )
  5634. }),
  5635. new wp.media.controller.CollectionEdit({
  5636. type: 'video',
  5637. collectionType: 'playlist',
  5638. title: l10n.editVideoPlaylistTitle,
  5639. SettingsView: wp.media.view.Settings.Playlist,
  5640. library: options.selection,
  5641. editing: options.editing,
  5642. menu: 'video-playlist',
  5643. dragInfoText: l10n.videoPlaylistDragInfo,
  5644. dragInfo: false
  5645. }),
  5646. new wp.media.controller.CollectionAdd({
  5647. type: 'video',
  5648. collectionType: 'playlist',
  5649. title: l10n.addToVideoPlaylistTitle
  5650. })
  5651. ]);
  5652. if ( wp.media.view.settings.post.featuredImageId ) {
  5653. this.states.add( new wp.media.controller.FeaturedImage() );
  5654. }
  5655. },
  5656. bindHandlers: function() {
  5657. var handlers, checkCounts;
  5658. Select.prototype.bindHandlers.apply( this, arguments );
  5659. this.on( 'activate', this.activate, this );
  5660. // Only bother checking media type counts if one of the counts is zero.
  5661. checkCounts = _.find( this.counts, function( type ) {
  5662. return type.count === 0;
  5663. } );
  5664. if ( typeof checkCounts !== 'undefined' ) {
  5665. this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
  5666. }
  5667. this.on( 'menu:create:gallery', this.createMenu, this );
  5668. this.on( 'menu:create:playlist', this.createMenu, this );
  5669. this.on( 'menu:create:video-playlist', this.createMenu, this );
  5670. this.on( 'toolbar:create:main-insert', this.createToolbar, this );
  5671. this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
  5672. this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
  5673. this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
  5674. this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
  5675. this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
  5676. handlers = {
  5677. menu: {
  5678. 'default': 'mainMenu',
  5679. 'gallery': 'galleryMenu',
  5680. 'playlist': 'playlistMenu',
  5681. 'video-playlist': 'videoPlaylistMenu'
  5682. },
  5683. content: {
  5684. 'embed': 'embedContent',
  5685. 'edit-image': 'editImageContent',
  5686. 'edit-selection': 'editSelectionContent'
  5687. },
  5688. toolbar: {
  5689. 'main-insert': 'mainInsertToolbar',
  5690. 'main-gallery': 'mainGalleryToolbar',
  5691. 'gallery-edit': 'galleryEditToolbar',
  5692. 'gallery-add': 'galleryAddToolbar',
  5693. 'main-playlist': 'mainPlaylistToolbar',
  5694. 'playlist-edit': 'playlistEditToolbar',
  5695. 'playlist-add': 'playlistAddToolbar',
  5696. 'main-video-playlist': 'mainVideoPlaylistToolbar',
  5697. 'video-playlist-edit': 'videoPlaylistEditToolbar',
  5698. 'video-playlist-add': 'videoPlaylistAddToolbar'
  5699. }
  5700. };
  5701. _.each( handlers, function( regionHandlers, region ) {
  5702. _.each( regionHandlers, function( callback, handler ) {
  5703. this.on( region + ':render:' + handler, this[ callback ], this );
  5704. }, this );
  5705. }, this );
  5706. },
  5707. activate: function() {
  5708. // Hide menu items for states tied to particular media types if there are no items.
  5709. _.each( this.counts, function( type ) {
  5710. if ( type.count < 1 ) {
  5711. this.menuItemVisibility( type.state, 'hide' );
  5712. }
  5713. }, this );
  5714. },
  5715. mediaTypeCounts: function( model, attr ) {
  5716. if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
  5717. this.counts[ attr ].count++;
  5718. this.menuItemVisibility( this.counts[ attr ].state, 'show' );
  5719. }
  5720. },
  5721. // Menus.
  5722. /**
  5723. * @param {wp.Backbone.View} view
  5724. */
  5725. mainMenu: function( view ) {
  5726. view.set({
  5727. 'library-separator': new wp.media.View({
  5728. className: 'separator',
  5729. priority: 100,
  5730. attributes: {
  5731. role: 'presentation'
  5732. }
  5733. })
  5734. });
  5735. },
  5736. menuItemVisibility: function( state, visibility ) {
  5737. var menu = this.menu.get();
  5738. if ( visibility === 'hide' ) {
  5739. menu.hide( state );
  5740. } else if ( visibility === 'show' ) {
  5741. menu.show( state );
  5742. }
  5743. },
  5744. /**
  5745. * @param {wp.Backbone.View} view
  5746. */
  5747. galleryMenu: function( view ) {
  5748. var lastState = this.lastState(),
  5749. previous = lastState && lastState.id,
  5750. frame = this;
  5751. view.set({
  5752. cancel: {
  5753. text: l10n.cancelGalleryTitle,
  5754. priority: 20,
  5755. click: function() {
  5756. if ( previous ) {
  5757. frame.setState( previous );
  5758. } else {
  5759. frame.close();
  5760. }
  5761. // Move focus to the modal after canceling a Gallery.
  5762. this.controller.modal.focusManager.focus();
  5763. }
  5764. },
  5765. separateCancel: new wp.media.View({
  5766. className: 'separator',
  5767. priority: 40
  5768. })
  5769. });
  5770. },
  5771. playlistMenu: function( view ) {
  5772. var lastState = this.lastState(),
  5773. previous = lastState && lastState.id,
  5774. frame = this;
  5775. view.set({
  5776. cancel: {
  5777. text: l10n.cancelPlaylistTitle,
  5778. priority: 20,
  5779. click: function() {
  5780. if ( previous ) {
  5781. frame.setState( previous );
  5782. } else {
  5783. frame.close();
  5784. }
  5785. // Move focus to the modal after canceling an Audio Playlist.
  5786. this.controller.modal.focusManager.focus();
  5787. }
  5788. },
  5789. separateCancel: new wp.media.View({
  5790. className: 'separator',
  5791. priority: 40
  5792. })
  5793. });
  5794. },
  5795. videoPlaylistMenu: function( view ) {
  5796. var lastState = this.lastState(),
  5797. previous = lastState && lastState.id,
  5798. frame = this;
  5799. view.set({
  5800. cancel: {
  5801. text: l10n.cancelVideoPlaylistTitle,
  5802. priority: 20,
  5803. click: function() {
  5804. if ( previous ) {
  5805. frame.setState( previous );
  5806. } else {
  5807. frame.close();
  5808. }
  5809. // Move focus to the modal after canceling a Video Playlist.
  5810. this.controller.modal.focusManager.focus();
  5811. }
  5812. },
  5813. separateCancel: new wp.media.View({
  5814. className: 'separator',
  5815. priority: 40
  5816. })
  5817. });
  5818. },
  5819. // Content.
  5820. embedContent: function() {
  5821. var view = new wp.media.view.Embed({
  5822. controller: this,
  5823. model: this.state()
  5824. }).render();
  5825. this.content.set( view );
  5826. },
  5827. editSelectionContent: function() {
  5828. var state = this.state(),
  5829. selection = state.get('selection'),
  5830. view;
  5831. view = new wp.media.view.AttachmentsBrowser({
  5832. controller: this,
  5833. collection: selection,
  5834. selection: selection,
  5835. model: state,
  5836. sortable: true,
  5837. search: false,
  5838. date: false,
  5839. dragInfo: true,
  5840. AttachmentView: wp.media.view.Attachments.EditSelection
  5841. }).render();
  5842. view.toolbar.set( 'backToLibrary', {
  5843. text: l10n.returnToLibrary,
  5844. priority: -100,
  5845. click: function() {
  5846. this.controller.content.mode('browse');
  5847. // Move focus to the modal when jumping back from Edit Selection to Add Media view.
  5848. this.controller.modal.focusManager.focus();
  5849. }
  5850. });
  5851. // Browse our library of attachments.
  5852. this.content.set( view );
  5853. // Trigger the controller to set focus.
  5854. this.trigger( 'edit:selection', this );
  5855. },
  5856. editImageContent: function() {
  5857. var image = this.state().get('image'),
  5858. view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
  5859. this.content.set( view );
  5860. // After creating the wrapper view, load the actual editor via an Ajax call.
  5861. view.loadEditor();
  5862. },
  5863. // Toolbars.
  5864. /**
  5865. * @param {wp.Backbone.View} view
  5866. */
  5867. selectionStatusToolbar: function( view ) {
  5868. var editable = this.state().get('editable');
  5869. view.set( 'selection', new wp.media.view.Selection({
  5870. controller: this,
  5871. collection: this.state().get('selection'),
  5872. priority: -40,
  5873. // If the selection is editable, pass the callback to
  5874. // switch the content mode.
  5875. editable: editable && function() {
  5876. this.controller.content.mode('edit-selection');
  5877. }
  5878. }).render() );
  5879. },
  5880. /**
  5881. * @param {wp.Backbone.View} view
  5882. */
  5883. mainInsertToolbar: function( view ) {
  5884. var controller = this;
  5885. this.selectionStatusToolbar( view );
  5886. view.set( 'insert', {
  5887. style: 'primary',
  5888. priority: 80,
  5889. text: l10n.insertIntoPost,
  5890. requires: { selection: true },
  5891. /**
  5892. * @ignore
  5893. *
  5894. * @fires wp.media.controller.State#insert
  5895. */
  5896. click: function() {
  5897. var state = controller.state(),
  5898. selection = state.get('selection');
  5899. controller.close();
  5900. state.trigger( 'insert', selection ).reset();
  5901. }
  5902. });
  5903. },
  5904. /**
  5905. * @param {wp.Backbone.View} view
  5906. */
  5907. mainGalleryToolbar: function( view ) {
  5908. var controller = this;
  5909. this.selectionStatusToolbar( view );
  5910. view.set( 'gallery', {
  5911. style: 'primary',
  5912. text: l10n.createNewGallery,
  5913. priority: 60,
  5914. requires: { selection: true },
  5915. click: function() {
  5916. var selection = controller.state().get('selection'),
  5917. edit = controller.state('gallery-edit'),
  5918. models = selection.where({ type: 'image' });
  5919. edit.set( 'library', new wp.media.model.Selection( models, {
  5920. props: selection.props.toJSON(),
  5921. multiple: true
  5922. }) );
  5923. // Jump to Edit Gallery view.
  5924. this.controller.setState( 'gallery-edit' );
  5925. // Move focus to the modal after jumping to Edit Gallery view.
  5926. this.controller.modal.focusManager.focus();
  5927. }
  5928. });
  5929. },
  5930. mainPlaylistToolbar: function( view ) {
  5931. var controller = this;
  5932. this.selectionStatusToolbar( view );
  5933. view.set( 'playlist', {
  5934. style: 'primary',
  5935. text: l10n.createNewPlaylist,
  5936. priority: 100,
  5937. requires: { selection: true },
  5938. click: function() {
  5939. var selection = controller.state().get('selection'),
  5940. edit = controller.state('playlist-edit'),
  5941. models = selection.where({ type: 'audio' });
  5942. edit.set( 'library', new wp.media.model.Selection( models, {
  5943. props: selection.props.toJSON(),
  5944. multiple: true
  5945. }) );
  5946. // Jump to Edit Audio Playlist view.
  5947. this.controller.setState( 'playlist-edit' );
  5948. // Move focus to the modal after jumping to Edit Audio Playlist view.
  5949. this.controller.modal.focusManager.focus();
  5950. }
  5951. });
  5952. },
  5953. mainVideoPlaylistToolbar: function( view ) {
  5954. var controller = this;
  5955. this.selectionStatusToolbar( view );
  5956. view.set( 'video-playlist', {
  5957. style: 'primary',
  5958. text: l10n.createNewVideoPlaylist,
  5959. priority: 100,
  5960. requires: { selection: true },
  5961. click: function() {
  5962. var selection = controller.state().get('selection'),
  5963. edit = controller.state('video-playlist-edit'),
  5964. models = selection.where({ type: 'video' });
  5965. edit.set( 'library', new wp.media.model.Selection( models, {
  5966. props: selection.props.toJSON(),
  5967. multiple: true
  5968. }) );
  5969. // Jump to Edit Video Playlist view.
  5970. this.controller.setState( 'video-playlist-edit' );
  5971. // Move focus to the modal after jumping to Edit Video Playlist view.
  5972. this.controller.modal.focusManager.focus();
  5973. }
  5974. });
  5975. },
  5976. featuredImageToolbar: function( toolbar ) {
  5977. this.createSelectToolbar( toolbar, {
  5978. text: l10n.setFeaturedImage,
  5979. state: this.options.state
  5980. });
  5981. },
  5982. mainEmbedToolbar: function( toolbar ) {
  5983. toolbar.view = new wp.media.view.Toolbar.Embed({
  5984. controller: this
  5985. });
  5986. },
  5987. galleryEditToolbar: function() {
  5988. var editing = this.state().get('editing');
  5989. this.toolbar.set( new wp.media.view.Toolbar({
  5990. controller: this,
  5991. items: {
  5992. insert: {
  5993. style: 'primary',
  5994. text: editing ? l10n.updateGallery : l10n.insertGallery,
  5995. priority: 80,
  5996. requires: { library: true },
  5997. /**
  5998. * @fires wp.media.controller.State#update
  5999. */
  6000. click: function() {
  6001. var controller = this.controller,
  6002. state = controller.state();
  6003. controller.close();
  6004. state.trigger( 'update', state.get('library') );
  6005. // Restore and reset the default state.
  6006. controller.setState( controller.options.state );
  6007. controller.reset();
  6008. }
  6009. }
  6010. }
  6011. }) );
  6012. },
  6013. galleryAddToolbar: function() {
  6014. this.toolbar.set( new wp.media.view.Toolbar({
  6015. controller: this,
  6016. items: {
  6017. insert: {
  6018. style: 'primary',
  6019. text: l10n.addToGallery,
  6020. priority: 80,
  6021. requires: { selection: true },
  6022. /**
  6023. * @fires wp.media.controller.State#reset
  6024. */
  6025. click: function() {
  6026. var controller = this.controller,
  6027. state = controller.state(),
  6028. edit = controller.state('gallery-edit');
  6029. edit.get('library').add( state.get('selection').models );
  6030. state.trigger('reset');
  6031. controller.setState('gallery-edit');
  6032. // Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
  6033. this.controller.modal.focusManager.focus();
  6034. }
  6035. }
  6036. }
  6037. }) );
  6038. },
  6039. playlistEditToolbar: function() {
  6040. var editing = this.state().get('editing');
  6041. this.toolbar.set( new wp.media.view.Toolbar({
  6042. controller: this,
  6043. items: {
  6044. insert: {
  6045. style: 'primary',
  6046. text: editing ? l10n.updatePlaylist : l10n.insertPlaylist,
  6047. priority: 80,
  6048. requires: { library: true },
  6049. /**
  6050. * @fires wp.media.controller.State#update
  6051. */
  6052. click: function() {
  6053. var controller = this.controller,
  6054. state = controller.state();
  6055. controller.close();
  6056. state.trigger( 'update', state.get('library') );
  6057. // Restore and reset the default state.
  6058. controller.setState( controller.options.state );
  6059. controller.reset();
  6060. }
  6061. }
  6062. }
  6063. }) );
  6064. },
  6065. playlistAddToolbar: function() {
  6066. this.toolbar.set( new wp.media.view.Toolbar({
  6067. controller: this,
  6068. items: {
  6069. insert: {
  6070. style: 'primary',
  6071. text: l10n.addToPlaylist,
  6072. priority: 80,
  6073. requires: { selection: true },
  6074. /**
  6075. * @fires wp.media.controller.State#reset
  6076. */
  6077. click: function() {
  6078. var controller = this.controller,
  6079. state = controller.state(),
  6080. edit = controller.state('playlist-edit');
  6081. edit.get('library').add( state.get('selection').models );
  6082. state.trigger('reset');
  6083. controller.setState('playlist-edit');
  6084. // Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
  6085. this.controller.modal.focusManager.focus();
  6086. }
  6087. }
  6088. }
  6089. }) );
  6090. },
  6091. videoPlaylistEditToolbar: function() {
  6092. var editing = this.state().get('editing');
  6093. this.toolbar.set( new wp.media.view.Toolbar({
  6094. controller: this,
  6095. items: {
  6096. insert: {
  6097. style: 'primary',
  6098. text: editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
  6099. priority: 140,
  6100. requires: { library: true },
  6101. click: function() {
  6102. var controller = this.controller,
  6103. state = controller.state(),
  6104. library = state.get('library');
  6105. library.type = 'video';
  6106. controller.close();
  6107. state.trigger( 'update', library );
  6108. // Restore and reset the default state.
  6109. controller.setState( controller.options.state );
  6110. controller.reset();
  6111. }
  6112. }
  6113. }
  6114. }) );
  6115. },
  6116. videoPlaylistAddToolbar: function() {
  6117. this.toolbar.set( new wp.media.view.Toolbar({
  6118. controller: this,
  6119. items: {
  6120. insert: {
  6121. style: 'primary',
  6122. text: l10n.addToVideoPlaylist,
  6123. priority: 140,
  6124. requires: { selection: true },
  6125. click: function() {
  6126. var controller = this.controller,
  6127. state = controller.state(),
  6128. edit = controller.state('video-playlist-edit');
  6129. edit.get('library').add( state.get('selection').models );
  6130. state.trigger('reset');
  6131. controller.setState('video-playlist-edit');
  6132. // Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
  6133. this.controller.modal.focusManager.focus();
  6134. }
  6135. }
  6136. }
  6137. }) );
  6138. }
  6139. });
  6140. module.exports = Post;
  6141. /***/ }),
  6142. /***/ 8719:
  6143. /***/ (function(module) {
  6144. var MediaFrame = wp.media.view.MediaFrame,
  6145. l10n = wp.media.view.l10n,
  6146. Select;
  6147. /**
  6148. * wp.media.view.MediaFrame.Select
  6149. *
  6150. * A frame for selecting an item or items from the media library.
  6151. *
  6152. * @memberOf wp.media.view.MediaFrame
  6153. *
  6154. * @class
  6155. * @augments wp.media.view.MediaFrame
  6156. * @augments wp.media.view.Frame
  6157. * @augments wp.media.View
  6158. * @augments wp.Backbone.View
  6159. * @augments Backbone.View
  6160. * @mixes wp.media.controller.StateMachine
  6161. */
  6162. Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
  6163. initialize: function() {
  6164. // Call 'initialize' directly on the parent class.
  6165. MediaFrame.prototype.initialize.apply( this, arguments );
  6166. _.defaults( this.options, {
  6167. selection: [],
  6168. library: {},
  6169. multiple: false,
  6170. state: 'library'
  6171. });
  6172. this.createSelection();
  6173. this.createStates();
  6174. this.bindHandlers();
  6175. },
  6176. /**
  6177. * Attach a selection collection to the frame.
  6178. *
  6179. * A selection is a collection of attachments used for a specific purpose
  6180. * by a media frame. e.g. Selecting an attachment (or many) to insert into
  6181. * post content.
  6182. *
  6183. * @see media.model.Selection
  6184. */
  6185. createSelection: function() {
  6186. var selection = this.options.selection;
  6187. if ( ! (selection instanceof wp.media.model.Selection) ) {
  6188. this.options.selection = new wp.media.model.Selection( selection, {
  6189. multiple: this.options.multiple
  6190. });
  6191. }
  6192. this._selection = {
  6193. attachments: new wp.media.model.Attachments(),
  6194. difference: []
  6195. };
  6196. },
  6197. editImageContent: function() {
  6198. var image = this.state().get('image'),
  6199. view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
  6200. this.content.set( view );
  6201. // After creating the wrapper view, load the actual editor via an Ajax call.
  6202. view.loadEditor();
  6203. },
  6204. /**
  6205. * Create the default states on the frame.
  6206. */
  6207. createStates: function() {
  6208. var options = this.options;
  6209. if ( this.options.states ) {
  6210. return;
  6211. }
  6212. // Add the default states.
  6213. this.states.add([
  6214. // Main states.
  6215. new wp.media.controller.Library({
  6216. library: wp.media.query( options.library ),
  6217. multiple: options.multiple,
  6218. title: options.title,
  6219. priority: 20
  6220. }),
  6221. new wp.media.controller.EditImage( { model: options.editImage } )
  6222. ]);
  6223. },
  6224. /**
  6225. * Bind region mode event callbacks.
  6226. *
  6227. * @see media.controller.Region.render
  6228. */
  6229. bindHandlers: function() {
  6230. this.on( 'router:create:browse', this.createRouter, this );
  6231. this.on( 'router:render:browse', this.browseRouter, this );
  6232. this.on( 'content:create:browse', this.browseContent, this );
  6233. this.on( 'content:render:upload', this.uploadContent, this );
  6234. this.on( 'toolbar:create:select', this.createSelectToolbar, this );
  6235. this.on( 'content:render:edit-image', this.editImageContent, this );
  6236. },
  6237. /**
  6238. * Render callback for the router region in the `browse` mode.
  6239. *
  6240. * @param {wp.media.view.Router} routerView
  6241. */
  6242. browseRouter: function( routerView ) {
  6243. routerView.set({
  6244. upload: {
  6245. text: l10n.uploadFilesTitle,
  6246. priority: 20
  6247. },
  6248. browse: {
  6249. text: l10n.mediaLibraryTitle,
  6250. priority: 40
  6251. }
  6252. });
  6253. },
  6254. /**
  6255. * Render callback for the content region in the `browse` mode.
  6256. *
  6257. * @param {wp.media.controller.Region} contentRegion
  6258. */
  6259. browseContent: function( contentRegion ) {
  6260. var state = this.state();
  6261. this.$el.removeClass('hide-toolbar');
  6262. // Browse our library of attachments.
  6263. contentRegion.view = new wp.media.view.AttachmentsBrowser({
  6264. controller: this,
  6265. collection: state.get('library'),
  6266. selection: state.get('selection'),
  6267. model: state,
  6268. sortable: state.get('sortable'),
  6269. search: state.get('searchable'),
  6270. filters: state.get('filterable'),
  6271. date: state.get('date'),
  6272. display: state.has('display') ? state.get('display') : state.get('displaySettings'),
  6273. dragInfo: state.get('dragInfo'),
  6274. idealColumnWidth: state.get('idealColumnWidth'),
  6275. suggestedWidth: state.get('suggestedWidth'),
  6276. suggestedHeight: state.get('suggestedHeight'),
  6277. AttachmentView: state.get('AttachmentView')
  6278. });
  6279. },
  6280. /**
  6281. * Render callback for the content region in the `upload` mode.
  6282. */
  6283. uploadContent: function() {
  6284. this.$el.removeClass( 'hide-toolbar' );
  6285. this.content.set( new wp.media.view.UploaderInline({
  6286. controller: this
  6287. }) );
  6288. },
  6289. /**
  6290. * Toolbars
  6291. *
  6292. * @param {Object} toolbar
  6293. * @param {Object} [options={}]
  6294. * @this wp.media.controller.Region
  6295. */
  6296. createSelectToolbar: function( toolbar, options ) {
  6297. options = options || this.options.button || {};
  6298. options.controller = this;
  6299. toolbar.view = new wp.media.view.Toolbar.Select( options );
  6300. }
  6301. });
  6302. module.exports = Select;
  6303. /***/ }),
  6304. /***/ 7990:
  6305. /***/ (function(module) {
  6306. /**
  6307. * wp.media.view.Heading
  6308. *
  6309. * A reusable heading component for the media library
  6310. *
  6311. * Used to add accessibility friendly headers in the media library/modal.
  6312. *
  6313. * @class
  6314. * @augments wp.media.View
  6315. * @augments wp.Backbone.View
  6316. * @augments Backbone.View
  6317. */
  6318. var Heading = wp.media.View.extend( {
  6319. tagName: function() {
  6320. return this.options.level || 'h1';
  6321. },
  6322. className: 'media-views-heading',
  6323. initialize: function() {
  6324. if ( this.options.className ) {
  6325. this.$el.addClass( this.options.className );
  6326. }
  6327. this.text = this.options.text;
  6328. },
  6329. render: function() {
  6330. this.$el.html( this.text );
  6331. return this;
  6332. }
  6333. } );
  6334. module.exports = Heading;
  6335. /***/ }),
  6336. /***/ 6217:
  6337. /***/ (function(module) {
  6338. /**
  6339. * wp.media.view.Iframe
  6340. *
  6341. * @memberOf wp.media.view
  6342. *
  6343. * @class
  6344. * @augments wp.media.View
  6345. * @augments wp.Backbone.View
  6346. * @augments Backbone.View
  6347. */
  6348. var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
  6349. className: 'media-iframe',
  6350. /**
  6351. * @return {wp.media.view.Iframe} Returns itself to allow chaining.
  6352. */
  6353. render: function() {
  6354. this.views.detach();
  6355. this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
  6356. this.views.render();
  6357. return this;
  6358. }
  6359. });
  6360. module.exports = Iframe;
  6361. /***/ }),
  6362. /***/ 7598:
  6363. /***/ (function(module) {
  6364. var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
  6365. $ = jQuery,
  6366. ImageDetails;
  6367. /**
  6368. * wp.media.view.ImageDetails
  6369. *
  6370. * @memberOf wp.media.view
  6371. *
  6372. * @class
  6373. * @augments wp.media.view.Settings.AttachmentDisplay
  6374. * @augments wp.media.view.Settings
  6375. * @augments wp.media.View
  6376. * @augments wp.Backbone.View
  6377. * @augments Backbone.View
  6378. */
  6379. ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
  6380. className: 'image-details',
  6381. template: wp.template('image-details'),
  6382. events: _.defaults( AttachmentDisplay.prototype.events, {
  6383. 'click .edit-attachment': 'editAttachment',
  6384. 'click .replace-attachment': 'replaceAttachment',
  6385. 'click .advanced-toggle': 'onToggleAdvanced',
  6386. 'change [data-setting="customWidth"]': 'onCustomSize',
  6387. 'change [data-setting="customHeight"]': 'onCustomSize',
  6388. 'keyup [data-setting="customWidth"]': 'onCustomSize',
  6389. 'keyup [data-setting="customHeight"]': 'onCustomSize'
  6390. } ),
  6391. initialize: function() {
  6392. // Used in AttachmentDisplay.prototype.updateLinkTo.
  6393. this.options.attachment = this.model.attachment;
  6394. this.listenTo( this.model, 'change:url', this.updateUrl );
  6395. this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
  6396. this.listenTo( this.model, 'change:size', this.toggleCustomSize );
  6397. AttachmentDisplay.prototype.initialize.apply( this, arguments );
  6398. },
  6399. prepare: function() {
  6400. var attachment = false;
  6401. if ( this.model.attachment ) {
  6402. attachment = this.model.attachment.toJSON();
  6403. }
  6404. return _.defaults({
  6405. model: this.model.toJSON(),
  6406. attachment: attachment
  6407. }, this.options );
  6408. },
  6409. render: function() {
  6410. var args = arguments;
  6411. if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
  6412. this.model.dfd
  6413. .done( _.bind( function() {
  6414. AttachmentDisplay.prototype.render.apply( this, args );
  6415. this.postRender();
  6416. }, this ) )
  6417. .fail( _.bind( function() {
  6418. this.model.attachment = false;
  6419. AttachmentDisplay.prototype.render.apply( this, args );
  6420. this.postRender();
  6421. }, this ) );
  6422. } else {
  6423. AttachmentDisplay.prototype.render.apply( this, arguments );
  6424. this.postRender();
  6425. }
  6426. return this;
  6427. },
  6428. postRender: function() {
  6429. setTimeout( _.bind( this.scrollToTop, this ), 10 );
  6430. this.toggleLinkSettings();
  6431. if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
  6432. this.toggleAdvanced( true );
  6433. }
  6434. this.trigger( 'post-render' );
  6435. },
  6436. scrollToTop: function() {
  6437. this.$( '.embed-media-settings' ).scrollTop( 0 );
  6438. },
  6439. updateUrl: function() {
  6440. this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
  6441. this.$( '.url' ).val( this.model.get( 'url' ) );
  6442. },
  6443. toggleLinkSettings: function() {
  6444. if ( this.model.get( 'link' ) === 'none' ) {
  6445. this.$( '.link-settings' ).addClass('hidden');
  6446. } else {
  6447. this.$( '.link-settings' ).removeClass('hidden');
  6448. }
  6449. },
  6450. toggleCustomSize: function() {
  6451. if ( this.model.get( 'size' ) !== 'custom' ) {
  6452. this.$( '.custom-size' ).addClass('hidden');
  6453. } else {
  6454. this.$( '.custom-size' ).removeClass('hidden');
  6455. }
  6456. },
  6457. onCustomSize: function( event ) {
  6458. var dimension = $( event.target ).data('setting'),
  6459. num = $( event.target ).val(),
  6460. value;
  6461. // Ignore bogus input.
  6462. if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
  6463. event.preventDefault();
  6464. return;
  6465. }
  6466. if ( dimension === 'customWidth' ) {
  6467. value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
  6468. this.model.set( 'customHeight', value, { silent: true } );
  6469. this.$( '[data-setting="customHeight"]' ).val( value );
  6470. } else {
  6471. value = Math.round( this.model.get( 'aspectRatio' ) * num );
  6472. this.model.set( 'customWidth', value, { silent: true } );
  6473. this.$( '[data-setting="customWidth"]' ).val( value );
  6474. }
  6475. },
  6476. onToggleAdvanced: function( event ) {
  6477. event.preventDefault();
  6478. this.toggleAdvanced();
  6479. },
  6480. toggleAdvanced: function( show ) {
  6481. var $advanced = this.$el.find( '.advanced-section' ),
  6482. mode;
  6483. if ( $advanced.hasClass('advanced-visible') || show === false ) {
  6484. $advanced.removeClass('advanced-visible');
  6485. $advanced.find('.advanced-settings').addClass('hidden');
  6486. mode = 'hide';
  6487. } else {
  6488. $advanced.addClass('advanced-visible');
  6489. $advanced.find('.advanced-settings').removeClass('hidden');
  6490. mode = 'show';
  6491. }
  6492. window.setUserSetting( 'advImgDetails', mode );
  6493. },
  6494. editAttachment: function( event ) {
  6495. var editState = this.controller.states.get( 'edit-image' );
  6496. if ( window.imageEdit && editState ) {
  6497. event.preventDefault();
  6498. editState.set( 'image', this.model.attachment );
  6499. this.controller.setState( 'edit-image' );
  6500. }
  6501. },
  6502. replaceAttachment: function( event ) {
  6503. event.preventDefault();
  6504. this.controller.setState( 'replace-image' );
  6505. }
  6506. });
  6507. module.exports = ImageDetails;
  6508. /***/ }),
  6509. /***/ 6644:
  6510. /***/ (function(module) {
  6511. /**
  6512. * wp.media.view.Label
  6513. *
  6514. * @memberOf wp.media.view
  6515. *
  6516. * @class
  6517. * @augments wp.media.View
  6518. * @augments wp.Backbone.View
  6519. * @augments Backbone.View
  6520. */
  6521. var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
  6522. tagName: 'label',
  6523. className: 'screen-reader-text',
  6524. initialize: function() {
  6525. this.value = this.options.value;
  6526. },
  6527. render: function() {
  6528. this.$el.html( this.value );
  6529. return this;
  6530. }
  6531. });
  6532. module.exports = Label;
  6533. /***/ }),
  6534. /***/ 4861:
  6535. /***/ (function(module) {
  6536. var Frame = wp.media.view.Frame,
  6537. l10n = wp.media.view.l10n,
  6538. $ = jQuery,
  6539. MediaFrame;
  6540. /**
  6541. * wp.media.view.MediaFrame
  6542. *
  6543. * The frame used to create the media modal.
  6544. *
  6545. * @memberOf wp.media.view
  6546. *
  6547. * @class
  6548. * @augments wp.media.view.Frame
  6549. * @augments wp.media.View
  6550. * @augments wp.Backbone.View
  6551. * @augments Backbone.View
  6552. * @mixes wp.media.controller.StateMachine
  6553. */
  6554. MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
  6555. className: 'media-frame',
  6556. template: wp.template('media-frame'),
  6557. regions: ['menu','title','content','toolbar','router'],
  6558. events: {
  6559. 'click .media-frame-menu-toggle': 'toggleMenu'
  6560. },
  6561. /**
  6562. * @constructs
  6563. */
  6564. initialize: function() {
  6565. Frame.prototype.initialize.apply( this, arguments );
  6566. _.defaults( this.options, {
  6567. title: l10n.mediaFrameDefaultTitle,
  6568. modal: true,
  6569. uploader: true
  6570. });
  6571. // Ensure core UI is enabled.
  6572. this.$el.addClass('wp-core-ui');
  6573. // Initialize modal container view.
  6574. if ( this.options.modal ) {
  6575. this.modal = new wp.media.view.Modal({
  6576. controller: this,
  6577. title: this.options.title
  6578. });
  6579. this.modal.content( this );
  6580. }
  6581. // Force the uploader off if the upload limit has been exceeded or
  6582. // if the browser isn't supported.
  6583. if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
  6584. this.options.uploader = false;
  6585. }
  6586. // Initialize window-wide uploader.
  6587. if ( this.options.uploader ) {
  6588. this.uploader = new wp.media.view.UploaderWindow({
  6589. controller: this,
  6590. uploader: {
  6591. dropzone: this.modal ? this.modal.$el : this.$el,
  6592. container: this.$el
  6593. }
  6594. });
  6595. this.views.set( '.media-frame-uploader', this.uploader );
  6596. }
  6597. this.on( 'attach', _.bind( this.views.ready, this.views ), this );
  6598. // Bind default title creation.
  6599. this.on( 'title:create:default', this.createTitle, this );
  6600. this.title.mode('default');
  6601. // Bind default menu.
  6602. this.on( 'menu:create:default', this.createMenu, this );
  6603. // Set the menu ARIA tab panel attributes when the modal opens.
  6604. this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
  6605. // Set the router ARIA tab panel attributes when the modal opens.
  6606. this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
  6607. // Update the menu ARIA tab panel attributes when the content updates.
  6608. this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
  6609. // Update the router ARIA tab panel attributes when the content updates.
  6610. this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
  6611. },
  6612. /**
  6613. * Sets the attributes to be used on the menu ARIA tab panel.
  6614. *
  6615. * @since 5.3.0
  6616. *
  6617. * @return {void}
  6618. */
  6619. setMenuTabPanelAriaAttributes: function() {
  6620. var stateId = this.state().get( 'id' ),
  6621. tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
  6622. ariaLabelledby;
  6623. tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
  6624. if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
  6625. ariaLabelledby = 'menu-item-' + stateId;
  6626. // Set the tab panel attributes only if the tabs are visible.
  6627. tabPanelEl
  6628. .attr( {
  6629. role: 'tabpanel',
  6630. 'aria-labelledby': ariaLabelledby,
  6631. tabIndex: '0'
  6632. } );
  6633. }
  6634. },
  6635. /**
  6636. * Sets the attributes to be used on the router ARIA tab panel.
  6637. *
  6638. * @since 5.3.0
  6639. *
  6640. * @return {void}
  6641. */
  6642. setRouterTabPanelAriaAttributes: function() {
  6643. var tabPanelEl = this.$el.find( '.media-frame-content' ),
  6644. ariaLabelledby;
  6645. tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
  6646. // Set the tab panel attributes only if the tabs are visible.
  6647. if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
  6648. ariaLabelledby = 'menu-item-' + this.content._mode;
  6649. tabPanelEl
  6650. .attr( {
  6651. role: 'tabpanel',
  6652. 'aria-labelledby': ariaLabelledby,
  6653. tabIndex: '0'
  6654. } );
  6655. }
  6656. },
  6657. /**
  6658. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6659. */
  6660. render: function() {
  6661. // Activate the default state if no active state exists.
  6662. if ( ! this.state() && this.options.state ) {
  6663. this.setState( this.options.state );
  6664. }
  6665. /**
  6666. * call 'render' directly on the parent class
  6667. */
  6668. return Frame.prototype.render.apply( this, arguments );
  6669. },
  6670. /**
  6671. * @param {Object} title
  6672. * @this wp.media.controller.Region
  6673. */
  6674. createTitle: function( title ) {
  6675. title.view = new wp.media.View({
  6676. controller: this,
  6677. tagName: 'h1'
  6678. });
  6679. },
  6680. /**
  6681. * @param {Object} menu
  6682. * @this wp.media.controller.Region
  6683. */
  6684. createMenu: function( menu ) {
  6685. menu.view = new wp.media.view.Menu({
  6686. controller: this,
  6687. attributes: {
  6688. role: 'tablist',
  6689. 'aria-orientation': 'vertical'
  6690. }
  6691. });
  6692. this.menuView = menu.view;
  6693. },
  6694. toggleMenu: function( event ) {
  6695. var menu = this.$el.find( '.media-menu' );
  6696. menu.toggleClass( 'visible' );
  6697. $( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
  6698. },
  6699. /**
  6700. * @param {Object} toolbar
  6701. * @this wp.media.controller.Region
  6702. */
  6703. createToolbar: function( toolbar ) {
  6704. toolbar.view = new wp.media.view.Toolbar({
  6705. controller: this
  6706. });
  6707. },
  6708. /**
  6709. * @param {Object} router
  6710. * @this wp.media.controller.Region
  6711. */
  6712. createRouter: function( router ) {
  6713. router.view = new wp.media.view.Router({
  6714. controller: this,
  6715. attributes: {
  6716. role: 'tablist',
  6717. 'aria-orientation': 'horizontal'
  6718. }
  6719. });
  6720. this.routerView = router.view;
  6721. },
  6722. /**
  6723. * @param {Object} options
  6724. */
  6725. createIframeStates: function( options ) {
  6726. var settings = wp.media.view.settings,
  6727. tabs = settings.tabs,
  6728. tabUrl = settings.tabUrl,
  6729. $postId;
  6730. if ( ! tabs || ! tabUrl ) {
  6731. return;
  6732. }
  6733. // Add the post ID to the tab URL if it exists.
  6734. $postId = $('#post_ID');
  6735. if ( $postId.length ) {
  6736. tabUrl += '&post_id=' + $postId.val();
  6737. }
  6738. // Generate the tab states.
  6739. _.each( tabs, function( title, id ) {
  6740. this.state( 'iframe:' + id ).set( _.defaults({
  6741. tab: id,
  6742. src: tabUrl + '&tab=' + id,
  6743. title: title,
  6744. content: 'iframe',
  6745. menu: 'default'
  6746. }, options ) );
  6747. }, this );
  6748. this.on( 'content:create:iframe', this.iframeContent, this );
  6749. this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
  6750. this.on( 'menu:render:default', this.iframeMenu, this );
  6751. this.on( 'open', this.hijackThickbox, this );
  6752. this.on( 'close', this.restoreThickbox, this );
  6753. },
  6754. /**
  6755. * @param {Object} content
  6756. * @this wp.media.controller.Region
  6757. */
  6758. iframeContent: function( content ) {
  6759. this.$el.addClass('hide-toolbar');
  6760. content.view = new wp.media.view.Iframe({
  6761. controller: this
  6762. });
  6763. },
  6764. iframeContentCleanup: function() {
  6765. this.$el.removeClass('hide-toolbar');
  6766. },
  6767. iframeMenu: function( view ) {
  6768. var views = {};
  6769. if ( ! view ) {
  6770. return;
  6771. }
  6772. _.each( wp.media.view.settings.tabs, function( title, id ) {
  6773. views[ 'iframe:' + id ] = {
  6774. text: this.state( 'iframe:' + id ).get('title'),
  6775. priority: 200
  6776. };
  6777. }, this );
  6778. view.set( views );
  6779. },
  6780. hijackThickbox: function() {
  6781. var frame = this;
  6782. if ( ! window.tb_remove || this._tb_remove ) {
  6783. return;
  6784. }
  6785. this._tb_remove = window.tb_remove;
  6786. window.tb_remove = function() {
  6787. frame.close();
  6788. frame.reset();
  6789. frame.setState( frame.options.state );
  6790. frame._tb_remove.call( window );
  6791. };
  6792. },
  6793. restoreThickbox: function() {
  6794. if ( ! this._tb_remove ) {
  6795. return;
  6796. }
  6797. window.tb_remove = this._tb_remove;
  6798. delete this._tb_remove;
  6799. }
  6800. });
  6801. // Map some of the modal's methods to the frame.
  6802. _.each(['open','close','attach','detach','escape'], function( method ) {
  6803. /**
  6804. * @function open
  6805. * @memberOf wp.media.view.MediaFrame
  6806. * @instance
  6807. *
  6808. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6809. */
  6810. /**
  6811. * @function close
  6812. * @memberOf wp.media.view.MediaFrame
  6813. * @instance
  6814. *
  6815. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6816. */
  6817. /**
  6818. * @function attach
  6819. * @memberOf wp.media.view.MediaFrame
  6820. * @instance
  6821. *
  6822. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6823. */
  6824. /**
  6825. * @function detach
  6826. * @memberOf wp.media.view.MediaFrame
  6827. * @instance
  6828. *
  6829. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6830. */
  6831. /**
  6832. * @function escape
  6833. * @memberOf wp.media.view.MediaFrame
  6834. * @instance
  6835. *
  6836. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6837. */
  6838. MediaFrame.prototype[ method ] = function() {
  6839. if ( this.modal ) {
  6840. this.modal[ method ].apply( this.modal, arguments );
  6841. }
  6842. return this;
  6843. };
  6844. });
  6845. module.exports = MediaFrame;
  6846. /***/ }),
  6847. /***/ 917:
  6848. /***/ (function(module) {
  6849. var MenuItem;
  6850. /**
  6851. * wp.media.view.MenuItem
  6852. *
  6853. * @memberOf wp.media.view
  6854. *
  6855. * @class
  6856. * @augments wp.media.View
  6857. * @augments wp.Backbone.View
  6858. * @augments Backbone.View
  6859. */
  6860. MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
  6861. tagName: 'button',
  6862. className: 'media-menu-item',
  6863. attributes: {
  6864. type: 'button',
  6865. role: 'tab'
  6866. },
  6867. events: {
  6868. 'click': '_click'
  6869. },
  6870. /**
  6871. * Allows to override the click event.
  6872. */
  6873. _click: function() {
  6874. var clickOverride = this.options.click;
  6875. if ( clickOverride ) {
  6876. clickOverride.call( this );
  6877. } else {
  6878. this.click();
  6879. }
  6880. },
  6881. click: function() {
  6882. var state = this.options.state;
  6883. if ( state ) {
  6884. this.controller.setState( state );
  6885. // Toggle the menu visibility in the responsive view.
  6886. this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
  6887. }
  6888. },
  6889. /**
  6890. * @return {wp.media.view.MenuItem} returns itself to allow chaining.
  6891. */
  6892. render: function() {
  6893. var options = this.options,
  6894. menuProperty = options.state || options.contentMode;
  6895. if ( options.text ) {
  6896. this.$el.text( options.text );
  6897. } else if ( options.html ) {
  6898. this.$el.html( options.html );
  6899. }
  6900. // Set the menu item ID based on the frame state associated to the menu item.
  6901. this.$el.attr( 'id', 'menu-item-' + menuProperty );
  6902. return this;
  6903. }
  6904. });
  6905. module.exports = MenuItem;
  6906. /***/ }),
  6907. /***/ 2596:
  6908. /***/ (function(module) {
  6909. var MenuItem = wp.media.view.MenuItem,
  6910. PriorityList = wp.media.view.PriorityList,
  6911. Menu;
  6912. /**
  6913. * wp.media.view.Menu
  6914. *
  6915. * @memberOf wp.media.view
  6916. *
  6917. * @class
  6918. * @augments wp.media.view.PriorityList
  6919. * @augments wp.media.View
  6920. * @augments wp.Backbone.View
  6921. * @augments Backbone.View
  6922. */
  6923. Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
  6924. tagName: 'div',
  6925. className: 'media-menu',
  6926. property: 'state',
  6927. ItemView: MenuItem,
  6928. region: 'menu',
  6929. attributes: {
  6930. role: 'tablist',
  6931. 'aria-orientation': 'horizontal'
  6932. },
  6933. initialize: function() {
  6934. this._views = {};
  6935. this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
  6936. delete this.options.views;
  6937. if ( ! this.options.silent ) {
  6938. this.render();
  6939. }
  6940. // Initialize the Focus Manager.
  6941. this.focusManager = new wp.media.view.FocusManager( {
  6942. el: this.el,
  6943. mode: 'tabsNavigation'
  6944. } );
  6945. // The menu is always rendered and can be visible or hidden on some frames.
  6946. this.isVisible = true;
  6947. },
  6948. /**
  6949. * @param {Object} options
  6950. * @param {string} id
  6951. * @return {wp.media.View}
  6952. */
  6953. toView: function( options, id ) {
  6954. options = options || {};
  6955. options[ this.property ] = options[ this.property ] || id;
  6956. return new this.ItemView( options ).render();
  6957. },
  6958. ready: function() {
  6959. /**
  6960. * call 'ready' directly on the parent class
  6961. */
  6962. PriorityList.prototype.ready.apply( this, arguments );
  6963. this.visibility();
  6964. // Set up aria tabs initial attributes.
  6965. this.focusManager.setupAriaTabs();
  6966. },
  6967. set: function() {
  6968. /**
  6969. * call 'set' directly on the parent class
  6970. */
  6971. PriorityList.prototype.set.apply( this, arguments );
  6972. this.visibility();
  6973. },
  6974. unset: function() {
  6975. /**
  6976. * call 'unset' directly on the parent class
  6977. */
  6978. PriorityList.prototype.unset.apply( this, arguments );
  6979. this.visibility();
  6980. },
  6981. visibility: function() {
  6982. var region = this.region,
  6983. view = this.controller[ region ].get(),
  6984. views = this.views.get(),
  6985. hide = ! views || views.length < 2;
  6986. if ( this === view ) {
  6987. // Flag this menu as hidden or visible.
  6988. this.isVisible = ! hide;
  6989. // Set or remove a CSS class to hide the menu.
  6990. this.controller.$el.toggleClass( 'hide-' + region, hide );
  6991. }
  6992. },
  6993. /**
  6994. * @param {string} id
  6995. */
  6996. select: function( id ) {
  6997. var view = this.get( id );
  6998. if ( ! view ) {
  6999. return;
  7000. }
  7001. this.deselect();
  7002. view.$el.addClass('active');
  7003. // Set up again the aria tabs initial attributes after the menu updates.
  7004. this.focusManager.setupAriaTabs();
  7005. },
  7006. deselect: function() {
  7007. this.$el.children().removeClass('active');
  7008. },
  7009. hide: function( id ) {
  7010. var view = this.get( id );
  7011. if ( ! view ) {
  7012. return;
  7013. }
  7014. view.$el.addClass('hidden');
  7015. },
  7016. show: function( id ) {
  7017. var view = this.get( id );
  7018. if ( ! view ) {
  7019. return;
  7020. }
  7021. view.$el.removeClass('hidden');
  7022. }
  7023. });
  7024. module.exports = Menu;
  7025. /***/ }),
  7026. /***/ 3939:
  7027. /***/ (function(module) {
  7028. var $ = jQuery,
  7029. Modal;
  7030. /**
  7031. * wp.media.view.Modal
  7032. *
  7033. * A modal view, which the media modal uses as its default container.
  7034. *
  7035. * @memberOf wp.media.view
  7036. *
  7037. * @class
  7038. * @augments wp.media.View
  7039. * @augments wp.Backbone.View
  7040. * @augments Backbone.View
  7041. */
  7042. Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
  7043. tagName: 'div',
  7044. template: wp.template('media-modal'),
  7045. events: {
  7046. 'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
  7047. 'keydown': 'keydown'
  7048. },
  7049. clickedOpenerEl: null,
  7050. initialize: function() {
  7051. _.defaults( this.options, {
  7052. container: document.body,
  7053. title: '',
  7054. propagate: true,
  7055. hasCloseButton: true
  7056. });
  7057. this.focusManager = new wp.media.view.FocusManager({
  7058. el: this.el
  7059. });
  7060. },
  7061. /**
  7062. * @return {Object}
  7063. */
  7064. prepare: function() {
  7065. return {
  7066. title: this.options.title,
  7067. hasCloseButton: this.options.hasCloseButton
  7068. };
  7069. },
  7070. /**
  7071. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7072. */
  7073. attach: function() {
  7074. if ( this.views.attached ) {
  7075. return this;
  7076. }
  7077. if ( ! this.views.rendered ) {
  7078. this.render();
  7079. }
  7080. this.$el.appendTo( this.options.container );
  7081. // Manually mark the view as attached and trigger ready.
  7082. this.views.attached = true;
  7083. this.views.ready();
  7084. return this.propagate('attach');
  7085. },
  7086. /**
  7087. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7088. */
  7089. detach: function() {
  7090. if ( this.$el.is(':visible') ) {
  7091. this.close();
  7092. }
  7093. this.$el.detach();
  7094. this.views.attached = false;
  7095. return this.propagate('detach');
  7096. },
  7097. /**
  7098. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7099. */
  7100. open: function() {
  7101. var $el = this.$el,
  7102. mceEditor;
  7103. if ( $el.is(':visible') ) {
  7104. return this;
  7105. }
  7106. this.clickedOpenerEl = document.activeElement;
  7107. if ( ! this.views.attached ) {
  7108. this.attach();
  7109. }
  7110. // Disable page scrolling.
  7111. $( 'body' ).addClass( 'modal-open' );
  7112. $el.show();
  7113. // Try to close the onscreen keyboard.
  7114. if ( 'ontouchend' in document ) {
  7115. if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
  7116. mceEditor.iframeElement.focus();
  7117. mceEditor.iframeElement.blur();
  7118. setTimeout( function() {
  7119. mceEditor.iframeElement.blur();
  7120. }, 100 );
  7121. }
  7122. }
  7123. // Set initial focus on the content instead of this view element, to avoid page scrolling.
  7124. this.$( '.media-modal' ).trigger( 'focus' );
  7125. // Hide the page content from assistive technologies.
  7126. this.focusManager.setAriaHiddenOnBodyChildren( $el );
  7127. return this.propagate('open');
  7128. },
  7129. /**
  7130. * @param {Object} options
  7131. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7132. */
  7133. close: function( options ) {
  7134. if ( ! this.views.attached || ! this.$el.is(':visible') ) {
  7135. return this;
  7136. }
  7137. // Pause current audio/video even after closing the modal.
  7138. $( '.mejs-pause button' ).trigger( 'click' );
  7139. // Enable page scrolling.
  7140. $( 'body' ).removeClass( 'modal-open' );
  7141. // Hide the modal element by adding display:none.
  7142. this.$el.hide();
  7143. /*
  7144. * Make visible again to assistive technologies all body children that
  7145. * have been made hidden when the modal opened.
  7146. */
  7147. this.focusManager.removeAriaHiddenFromBodyChildren();
  7148. // Move focus back in useful location once modal is closed.
  7149. if ( null !== this.clickedOpenerEl ) {
  7150. // Move focus back to the element that opened the modal.
  7151. this.clickedOpenerEl.focus();
  7152. } else {
  7153. // Fallback to the admin page main element.
  7154. $( '#wpbody-content' )
  7155. .attr( 'tabindex', '-1' )
  7156. .trigger( 'focus' );
  7157. }
  7158. this.propagate('close');
  7159. if ( options && options.escape ) {
  7160. this.propagate('escape');
  7161. }
  7162. return this;
  7163. },
  7164. /**
  7165. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7166. */
  7167. escape: function() {
  7168. return this.close({ escape: true });
  7169. },
  7170. /**
  7171. * @param {Object} event
  7172. */
  7173. escapeHandler: function( event ) {
  7174. event.preventDefault();
  7175. this.escape();
  7176. },
  7177. /**
  7178. * @param {Array|Object} content Views to register to '.media-modal-content'
  7179. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7180. */
  7181. content: function( content ) {
  7182. this.views.set( '.media-modal-content', content );
  7183. return this;
  7184. },
  7185. /**
  7186. * Triggers a modal event and if the `propagate` option is set,
  7187. * forwards events to the modal's controller.
  7188. *
  7189. * @param {string} id
  7190. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7191. */
  7192. propagate: function( id ) {
  7193. this.trigger( id );
  7194. if ( this.options.propagate ) {
  7195. this.controller.trigger( id );
  7196. }
  7197. return this;
  7198. },
  7199. /**
  7200. * @param {Object} event
  7201. */
  7202. keydown: function( event ) {
  7203. // Close the modal when escape is pressed.
  7204. if ( 27 === event.which && this.$el.is(':visible') ) {
  7205. this.escape();
  7206. event.stopImmediatePropagation();
  7207. }
  7208. }
  7209. });
  7210. module.exports = Modal;
  7211. /***/ }),
  7212. /***/ 1993:
  7213. /***/ (function(module) {
  7214. /**
  7215. * wp.media.view.PriorityList
  7216. *
  7217. * @memberOf wp.media.view
  7218. *
  7219. * @class
  7220. * @augments wp.media.View
  7221. * @augments wp.Backbone.View
  7222. * @augments Backbone.View
  7223. */
  7224. var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
  7225. tagName: 'div',
  7226. initialize: function() {
  7227. this._views = {};
  7228. this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
  7229. delete this.options.views;
  7230. if ( ! this.options.silent ) {
  7231. this.render();
  7232. }
  7233. },
  7234. /**
  7235. * @param {string} id
  7236. * @param {wp.media.View|Object} view
  7237. * @param {Object} options
  7238. * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
  7239. */
  7240. set: function( id, view, options ) {
  7241. var priority, views, index;
  7242. options = options || {};
  7243. // Accept an object with an `id` : `view` mapping.
  7244. if ( _.isObject( id ) ) {
  7245. _.each( id, function( view, id ) {
  7246. this.set( id, view );
  7247. }, this );
  7248. return this;
  7249. }
  7250. if ( ! (view instanceof Backbone.View) ) {
  7251. view = this.toView( view, id, options );
  7252. }
  7253. view.controller = view.controller || this.controller;
  7254. this.unset( id );
  7255. priority = view.options.priority || 10;
  7256. views = this.views.get() || [];
  7257. _.find( views, function( existing, i ) {
  7258. if ( existing.options.priority > priority ) {
  7259. index = i;
  7260. return true;
  7261. }
  7262. });
  7263. this._views[ id ] = view;
  7264. this.views.add( view, {
  7265. at: _.isNumber( index ) ? index : views.length || 0
  7266. });
  7267. return this;
  7268. },
  7269. /**
  7270. * @param {string} id
  7271. * @return {wp.media.View}
  7272. */
  7273. get: function( id ) {
  7274. return this._views[ id ];
  7275. },
  7276. /**
  7277. * @param {string} id
  7278. * @return {wp.media.view.PriorityList}
  7279. */
  7280. unset: function( id ) {
  7281. var view = this.get( id );
  7282. if ( view ) {
  7283. view.remove();
  7284. }
  7285. delete this._views[ id ];
  7286. return this;
  7287. },
  7288. /**
  7289. * @param {Object} options
  7290. * @return {wp.media.View}
  7291. */
  7292. toView: function( options ) {
  7293. return new wp.media.View( options );
  7294. }
  7295. });
  7296. module.exports = PriorityList;
  7297. /***/ }),
  7298. /***/ 9484:
  7299. /***/ (function(module) {
  7300. /**
  7301. * wp.media.view.RouterItem
  7302. *
  7303. * @memberOf wp.media.view
  7304. *
  7305. * @class
  7306. * @augments wp.media.view.MenuItem
  7307. * @augments wp.media.View
  7308. * @augments wp.Backbone.View
  7309. * @augments Backbone.View
  7310. */
  7311. var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
  7312. /**
  7313. * On click handler to activate the content region's corresponding mode.
  7314. */
  7315. click: function() {
  7316. var contentMode = this.options.contentMode;
  7317. if ( contentMode ) {
  7318. this.controller.content.mode( contentMode );
  7319. }
  7320. }
  7321. });
  7322. module.exports = RouterItem;
  7323. /***/ }),
  7324. /***/ 1562:
  7325. /***/ (function(module) {
  7326. var Menu = wp.media.view.Menu,
  7327. Router;
  7328. /**
  7329. * wp.media.view.Router
  7330. *
  7331. * @memberOf wp.media.view
  7332. *
  7333. * @class
  7334. * @augments wp.media.view.Menu
  7335. * @augments wp.media.view.PriorityList
  7336. * @augments wp.media.View
  7337. * @augments wp.Backbone.View
  7338. * @augments Backbone.View
  7339. */
  7340. Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
  7341. tagName: 'div',
  7342. className: 'media-router',
  7343. property: 'contentMode',
  7344. ItemView: wp.media.view.RouterItem,
  7345. region: 'router',
  7346. attributes: {
  7347. role: 'tablist',
  7348. 'aria-orientation': 'horizontal'
  7349. },
  7350. initialize: function() {
  7351. this.controller.on( 'content:render', this.update, this );
  7352. // Call 'initialize' directly on the parent class.
  7353. Menu.prototype.initialize.apply( this, arguments );
  7354. },
  7355. update: function() {
  7356. var mode = this.controller.content.mode();
  7357. if ( mode ) {
  7358. this.select( mode );
  7359. }
  7360. }
  7361. });
  7362. module.exports = Router;
  7363. /***/ }),
  7364. /***/ 4556:
  7365. /***/ (function(module) {
  7366. var Search;
  7367. /**
  7368. * wp.media.view.Search
  7369. *
  7370. * @memberOf wp.media.view
  7371. *
  7372. * @class
  7373. * @augments wp.media.View
  7374. * @augments wp.Backbone.View
  7375. * @augments Backbone.View
  7376. */
  7377. Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
  7378. tagName: 'input',
  7379. className: 'search',
  7380. id: 'media-search-input',
  7381. attributes: {
  7382. type: 'search'
  7383. },
  7384. events: {
  7385. 'input': 'search'
  7386. },
  7387. /**
  7388. * @return {wp.media.view.Search} Returns itself to allow chaining.
  7389. */
  7390. render: function() {
  7391. this.el.value = this.model.escape('search');
  7392. return this;
  7393. },
  7394. search: _.debounce( function( event ) {
  7395. var searchTerm = event.target.value.trim();
  7396. // Trigger the search only after 2 ASCII characters.
  7397. if ( searchTerm && searchTerm.length > 1 ) {
  7398. this.model.set( 'search', searchTerm );
  7399. } else {
  7400. this.model.unset( 'search' );
  7401. }
  7402. }, 500 )
  7403. });
  7404. module.exports = Search;
  7405. /***/ }),
  7406. /***/ 6191:
  7407. /***/ (function(module) {
  7408. var _n = wp.i18n._n,
  7409. sprintf = wp.i18n.sprintf,
  7410. Selection;
  7411. /**
  7412. * wp.media.view.Selection
  7413. *
  7414. * @memberOf wp.media.view
  7415. *
  7416. * @class
  7417. * @augments wp.media.View
  7418. * @augments wp.Backbone.View
  7419. * @augments Backbone.View
  7420. */
  7421. Selection = wp.media.View.extend(/** @lends wp.media.view.Selection.prototype */{
  7422. tagName: 'div',
  7423. className: 'media-selection',
  7424. template: wp.template('media-selection'),
  7425. events: {
  7426. 'click .edit-selection': 'edit',
  7427. 'click .clear-selection': 'clear'
  7428. },
  7429. initialize: function() {
  7430. _.defaults( this.options, {
  7431. editable: false,
  7432. clearable: true
  7433. });
  7434. /**
  7435. * @member {wp.media.view.Attachments.Selection}
  7436. */
  7437. this.attachments = new wp.media.view.Attachments.Selection({
  7438. controller: this.controller,
  7439. collection: this.collection,
  7440. selection: this.collection,
  7441. model: new Backbone.Model()
  7442. });
  7443. this.views.set( '.selection-view', this.attachments );
  7444. this.collection.on( 'add remove reset', this.refresh, this );
  7445. this.controller.on( 'content:activate', this.refresh, this );
  7446. },
  7447. ready: function() {
  7448. this.refresh();
  7449. },
  7450. refresh: function() {
  7451. // If the selection hasn't been rendered, bail.
  7452. if ( ! this.$el.children().length ) {
  7453. return;
  7454. }
  7455. var collection = this.collection,
  7456. editing = 'edit-selection' === this.controller.content.mode();
  7457. // If nothing is selected, display nothing.
  7458. this.$el.toggleClass( 'empty', ! collection.length );
  7459. this.$el.toggleClass( 'one', 1 === collection.length );
  7460. this.$el.toggleClass( 'editing', editing );
  7461. this.$( '.count' ).text(
  7462. /* translators: %s: Number of selected media attachments. */
  7463. sprintf( _n( '%s item selected', '%s items selected', collection.length ), collection.length )
  7464. );
  7465. },
  7466. edit: function( event ) {
  7467. event.preventDefault();
  7468. if ( this.options.editable ) {
  7469. this.options.editable.call( this, this.collection );
  7470. }
  7471. },
  7472. clear: function( event ) {
  7473. event.preventDefault();
  7474. this.collection.reset();
  7475. // Move focus to the modal.
  7476. this.controller.modal.focusManager.focus();
  7477. }
  7478. });
  7479. module.exports = Selection;
  7480. /***/ }),
  7481. /***/ 859:
  7482. /***/ (function(module) {
  7483. var View = wp.media.View,
  7484. $ = Backbone.$,
  7485. Settings;
  7486. /**
  7487. * wp.media.view.Settings
  7488. *
  7489. * @memberOf wp.media.view
  7490. *
  7491. * @class
  7492. * @augments wp.media.View
  7493. * @augments wp.Backbone.View
  7494. * @augments Backbone.View
  7495. */
  7496. Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
  7497. events: {
  7498. 'click button': 'updateHandler',
  7499. 'change input': 'updateHandler',
  7500. 'change select': 'updateHandler',
  7501. 'change textarea': 'updateHandler'
  7502. },
  7503. initialize: function() {
  7504. this.model = this.model || new Backbone.Model();
  7505. this.listenTo( this.model, 'change', this.updateChanges );
  7506. },
  7507. prepare: function() {
  7508. return _.defaults({
  7509. model: this.model.toJSON()
  7510. }, this.options );
  7511. },
  7512. /**
  7513. * @return {wp.media.view.Settings} Returns itself to allow chaining.
  7514. */
  7515. render: function() {
  7516. View.prototype.render.apply( this, arguments );
  7517. // Select the correct values.
  7518. _( this.model.attributes ).chain().keys().each( this.update, this );
  7519. return this;
  7520. },
  7521. /**
  7522. * @param {string} key
  7523. */
  7524. update: function( key ) {
  7525. var value = this.model.get( key ),
  7526. $setting = this.$('[data-setting="' + key + '"]'),
  7527. $buttons, $value;
  7528. // Bail if we didn't find a matching setting.
  7529. if ( ! $setting.length ) {
  7530. return;
  7531. }
  7532. // Attempt to determine how the setting is rendered and update
  7533. // the selected value.
  7534. // Handle dropdowns.
  7535. if ( $setting.is('select') ) {
  7536. $value = $setting.find('[value="' + value + '"]');
  7537. if ( $value.length ) {
  7538. $setting.find('option').prop( 'selected', false );
  7539. $value.prop( 'selected', true );
  7540. } else {
  7541. // If we can't find the desired value, record what *is* selected.
  7542. this.model.set( key, $setting.find(':selected').val() );
  7543. }
  7544. // Handle button groups.
  7545. } else if ( $setting.hasClass('button-group') ) {
  7546. $buttons = $setting.find( 'button' )
  7547. .removeClass( 'active' )
  7548. .attr( 'aria-pressed', 'false' );
  7549. $buttons.filter( '[value="' + value + '"]' )
  7550. .addClass( 'active' )
  7551. .attr( 'aria-pressed', 'true' );
  7552. // Handle text inputs and textareas.
  7553. } else if ( $setting.is('input[type="text"], textarea') ) {
  7554. if ( ! $setting.is(':focus') ) {
  7555. $setting.val( value );
  7556. }
  7557. // Handle checkboxes.
  7558. } else if ( $setting.is('input[type="checkbox"]') ) {
  7559. $setting.prop( 'checked', !! value && 'false' !== value );
  7560. }
  7561. },
  7562. /**
  7563. * @param {Object} event
  7564. */
  7565. updateHandler: function( event ) {
  7566. var $setting = $( event.target ).closest('[data-setting]'),
  7567. value = event.target.value,
  7568. userSetting;
  7569. event.preventDefault();
  7570. if ( ! $setting.length ) {
  7571. return;
  7572. }
  7573. // Use the correct value for checkboxes.
  7574. if ( $setting.is('input[type="checkbox"]') ) {
  7575. value = $setting[0].checked;
  7576. }
  7577. // Update the corresponding setting.
  7578. this.model.set( $setting.data('setting'), value );
  7579. // If the setting has a corresponding user setting,
  7580. // update that as well.
  7581. userSetting = $setting.data('userSetting');
  7582. if ( userSetting ) {
  7583. window.setUserSetting( userSetting, value );
  7584. }
  7585. },
  7586. updateChanges: function( model ) {
  7587. if ( model.hasChanged() ) {
  7588. _( model.changed ).chain().keys().each( this.update, this );
  7589. }
  7590. }
  7591. });
  7592. module.exports = Settings;
  7593. /***/ }),
  7594. /***/ 2176:
  7595. /***/ (function(module) {
  7596. var Settings = wp.media.view.Settings,
  7597. AttachmentDisplay;
  7598. /**
  7599. * wp.media.view.Settings.AttachmentDisplay
  7600. *
  7601. * @memberOf wp.media.view.Settings
  7602. *
  7603. * @class
  7604. * @augments wp.media.view.Settings
  7605. * @augments wp.media.View
  7606. * @augments wp.Backbone.View
  7607. * @augments Backbone.View
  7608. */
  7609. AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
  7610. className: 'attachment-display-settings',
  7611. template: wp.template('attachment-display-settings'),
  7612. initialize: function() {
  7613. var attachment = this.options.attachment;
  7614. _.defaults( this.options, {
  7615. userSettings: false
  7616. });
  7617. // Call 'initialize' directly on the parent class.
  7618. Settings.prototype.initialize.apply( this, arguments );
  7619. this.listenTo( this.model, 'change:link', this.updateLinkTo );
  7620. if ( attachment ) {
  7621. attachment.on( 'change:uploading', this.render, this );
  7622. }
  7623. },
  7624. dispose: function() {
  7625. var attachment = this.options.attachment;
  7626. if ( attachment ) {
  7627. attachment.off( null, null, this );
  7628. }
  7629. /**
  7630. * call 'dispose' directly on the parent class
  7631. */
  7632. Settings.prototype.dispose.apply( this, arguments );
  7633. },
  7634. /**
  7635. * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
  7636. */
  7637. render: function() {
  7638. var attachment = this.options.attachment;
  7639. if ( attachment ) {
  7640. _.extend( this.options, {
  7641. sizes: attachment.get('sizes'),
  7642. type: attachment.get('type')
  7643. });
  7644. }
  7645. /**
  7646. * call 'render' directly on the parent class
  7647. */
  7648. Settings.prototype.render.call( this );
  7649. this.updateLinkTo();
  7650. return this;
  7651. },
  7652. updateLinkTo: function() {
  7653. var linkTo = this.model.get('link'),
  7654. $input = this.$('.link-to-custom'),
  7655. attachment = this.options.attachment;
  7656. if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
  7657. $input.closest( '.setting' ).addClass( 'hidden' );
  7658. return;
  7659. }
  7660. if ( attachment ) {
  7661. if ( 'post' === linkTo ) {
  7662. $input.val( attachment.get('link') );
  7663. } else if ( 'file' === linkTo ) {
  7664. $input.val( attachment.get('url') );
  7665. } else if ( ! this.model.get('linkUrl') ) {
  7666. $input.val('http://');
  7667. }
  7668. $input.prop( 'readonly', 'custom' !== linkTo );
  7669. }
  7670. $input.closest( '.setting' ).removeClass( 'hidden' );
  7671. if ( $input.length ) {
  7672. $input[0].scrollIntoView();
  7673. }
  7674. }
  7675. });
  7676. module.exports = AttachmentDisplay;
  7677. /***/ }),
  7678. /***/ 6872:
  7679. /***/ (function(module) {
  7680. /**
  7681. * wp.media.view.Settings.Gallery
  7682. *
  7683. * @memberOf wp.media.view.Settings
  7684. *
  7685. * @class
  7686. * @augments wp.media.view.Settings
  7687. * @augments wp.media.View
  7688. * @augments wp.Backbone.View
  7689. * @augments Backbone.View
  7690. */
  7691. var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
  7692. className: 'collection-settings gallery-settings',
  7693. template: wp.template('gallery-settings')
  7694. });
  7695. module.exports = Gallery;
  7696. /***/ }),
  7697. /***/ 8488:
  7698. /***/ (function(module) {
  7699. /**
  7700. * wp.media.view.Settings.Playlist
  7701. *
  7702. * @memberOf wp.media.view.Settings
  7703. *
  7704. * @class
  7705. * @augments wp.media.view.Settings
  7706. * @augments wp.media.View
  7707. * @augments wp.Backbone.View
  7708. * @augments Backbone.View
  7709. */
  7710. var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
  7711. className: 'collection-settings playlist-settings',
  7712. template: wp.template('playlist-settings')
  7713. });
  7714. module.exports = Playlist;
  7715. /***/ }),
  7716. /***/ 9799:
  7717. /***/ (function(module) {
  7718. /**
  7719. * wp.media.view.Sidebar
  7720. *
  7721. * @memberOf wp.media.view
  7722. *
  7723. * @class
  7724. * @augments wp.media.view.PriorityList
  7725. * @augments wp.media.View
  7726. * @augments wp.Backbone.View
  7727. * @augments Backbone.View
  7728. */
  7729. var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
  7730. className: 'media-sidebar'
  7731. });
  7732. module.exports = Sidebar;
  7733. /***/ }),
  7734. /***/ 5187:
  7735. /***/ (function(module) {
  7736. var View = wp.media.view,
  7737. SiteIconCropper;
  7738. /**
  7739. * wp.media.view.SiteIconCropper
  7740. *
  7741. * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
  7742. *
  7743. * Takes imgAreaSelect options from
  7744. * wp.customize.SiteIconControl.calculateImageSelectOptions.
  7745. *
  7746. * @memberOf wp.media.view
  7747. *
  7748. * @class
  7749. * @augments wp.media.view.Cropper
  7750. * @augments wp.media.View
  7751. * @augments wp.Backbone.View
  7752. * @augments Backbone.View
  7753. */
  7754. SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
  7755. className: 'crop-content site-icon',
  7756. ready: function () {
  7757. View.Cropper.prototype.ready.apply( this, arguments );
  7758. this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
  7759. },
  7760. addSidebar: function() {
  7761. this.sidebar = new wp.media.view.Sidebar({
  7762. controller: this.controller
  7763. });
  7764. this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
  7765. controller: this.controller,
  7766. attachment: this.options.attachment
  7767. }) );
  7768. this.controller.cropperView.views.add( this.sidebar );
  7769. }
  7770. });
  7771. module.exports = SiteIconCropper;
  7772. /***/ }),
  7773. /***/ 8260:
  7774. /***/ (function(module) {
  7775. var View = wp.media.View,
  7776. $ = jQuery,
  7777. SiteIconPreview;
  7778. /**
  7779. * wp.media.view.SiteIconPreview
  7780. *
  7781. * Shows a preview of the Site Icon as a favicon and app icon while cropping.
  7782. *
  7783. * @memberOf wp.media.view
  7784. *
  7785. * @class
  7786. * @augments wp.media.View
  7787. * @augments wp.Backbone.View
  7788. * @augments Backbone.View
  7789. */
  7790. SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
  7791. className: 'site-icon-preview',
  7792. template: wp.template( 'site-icon-preview' ),
  7793. ready: function() {
  7794. this.controller.imgSelect.setOptions({
  7795. onInit: this.updatePreview,
  7796. onSelectChange: this.updatePreview
  7797. });
  7798. },
  7799. prepare: function() {
  7800. return {
  7801. url: this.options.attachment.get( 'url' )
  7802. };
  7803. },
  7804. updatePreview: function( img, coords ) {
  7805. var rx = 64 / coords.width,
  7806. ry = 64 / coords.height,
  7807. preview_rx = 16 / coords.width,
  7808. preview_ry = 16 / coords.height;
  7809. $( '#preview-app-icon' ).css({
  7810. width: Math.round(rx * this.imageWidth ) + 'px',
  7811. height: Math.round(ry * this.imageHeight ) + 'px',
  7812. marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
  7813. marginTop: '-' + Math.round(ry * coords.y1) + 'px'
  7814. });
  7815. $( '#preview-favicon' ).css({
  7816. width: Math.round( preview_rx * this.imageWidth ) + 'px',
  7817. height: Math.round( preview_ry * this.imageHeight ) + 'px',
  7818. marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
  7819. marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
  7820. });
  7821. }
  7822. });
  7823. module.exports = SiteIconPreview;
  7824. /***/ }),
  7825. /***/ 2234:
  7826. /***/ (function(module) {
  7827. /**
  7828. * wp.media.view.Spinner
  7829. *
  7830. * Represents a spinner in the Media Library.
  7831. *
  7832. * @since 3.9.0
  7833. *
  7834. * @memberOf wp.media.view
  7835. *
  7836. * @class
  7837. * @augments wp.media.View
  7838. * @augments wp.Backbone.View
  7839. * @augments Backbone.View
  7840. */
  7841. var Spinner = wp.media.View.extend(/** @lends wp.media.view.Spinner.prototype */{
  7842. tagName: 'span',
  7843. className: 'spinner',
  7844. spinnerTimeout: false,
  7845. delay: 400,
  7846. /**
  7847. * Shows the spinner. Delays the visibility by the configured amount.
  7848. *
  7849. * @since 3.9.0
  7850. *
  7851. * @return {wp.media.view.Spinner} The spinner.
  7852. */
  7853. show: function() {
  7854. if ( ! this.spinnerTimeout ) {
  7855. this.spinnerTimeout = _.delay(function( $el ) {
  7856. $el.addClass( 'is-active' );
  7857. }, this.delay, this.$el );
  7858. }
  7859. return this;
  7860. },
  7861. /**
  7862. * Hides the spinner.
  7863. *
  7864. * @since 3.9.0
  7865. *
  7866. * @return {wp.media.view.Spinner} The spinner.
  7867. */
  7868. hide: function() {
  7869. this.$el.removeClass( 'is-active' );
  7870. this.spinnerTimeout = clearTimeout( this.spinnerTimeout );
  7871. return this;
  7872. }
  7873. });
  7874. module.exports = Spinner;
  7875. /***/ }),
  7876. /***/ 9510:
  7877. /***/ (function(module) {
  7878. var View = wp.media.View,
  7879. Toolbar;
  7880. /**
  7881. * wp.media.view.Toolbar
  7882. *
  7883. * A toolbar which consists of a primary and a secondary section. Each sections
  7884. * can be filled with views.
  7885. *
  7886. * @memberOf wp.media.view
  7887. *
  7888. * @class
  7889. * @augments wp.media.View
  7890. * @augments wp.Backbone.View
  7891. * @augments Backbone.View
  7892. */
  7893. Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
  7894. tagName: 'div',
  7895. className: 'media-toolbar',
  7896. initialize: function() {
  7897. var state = this.controller.state(),
  7898. selection = this.selection = state.get('selection'),
  7899. library = this.library = state.get('library');
  7900. this._views = {};
  7901. // The toolbar is composed of two `PriorityList` views.
  7902. this.primary = new wp.media.view.PriorityList();
  7903. this.secondary = new wp.media.view.PriorityList();
  7904. this.primary.$el.addClass('media-toolbar-primary search-form');
  7905. this.secondary.$el.addClass('media-toolbar-secondary');
  7906. this.views.set([ this.secondary, this.primary ]);
  7907. if ( this.options.items ) {
  7908. this.set( this.options.items, { silent: true });
  7909. }
  7910. if ( ! this.options.silent ) {
  7911. this.render();
  7912. }
  7913. if ( selection ) {
  7914. selection.on( 'add remove reset', this.refresh, this );
  7915. }
  7916. if ( library ) {
  7917. library.on( 'add remove reset', this.refresh, this );
  7918. }
  7919. },
  7920. /**
  7921. * @return {wp.media.view.Toolbar} Returns itsef to allow chaining
  7922. */
  7923. dispose: function() {
  7924. if ( this.selection ) {
  7925. this.selection.off( null, null, this );
  7926. }
  7927. if ( this.library ) {
  7928. this.library.off( null, null, this );
  7929. }
  7930. /**
  7931. * call 'dispose' directly on the parent class
  7932. */
  7933. return View.prototype.dispose.apply( this, arguments );
  7934. },
  7935. ready: function() {
  7936. this.refresh();
  7937. },
  7938. /**
  7939. * @param {string} id
  7940. * @param {Backbone.View|Object} view
  7941. * @param {Object} [options={}]
  7942. * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
  7943. */
  7944. set: function( id, view, options ) {
  7945. var list;
  7946. options = options || {};
  7947. // Accept an object with an `id` : `view` mapping.
  7948. if ( _.isObject( id ) ) {
  7949. _.each( id, function( view, id ) {
  7950. this.set( id, view, { silent: true });
  7951. }, this );
  7952. } else {
  7953. if ( ! ( view instanceof Backbone.View ) ) {
  7954. view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
  7955. view = new wp.media.view.Button( view ).render();
  7956. }
  7957. view.controller = view.controller || this.controller;
  7958. this._views[ id ] = view;
  7959. list = view.options.priority < 0 ? 'secondary' : 'primary';
  7960. this[ list ].set( id, view, options );
  7961. }
  7962. if ( ! options.silent ) {
  7963. this.refresh();
  7964. }
  7965. return this;
  7966. },
  7967. /**
  7968. * @param {string} id
  7969. * @return {wp.media.view.Button}
  7970. */
  7971. get: function( id ) {
  7972. return this._views[ id ];
  7973. },
  7974. /**
  7975. * @param {string} id
  7976. * @param {Object} options
  7977. * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
  7978. */
  7979. unset: function( id, options ) {
  7980. delete this._views[ id ];
  7981. this.primary.unset( id, options );
  7982. this.secondary.unset( id, options );
  7983. if ( ! options || ! options.silent ) {
  7984. this.refresh();
  7985. }
  7986. return this;
  7987. },
  7988. refresh: function() {
  7989. var state = this.controller.state(),
  7990. library = state.get('library'),
  7991. selection = state.get('selection');
  7992. _.each( this._views, function( button ) {
  7993. if ( ! button.model || ! button.options || ! button.options.requires ) {
  7994. return;
  7995. }
  7996. var requires = button.options.requires,
  7997. disabled = false;
  7998. // Prevent insertion of attachments if any of them are still uploading.
  7999. if ( selection && selection.models ) {
  8000. disabled = _.some( selection.models, function( attachment ) {
  8001. return attachment.get('uploading') === true;
  8002. });
  8003. }
  8004. if ( requires.selection && selection && ! selection.length ) {
  8005. disabled = true;
  8006. } else if ( requires.library && library && ! library.length ) {
  8007. disabled = true;
  8008. }
  8009. button.model.set( 'disabled', disabled );
  8010. });
  8011. }
  8012. });
  8013. module.exports = Toolbar;
  8014. /***/ }),
  8015. /***/ 7128:
  8016. /***/ (function(module) {
  8017. var Select = wp.media.view.Toolbar.Select,
  8018. l10n = wp.media.view.l10n,
  8019. Embed;
  8020. /**
  8021. * wp.media.view.Toolbar.Embed
  8022. *
  8023. * @memberOf wp.media.view.Toolbar
  8024. *
  8025. * @class
  8026. * @augments wp.media.view.Toolbar.Select
  8027. * @augments wp.media.view.Toolbar
  8028. * @augments wp.media.View
  8029. * @augments wp.Backbone.View
  8030. * @augments Backbone.View
  8031. */
  8032. Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
  8033. initialize: function() {
  8034. _.defaults( this.options, {
  8035. text: l10n.insertIntoPost,
  8036. requires: false
  8037. });
  8038. // Call 'initialize' directly on the parent class.
  8039. Select.prototype.initialize.apply( this, arguments );
  8040. },
  8041. refresh: function() {
  8042. var url = this.controller.state().props.get('url');
  8043. this.get('select').model.set( 'disabled', ! url || url === 'http://' );
  8044. /**
  8045. * call 'refresh' directly on the parent class
  8046. */
  8047. Select.prototype.refresh.apply( this, arguments );
  8048. }
  8049. });
  8050. module.exports = Embed;
  8051. /***/ }),
  8052. /***/ 6850:
  8053. /***/ (function(module) {
  8054. var Toolbar = wp.media.view.Toolbar,
  8055. l10n = wp.media.view.l10n,
  8056. Select;
  8057. /**
  8058. * wp.media.view.Toolbar.Select
  8059. *
  8060. * @memberOf wp.media.view.Toolbar
  8061. *
  8062. * @class
  8063. * @augments wp.media.view.Toolbar
  8064. * @augments wp.media.View
  8065. * @augments wp.Backbone.View
  8066. * @augments Backbone.View
  8067. */
  8068. Select = Toolbar.extend(/** @lends wp.media.view.Toolbar.Select.prototype */{
  8069. initialize: function() {
  8070. var options = this.options;
  8071. _.bindAll( this, 'clickSelect' );
  8072. _.defaults( options, {
  8073. event: 'select',
  8074. state: false,
  8075. reset: true,
  8076. close: true,
  8077. text: l10n.select,
  8078. // Does the button rely on the selection?
  8079. requires: {
  8080. selection: true
  8081. }
  8082. });
  8083. options.items = _.defaults( options.items || {}, {
  8084. select: {
  8085. style: 'primary',
  8086. text: options.text,
  8087. priority: 80,
  8088. click: this.clickSelect,
  8089. requires: options.requires
  8090. }
  8091. });
  8092. // Call 'initialize' directly on the parent class.
  8093. Toolbar.prototype.initialize.apply( this, arguments );
  8094. },
  8095. clickSelect: function() {
  8096. var options = this.options,
  8097. controller = this.controller;
  8098. if ( options.close ) {
  8099. controller.close();
  8100. }
  8101. if ( options.event ) {
  8102. controller.state().trigger( options.event );
  8103. }
  8104. if ( options.state ) {
  8105. controller.setState( options.state );
  8106. }
  8107. if ( options.reset ) {
  8108. controller.reset();
  8109. }
  8110. }
  8111. });
  8112. module.exports = Select;
  8113. /***/ }),
  8114. /***/ 841:
  8115. /***/ (function(module) {
  8116. var View = wp.media.View,
  8117. l10n = wp.media.view.l10n,
  8118. $ = jQuery,
  8119. EditorUploader;
  8120. /**
  8121. * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
  8122. * and relays drag'n'dropped files to a media workflow.
  8123. *
  8124. * wp.media.view.EditorUploader
  8125. *
  8126. * @memberOf wp.media.view
  8127. *
  8128. * @class
  8129. * @augments wp.media.View
  8130. * @augments wp.Backbone.View
  8131. * @augments Backbone.View
  8132. */
  8133. EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
  8134. tagName: 'div',
  8135. className: 'uploader-editor',
  8136. template: wp.template( 'uploader-editor' ),
  8137. localDrag: false,
  8138. overContainer: false,
  8139. overDropzone: false,
  8140. draggingFile: null,
  8141. /**
  8142. * Bind drag'n'drop events to callbacks.
  8143. */
  8144. initialize: function() {
  8145. this.initialized = false;
  8146. // Bail if not enabled or UA does not support drag'n'drop or File API.
  8147. if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
  8148. return this;
  8149. }
  8150. this.$document = $(document);
  8151. this.dropzones = [];
  8152. this.files = [];
  8153. this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
  8154. this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
  8155. this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
  8156. this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
  8157. this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
  8158. this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
  8159. this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
  8160. this.localDrag = event.type === 'dragstart';
  8161. if ( event.type === 'drop' ) {
  8162. this.containerDragleave();
  8163. }
  8164. }, this ) );
  8165. this.initialized = true;
  8166. return this;
  8167. },
  8168. /**
  8169. * Check browser support for drag'n'drop.
  8170. *
  8171. * @return {boolean}
  8172. */
  8173. browserSupport: function() {
  8174. var supports = false, div = document.createElement('div');
  8175. supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
  8176. supports = supports && !! ( window.File && window.FileList && window.FileReader );
  8177. return supports;
  8178. },
  8179. isDraggingFile: function( event ) {
  8180. if ( this.draggingFile !== null ) {
  8181. return this.draggingFile;
  8182. }
  8183. if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
  8184. return false;
  8185. }
  8186. this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
  8187. _.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
  8188. return this.draggingFile;
  8189. },
  8190. refresh: function( e ) {
  8191. var dropzone_id;
  8192. for ( dropzone_id in this.dropzones ) {
  8193. // Hide the dropzones only if dragging has left the screen.
  8194. this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
  8195. }
  8196. if ( ! _.isUndefined( e ) ) {
  8197. $( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
  8198. }
  8199. if ( ! this.overContainer && ! this.overDropzone ) {
  8200. this.draggingFile = null;
  8201. }
  8202. return this;
  8203. },
  8204. render: function() {
  8205. if ( ! this.initialized ) {
  8206. return this;
  8207. }
  8208. View.prototype.render.apply( this, arguments );
  8209. $( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
  8210. return this;
  8211. },
  8212. attach: function( index, editor ) {
  8213. // Attach a dropzone to an editor.
  8214. var dropzone = this.$el.clone();
  8215. this.dropzones.push( dropzone );
  8216. $( editor ).append( dropzone );
  8217. return this;
  8218. },
  8219. /**
  8220. * When a file is dropped on the editor uploader, open up an editor media workflow
  8221. * and upload the file immediately.
  8222. *
  8223. * @param {jQuery.Event} event The 'drop' event.
  8224. */
  8225. drop: function( event ) {
  8226. var $wrap, uploadView;
  8227. this.containerDragleave( event );
  8228. this.dropzoneDragleave( event );
  8229. this.files = event.originalEvent.dataTransfer.files;
  8230. if ( this.files.length < 1 ) {
  8231. return;
  8232. }
  8233. // Set the active editor to the drop target.
  8234. $wrap = $( event.target ).parents( '.wp-editor-wrap' );
  8235. if ( $wrap.length > 0 && $wrap[0].id ) {
  8236. window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
  8237. }
  8238. if ( ! this.workflow ) {
  8239. this.workflow = wp.media.editor.open( window.wpActiveEditor, {
  8240. frame: 'post',
  8241. state: 'insert',
  8242. title: l10n.addMedia,
  8243. multiple: true
  8244. });
  8245. uploadView = this.workflow.uploader;
  8246. if ( uploadView.uploader && uploadView.uploader.ready ) {
  8247. this.addFiles.apply( this );
  8248. } else {
  8249. this.workflow.on( 'uploader:ready', this.addFiles, this );
  8250. }
  8251. } else {
  8252. this.workflow.state().reset();
  8253. this.addFiles.apply( this );
  8254. this.workflow.open();
  8255. }
  8256. return false;
  8257. },
  8258. /**
  8259. * Add the files to the uploader.
  8260. */
  8261. addFiles: function() {
  8262. if ( this.files.length ) {
  8263. this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
  8264. this.files = [];
  8265. }
  8266. return this;
  8267. },
  8268. containerDragover: function( event ) {
  8269. if ( this.localDrag || ! this.isDraggingFile( event ) ) {
  8270. return;
  8271. }
  8272. this.overContainer = true;
  8273. this.refresh();
  8274. },
  8275. containerDragleave: function() {
  8276. this.overContainer = false;
  8277. // Throttle dragleave because it's called when bouncing from some elements to others.
  8278. _.delay( _.bind( this.refresh, this ), 50 );
  8279. },
  8280. dropzoneDragover: function( event ) {
  8281. if ( this.localDrag || ! this.isDraggingFile( event ) ) {
  8282. return;
  8283. }
  8284. this.overDropzone = true;
  8285. this.refresh( event );
  8286. return false;
  8287. },
  8288. dropzoneDragleave: function( e ) {
  8289. this.overDropzone = false;
  8290. _.delay( _.bind( this.refresh, this, e ), 50 );
  8291. },
  8292. click: function( e ) {
  8293. // In the rare case where the dropzone gets stuck, hide it on click.
  8294. this.containerDragleave( e );
  8295. this.dropzoneDragleave( e );
  8296. this.localDrag = false;
  8297. }
  8298. });
  8299. module.exports = EditorUploader;
  8300. /***/ }),
  8301. /***/ 6353:
  8302. /***/ (function(module) {
  8303. var View = wp.media.View,
  8304. UploaderInline;
  8305. /**
  8306. * wp.media.view.UploaderInline
  8307. *
  8308. * The inline uploader that shows up in the 'Upload Files' tab.
  8309. *
  8310. * @memberOf wp.media.view
  8311. *
  8312. * @class
  8313. * @augments wp.media.View
  8314. * @augments wp.Backbone.View
  8315. * @augments Backbone.View
  8316. */
  8317. UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
  8318. tagName: 'div',
  8319. className: 'uploader-inline',
  8320. template: wp.template('uploader-inline'),
  8321. events: {
  8322. 'click .close': 'hide'
  8323. },
  8324. initialize: function() {
  8325. _.defaults( this.options, {
  8326. message: '',
  8327. status: true,
  8328. canClose: false
  8329. });
  8330. if ( ! this.options.$browser && this.controller.uploader ) {
  8331. this.options.$browser = this.controller.uploader.$browser;
  8332. }
  8333. if ( _.isUndefined( this.options.postId ) ) {
  8334. this.options.postId = wp.media.view.settings.post.id;
  8335. }
  8336. if ( this.options.status ) {
  8337. this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
  8338. controller: this.controller
  8339. }) );
  8340. }
  8341. },
  8342. prepare: function() {
  8343. var suggestedWidth = this.controller.state().get('suggestedWidth'),
  8344. suggestedHeight = this.controller.state().get('suggestedHeight'),
  8345. data = {};
  8346. data.message = this.options.message;
  8347. data.canClose = this.options.canClose;
  8348. if ( suggestedWidth && suggestedHeight ) {
  8349. data.suggestedWidth = suggestedWidth;
  8350. data.suggestedHeight = suggestedHeight;
  8351. }
  8352. return data;
  8353. },
  8354. /**
  8355. * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
  8356. */
  8357. dispose: function() {
  8358. if ( this.disposing ) {
  8359. /**
  8360. * call 'dispose' directly on the parent class
  8361. */
  8362. return View.prototype.dispose.apply( this, arguments );
  8363. }
  8364. /*
  8365. * Run remove on `dispose`, so we can be sure to refresh the
  8366. * uploader with a view-less DOM. Track whether we're disposing
  8367. * so we don't trigger an infinite loop.
  8368. */
  8369. this.disposing = true;
  8370. return this.remove();
  8371. },
  8372. /**
  8373. * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
  8374. */
  8375. remove: function() {
  8376. /**
  8377. * call 'remove' directly on the parent class
  8378. */
  8379. var result = View.prototype.remove.apply( this, arguments );
  8380. _.defer( _.bind( this.refresh, this ) );
  8381. return result;
  8382. },
  8383. refresh: function() {
  8384. var uploader = this.controller.uploader;
  8385. if ( uploader ) {
  8386. uploader.refresh();
  8387. }
  8388. },
  8389. /**
  8390. * @return {wp.media.view.UploaderInline}
  8391. */
  8392. ready: function() {
  8393. var $browser = this.options.$browser,
  8394. $placeholder;
  8395. if ( this.controller.uploader ) {
  8396. $placeholder = this.$('.browser');
  8397. // Check if we've already replaced the placeholder.
  8398. if ( $placeholder[0] === $browser[0] ) {
  8399. return;
  8400. }
  8401. $browser.detach().text( $placeholder.text() );
  8402. $browser[0].className = $placeholder[0].className;
  8403. $browser[0].setAttribute( 'aria-labelledby', $browser[0].id + ' ' + $placeholder[0].getAttribute('aria-labelledby') );
  8404. $placeholder.replaceWith( $browser.show() );
  8405. }
  8406. this.refresh();
  8407. return this;
  8408. },
  8409. show: function() {
  8410. this.$el.removeClass( 'hidden' );
  8411. if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
  8412. this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
  8413. }
  8414. },
  8415. hide: function() {
  8416. this.$el.addClass( 'hidden' );
  8417. if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
  8418. this.controller.$uploaderToggler
  8419. .attr( 'aria-expanded', 'false' )
  8420. // Move focus back to the toggle button when closing the uploader.
  8421. .trigger( 'focus' );
  8422. }
  8423. }
  8424. });
  8425. module.exports = UploaderInline;
  8426. /***/ }),
  8427. /***/ 9411:
  8428. /***/ (function(module) {
  8429. /**
  8430. * wp.media.view.UploaderStatusError
  8431. *
  8432. * @memberOf wp.media.view
  8433. *
  8434. * @class
  8435. * @augments wp.media.View
  8436. * @augments wp.Backbone.View
  8437. * @augments Backbone.View
  8438. */
  8439. var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
  8440. className: 'upload-error',
  8441. template: wp.template('uploader-status-error')
  8442. });
  8443. module.exports = UploaderStatusError;
  8444. /***/ }),
  8445. /***/ 2894:
  8446. /***/ (function(module) {
  8447. var View = wp.media.View,
  8448. UploaderStatus;
  8449. /**
  8450. * wp.media.view.UploaderStatus
  8451. *
  8452. * An uploader status for on-going uploads.
  8453. *
  8454. * @memberOf wp.media.view
  8455. *
  8456. * @class
  8457. * @augments wp.media.View
  8458. * @augments wp.Backbone.View
  8459. * @augments Backbone.View
  8460. */
  8461. UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
  8462. className: 'media-uploader-status',
  8463. template: wp.template('uploader-status'),
  8464. events: {
  8465. 'click .upload-dismiss-errors': 'dismiss'
  8466. },
  8467. initialize: function() {
  8468. this.queue = wp.Uploader.queue;
  8469. this.queue.on( 'add remove reset', this.visibility, this );
  8470. this.queue.on( 'add remove reset change:percent', this.progress, this );
  8471. this.queue.on( 'add remove reset change:uploading', this.info, this );
  8472. this.errors = wp.Uploader.errors;
  8473. this.errors.reset();
  8474. this.errors.on( 'add remove reset', this.visibility, this );
  8475. this.errors.on( 'add', this.error, this );
  8476. },
  8477. /**
  8478. * @return {wp.media.view.UploaderStatus}
  8479. */
  8480. dispose: function() {
  8481. wp.Uploader.queue.off( null, null, this );
  8482. /**
  8483. * call 'dispose' directly on the parent class
  8484. */
  8485. View.prototype.dispose.apply( this, arguments );
  8486. return this;
  8487. },
  8488. visibility: function() {
  8489. this.$el.toggleClass( 'uploading', !! this.queue.length );
  8490. this.$el.toggleClass( 'errors', !! this.errors.length );
  8491. this.$el.toggle( !! this.queue.length || !! this.errors.length );
  8492. },
  8493. ready: function() {
  8494. _.each({
  8495. '$bar': '.media-progress-bar div',
  8496. '$index': '.upload-index',
  8497. '$total': '.upload-total',
  8498. '$filename': '.upload-filename'
  8499. }, function( selector, key ) {
  8500. this[ key ] = this.$( selector );
  8501. }, this );
  8502. this.visibility();
  8503. this.progress();
  8504. this.info();
  8505. },
  8506. progress: function() {
  8507. var queue = this.queue,
  8508. $bar = this.$bar;
  8509. if ( ! $bar || ! queue.length ) {
  8510. return;
  8511. }
  8512. $bar.width( ( queue.reduce( function( memo, attachment ) {
  8513. if ( ! attachment.get('uploading') ) {
  8514. return memo + 100;
  8515. }
  8516. var percent = attachment.get('percent');
  8517. return memo + ( _.isNumber( percent ) ? percent : 100 );
  8518. }, 0 ) / queue.length ) + '%' );
  8519. },
  8520. info: function() {
  8521. var queue = this.queue,
  8522. index = 0, active;
  8523. if ( ! queue.length ) {
  8524. return;
  8525. }
  8526. active = this.queue.find( function( attachment, i ) {
  8527. index = i;
  8528. return attachment.get('uploading');
  8529. });
  8530. if ( this.$index && this.$total && this.$filename ) {
  8531. this.$index.text( index + 1 );
  8532. this.$total.text( queue.length );
  8533. this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
  8534. }
  8535. },
  8536. /**
  8537. * @param {string} filename
  8538. * @return {string}
  8539. */
  8540. filename: function( filename ) {
  8541. return _.escape( filename );
  8542. },
  8543. /**
  8544. * @param {Backbone.Model} error
  8545. */
  8546. error: function( error ) {
  8547. var statusError = new wp.media.view.UploaderStatusError( {
  8548. filename: this.filename( error.get( 'file' ).name ),
  8549. message: error.get( 'message' )
  8550. } );
  8551. var buttonClose = this.$el.find( 'button' );
  8552. // Can show additional info here while retrying to create image sub-sizes.
  8553. this.views.add( '.upload-errors', statusError, { at: 0 } );
  8554. _.delay( function() {
  8555. buttonClose.trigger( 'focus' );
  8556. wp.a11y.speak( error.get( 'message' ), 'assertive' );
  8557. }, 1000 );
  8558. },
  8559. dismiss: function() {
  8560. var errors = this.views.get('.upload-errors');
  8561. if ( errors ) {
  8562. _.invoke( errors, 'remove' );
  8563. }
  8564. wp.Uploader.errors.reset();
  8565. // Move focus to the modal after the dismiss button gets removed from the DOM.
  8566. if ( this.controller.modal ) {
  8567. this.controller.modal.focusManager.focus();
  8568. }
  8569. }
  8570. });
  8571. module.exports = UploaderStatus;
  8572. /***/ }),
  8573. /***/ 5823:
  8574. /***/ (function(module) {
  8575. var $ = jQuery,
  8576. UploaderWindow;
  8577. /**
  8578. * wp.media.view.UploaderWindow
  8579. *
  8580. * An uploader window that allows for dragging and dropping media.
  8581. *
  8582. * @memberOf wp.media.view
  8583. *
  8584. * @class
  8585. * @augments wp.media.View
  8586. * @augments wp.Backbone.View
  8587. * @augments Backbone.View
  8588. *
  8589. * @param {object} [options] Options hash passed to the view.
  8590. * @param {object} [options.uploader] Uploader properties.
  8591. * @param {jQuery} [options.uploader.browser]
  8592. * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
  8593. * @param {object} [options.uploader.params]
  8594. */
  8595. UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
  8596. tagName: 'div',
  8597. className: 'uploader-window',
  8598. template: wp.template('uploader-window'),
  8599. initialize: function() {
  8600. var uploader;
  8601. this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
  8602. uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
  8603. dropzone: this.$el,
  8604. browser: this.$browser,
  8605. params: {}
  8606. });
  8607. // Ensure the dropzone is a jQuery collection.
  8608. if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
  8609. uploader.dropzone = $( uploader.dropzone );
  8610. }
  8611. this.controller.on( 'activate', this.refresh, this );
  8612. this.controller.on( 'detach', function() {
  8613. this.$browser.remove();
  8614. }, this );
  8615. },
  8616. refresh: function() {
  8617. if ( this.uploader ) {
  8618. this.uploader.refresh();
  8619. }
  8620. },
  8621. ready: function() {
  8622. var postId = wp.media.view.settings.post.id,
  8623. dropzone;
  8624. // If the uploader already exists, bail.
  8625. if ( this.uploader ) {
  8626. return;
  8627. }
  8628. if ( postId ) {
  8629. this.options.uploader.params.post_id = postId;
  8630. }
  8631. this.uploader = new wp.Uploader( this.options.uploader );
  8632. dropzone = this.uploader.dropzone;
  8633. dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
  8634. dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
  8635. $( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
  8636. },
  8637. _ready: function() {
  8638. this.controller.trigger( 'uploader:ready' );
  8639. },
  8640. show: function() {
  8641. var $el = this.$el.show();
  8642. // Ensure that the animation is triggered by waiting until
  8643. // the transparent element is painted into the DOM.
  8644. _.defer( function() {
  8645. $el.css({ opacity: 1 });
  8646. });
  8647. },
  8648. hide: function() {
  8649. var $el = this.$el.css({ opacity: 0 });
  8650. wp.media.transition( $el ).done( function() {
  8651. // Transition end events are subject to race conditions.
  8652. // Make sure that the value is set as intended.
  8653. if ( '0' === $el.css('opacity') ) {
  8654. $el.hide();
  8655. }
  8656. });
  8657. // https://core.trac.wordpress.org/ticket/27341
  8658. _.delay( function() {
  8659. if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
  8660. $el.hide();
  8661. }
  8662. }, 500 );
  8663. }
  8664. });
  8665. module.exports = UploaderWindow;
  8666. /***/ }),
  8667. /***/ 487:
  8668. /***/ (function(module) {
  8669. /**
  8670. * wp.media.View
  8671. *
  8672. * The base view class for media.
  8673. *
  8674. * Undelegating events, removing events from the model, and
  8675. * removing events from the controller mirror the code for
  8676. * `Backbone.View.dispose` in Backbone 0.9.8 development.
  8677. *
  8678. * This behavior has since been removed, and should not be used
  8679. * outside of the media manager.
  8680. *
  8681. * @memberOf wp.media
  8682. *
  8683. * @class
  8684. * @augments wp.Backbone.View
  8685. * @augments Backbone.View
  8686. */
  8687. var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
  8688. constructor: function( options ) {
  8689. if ( options && options.controller ) {
  8690. this.controller = options.controller;
  8691. }
  8692. wp.Backbone.View.apply( this, arguments );
  8693. },
  8694. /**
  8695. * @todo The internal comment mentions this might have been a stop-gap
  8696. * before Backbone 0.9.8 came out. Figure out if Backbone core takes
  8697. * care of this in Backbone.View now.
  8698. *
  8699. * @return {wp.media.View} Returns itself to allow chaining.
  8700. */
  8701. dispose: function() {
  8702. /*
  8703. * Undelegating events, removing events from the model, and
  8704. * removing events from the controller mirror the code for
  8705. * `Backbone.View.dispose` in Backbone 0.9.8 development.
  8706. */
  8707. this.undelegateEvents();
  8708. if ( this.model && this.model.off ) {
  8709. this.model.off( null, null, this );
  8710. }
  8711. if ( this.collection && this.collection.off ) {
  8712. this.collection.off( null, null, this );
  8713. }
  8714. // Unbind controller events.
  8715. if ( this.controller && this.controller.off ) {
  8716. this.controller.off( null, null, this );
  8717. }
  8718. return this;
  8719. },
  8720. /**
  8721. * @return {wp.media.View} Returns itself to allow chaining.
  8722. */
  8723. remove: function() {
  8724. this.dispose();
  8725. /**
  8726. * call 'remove' directly on the parent class
  8727. */
  8728. return wp.Backbone.View.prototype.remove.apply( this, arguments );
  8729. }
  8730. });
  8731. module.exports = View;
  8732. /***/ })
  8733. /******/ });
  8734. /************************************************************************/
  8735. /******/ // The module cache
  8736. /******/ var __webpack_module_cache__ = {};
  8737. /******/
  8738. /******/ // The require function
  8739. /******/ function __webpack_require__(moduleId) {
  8740. /******/ // Check if module is in cache
  8741. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  8742. /******/ if (cachedModule !== undefined) {
  8743. /******/ return cachedModule.exports;
  8744. /******/ }
  8745. /******/ // Create a new module (and put it into the cache)
  8746. /******/ var module = __webpack_module_cache__[moduleId] = {
  8747. /******/ // no module.id needed
  8748. /******/ // no module.loaded needed
  8749. /******/ exports: {}
  8750. /******/ };
  8751. /******/
  8752. /******/ // Execute the module function
  8753. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  8754. /******/
  8755. /******/ // Return the exports of the module
  8756. /******/ return module.exports;
  8757. /******/ }
  8758. /******/
  8759. /************************************************************************/
  8760. var __webpack_exports__ = {};
  8761. // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
  8762. !function() {
  8763. /**
  8764. * @output wp-includes/js/media-views.js
  8765. */
  8766. var media = wp.media,
  8767. $ = jQuery,
  8768. l10n;
  8769. media.isTouchDevice = ( 'ontouchend' in document );
  8770. // Link any localized strings.
  8771. l10n = media.view.l10n = window._wpMediaViewsL10n || {};
  8772. // Link any settings.
  8773. media.view.settings = l10n.settings || {};
  8774. delete l10n.settings;
  8775. // Copy the `post` setting over to the model settings.
  8776. media.model.settings.post = media.view.settings.post;
  8777. // Check if the browser supports CSS 3.0 transitions.
  8778. $.support.transition = (function(){
  8779. var style = document.documentElement.style,
  8780. transitions = {
  8781. WebkitTransition: 'webkitTransitionEnd',
  8782. MozTransition: 'transitionend',
  8783. OTransition: 'oTransitionEnd otransitionend',
  8784. transition: 'transitionend'
  8785. }, transition;
  8786. transition = _.find( _.keys( transitions ), function( transition ) {
  8787. return ! _.isUndefined( style[ transition ] );
  8788. });
  8789. return transition && {
  8790. end: transitions[ transition ]
  8791. };
  8792. }());
  8793. /**
  8794. * A shared event bus used to provide events into
  8795. * the media workflows that 3rd-party devs can use to hook
  8796. * in.
  8797. */
  8798. media.events = _.extend( {}, Backbone.Events );
  8799. /**
  8800. * Makes it easier to bind events using transitions.
  8801. *
  8802. * @param {string} selector
  8803. * @param {number} sensitivity
  8804. * @return {Promise}
  8805. */
  8806. media.transition = function( selector, sensitivity ) {
  8807. var deferred = $.Deferred();
  8808. sensitivity = sensitivity || 2000;
  8809. if ( $.support.transition ) {
  8810. if ( ! (selector instanceof $) ) {
  8811. selector = $( selector );
  8812. }
  8813. // Resolve the deferred when the first element finishes animating.
  8814. selector.first().one( $.support.transition.end, deferred.resolve );
  8815. // Just in case the event doesn't trigger, fire a callback.
  8816. _.delay( deferred.resolve, sensitivity );
  8817. // Otherwise, execute on the spot.
  8818. } else {
  8819. deferred.resolve();
  8820. }
  8821. return deferred.promise();
  8822. };
  8823. media.controller.Region = __webpack_require__( 4903 );
  8824. media.controller.StateMachine = __webpack_require__( 5466 );
  8825. media.controller.State = __webpack_require__( 5826 );
  8826. media.selectionSync = __webpack_require__( 3526 );
  8827. media.controller.Library = __webpack_require__( 9024 );
  8828. media.controller.ImageDetails = __webpack_require__( 3849 );
  8829. media.controller.GalleryEdit = __webpack_require__( 6328 );
  8830. media.controller.GalleryAdd = __webpack_require__( 7323 );
  8831. media.controller.CollectionEdit = __webpack_require__( 1817 );
  8832. media.controller.CollectionAdd = __webpack_require__( 1517 );
  8833. media.controller.FeaturedImage = __webpack_require__( 5095 );
  8834. media.controller.ReplaceImage = __webpack_require__( 8493 );
  8835. media.controller.EditImage = __webpack_require__( 7658 );
  8836. media.controller.MediaLibrary = __webpack_require__( 3742 );
  8837. media.controller.Embed = __webpack_require__( 9067 );
  8838. media.controller.Cropper = __webpack_require__( 2288 );
  8839. media.controller.CustomizeImageCropper = __webpack_require__( 6934 );
  8840. media.controller.SiteIconCropper = __webpack_require__( 5274 );
  8841. media.View = __webpack_require__( 487 );
  8842. media.view.Frame = __webpack_require__( 3647 );
  8843. media.view.MediaFrame = __webpack_require__( 4861 );
  8844. media.view.MediaFrame.Select = __webpack_require__( 8719 );
  8845. media.view.MediaFrame.Post = __webpack_require__( 9075 );
  8846. media.view.MediaFrame.ImageDetails = __webpack_require__( 9142 );
  8847. media.view.Modal = __webpack_require__( 3939 );
  8848. media.view.FocusManager = __webpack_require__( 6557 );
  8849. media.view.UploaderWindow = __webpack_require__( 5823 );
  8850. media.view.EditorUploader = __webpack_require__( 841 );
  8851. media.view.UploaderInline = __webpack_require__( 6353 );
  8852. media.view.UploaderStatus = __webpack_require__( 2894 );
  8853. media.view.UploaderStatusError = __webpack_require__( 9411 );
  8854. media.view.Toolbar = __webpack_require__( 9510 );
  8855. media.view.Toolbar.Select = __webpack_require__( 6850 );
  8856. media.view.Toolbar.Embed = __webpack_require__( 7128 );
  8857. media.view.Button = __webpack_require__( 3157 );
  8858. media.view.ButtonGroup = __webpack_require__( 4094 );
  8859. media.view.PriorityList = __webpack_require__( 1993 );
  8860. media.view.MenuItem = __webpack_require__( 917 );
  8861. media.view.Menu = __webpack_require__( 2596 );
  8862. media.view.RouterItem = __webpack_require__( 9484 );
  8863. media.view.Router = __webpack_require__( 1562 );
  8864. media.view.Sidebar = __webpack_require__( 9799 );
  8865. media.view.Attachment = __webpack_require__( 5019 );
  8866. media.view.Attachment.Library = __webpack_require__( 9254 );
  8867. media.view.Attachment.EditLibrary = __webpack_require__( 4640 );
  8868. media.view.Attachments = __webpack_require__( 8408 );
  8869. media.view.Search = __webpack_require__( 4556 );
  8870. media.view.AttachmentFilters = __webpack_require__( 4906 );
  8871. media.view.DateFilter = __webpack_require__( 9663 );
  8872. media.view.AttachmentFilters.Uploaded = __webpack_require__( 7040 );
  8873. media.view.AttachmentFilters.All = __webpack_require__( 2868 );
  8874. media.view.AttachmentsBrowser = __webpack_require__( 9239 );
  8875. media.view.Selection = __webpack_require__( 6191 );
  8876. media.view.Attachment.Selection = __webpack_require__( 9003 );
  8877. media.view.Attachments.Selection = __webpack_require__( 1223 );
  8878. media.view.Attachment.EditSelection = __webpack_require__( 1009 );
  8879. media.view.Settings = __webpack_require__( 859 );
  8880. media.view.Settings.AttachmentDisplay = __webpack_require__( 2176 );
  8881. media.view.Settings.Gallery = __webpack_require__( 6872 );
  8882. media.view.Settings.Playlist = __webpack_require__( 8488 );
  8883. media.view.Attachment.Details = __webpack_require__( 7274 );
  8884. media.view.AttachmentCompat = __webpack_require__( 8093 );
  8885. media.view.Iframe = __webpack_require__( 6217 );
  8886. media.view.Embed = __webpack_require__( 5138 );
  8887. media.view.Label = __webpack_require__( 6644 );
  8888. media.view.EmbedUrl = __webpack_require__( 4848 );
  8889. media.view.EmbedLink = __webpack_require__( 6959 );
  8890. media.view.EmbedImage = __webpack_require__( 1338 );
  8891. media.view.ImageDetails = __webpack_require__( 7598 );
  8892. media.view.Cropper = __webpack_require__( 7137 );
  8893. media.view.SiteIconCropper = __webpack_require__( 5187 );
  8894. media.view.SiteIconPreview = __webpack_require__( 8260 );
  8895. media.view.EditImage = __webpack_require__( 5970 );
  8896. media.view.Spinner = __webpack_require__( 2234 );
  8897. media.view.Heading = __webpack_require__( 7990 );
  8898. }();
  8899. /******/ })()
  8900. ;