media-views.js 265 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496
  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. if ( this.model.get( 'url' ) ) {
  4855. this.input.value = this.model.get('url');
  4856. } else {
  4857. this.input.setAttribute( 'placeholder', 'https://' );
  4858. }
  4859. /**
  4860. * Call `render` directly on parent class with passed arguments
  4861. */
  4862. View.prototype.render.apply( this, arguments );
  4863. return this;
  4864. },
  4865. url: function( event ) {
  4866. var url = event.target.value || '';
  4867. this.model.set( 'url', url.trim() );
  4868. }
  4869. });
  4870. module.exports = EmbedUrl;
  4871. /***/ }),
  4872. /***/ 6557:
  4873. /***/ (function(module) {
  4874. var $ = jQuery;
  4875. /**
  4876. * wp.media.view.FocusManager
  4877. *
  4878. * @memberOf wp.media.view
  4879. *
  4880. * @class
  4881. * @augments wp.media.View
  4882. * @augments wp.Backbone.View
  4883. * @augments Backbone.View
  4884. */
  4885. var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
  4886. events: {
  4887. 'keydown': 'focusManagementMode'
  4888. },
  4889. /**
  4890. * Initializes the Focus Manager.
  4891. *
  4892. * @param {Object} options The Focus Manager options.
  4893. *
  4894. * @since 5.3.0
  4895. *
  4896. * @return {void}
  4897. */
  4898. initialize: function( options ) {
  4899. this.mode = options.mode || 'constrainTabbing';
  4900. this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
  4901. },
  4902. /**
  4903. * Determines which focus management mode to use.
  4904. *
  4905. * @since 5.3.0
  4906. *
  4907. * @param {Object} event jQuery event object.
  4908. *
  4909. * @return {void}
  4910. */
  4911. focusManagementMode: function( event ) {
  4912. if ( this.mode === 'constrainTabbing' ) {
  4913. this.constrainTabbing( event );
  4914. }
  4915. if ( this.mode === 'tabsNavigation' ) {
  4916. this.tabsNavigation( event );
  4917. }
  4918. },
  4919. /**
  4920. * Gets all the tabbable elements.
  4921. *
  4922. * @since 5.3.0
  4923. *
  4924. * @return {Object} A jQuery collection of tabbable elements.
  4925. */
  4926. getTabbables: function() {
  4927. // Skip the file input added by Plupload.
  4928. return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
  4929. },
  4930. /**
  4931. * Moves focus to the modal dialog.
  4932. *
  4933. * @since 3.5.0
  4934. *
  4935. * @return {void}
  4936. */
  4937. focus: function() {
  4938. this.$( '.media-modal' ).trigger( 'focus' );
  4939. },
  4940. /**
  4941. * Constrains navigation with the Tab key within the media view element.
  4942. *
  4943. * @since 4.0.0
  4944. *
  4945. * @param {Object} event A keydown jQuery event.
  4946. *
  4947. * @return {void}
  4948. */
  4949. constrainTabbing: function( event ) {
  4950. var tabbables;
  4951. // Look for the tab key.
  4952. if ( 9 !== event.keyCode ) {
  4953. return;
  4954. }
  4955. tabbables = this.getTabbables();
  4956. // Keep tab focus within media modal while it's open.
  4957. if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
  4958. tabbables.first().focus();
  4959. return false;
  4960. } else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
  4961. tabbables.last().focus();
  4962. return false;
  4963. }
  4964. },
  4965. /**
  4966. * Hides from assistive technologies all the body children.
  4967. *
  4968. * Sets an `aria-hidden="true"` attribute on all the body children except
  4969. * the provided element and other elements that should not be hidden.
  4970. *
  4971. * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
  4972. * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
  4973. * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
  4974. * of the modal dialog and get hidden from assistive technologies.
  4975. *
  4976. * @since 5.2.3
  4977. *
  4978. * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
  4979. *
  4980. * @return {void}
  4981. */
  4982. setAriaHiddenOnBodyChildren: function( visibleElement ) {
  4983. var bodyChildren,
  4984. self = this;
  4985. if ( this.isBodyAriaHidden ) {
  4986. return;
  4987. }
  4988. // Get all the body children.
  4989. bodyChildren = document.body.children;
  4990. // Loop through the body children and hide the ones that should be hidden.
  4991. _.each( bodyChildren, function( element ) {
  4992. // Don't hide the modal element.
  4993. if ( element === visibleElement[0] ) {
  4994. return;
  4995. }
  4996. // Determine the body children to hide.
  4997. if ( self.elementShouldBeHidden( element ) ) {
  4998. element.setAttribute( 'aria-hidden', 'true' );
  4999. // Store the hidden elements.
  5000. self.ariaHiddenElements.push( element );
  5001. }
  5002. } );
  5003. this.isBodyAriaHidden = true;
  5004. },
  5005. /**
  5006. * Unhides from assistive technologies all the body children.
  5007. *
  5008. * Makes visible again to assistive technologies all the body children
  5009. * previously hidden and stored in this.ariaHiddenElements.
  5010. *
  5011. * @since 5.2.3
  5012. *
  5013. * @return {void}
  5014. */
  5015. removeAriaHiddenFromBodyChildren: function() {
  5016. _.each( this.ariaHiddenElements, function( element ) {
  5017. element.removeAttribute( 'aria-hidden' );
  5018. } );
  5019. this.ariaHiddenElements = [];
  5020. this.isBodyAriaHidden = false;
  5021. },
  5022. /**
  5023. * Determines if the passed element should not be hidden from assistive technologies.
  5024. *
  5025. * @since 5.2.3
  5026. *
  5027. * @param {Object} element The DOM element that should be checked.
  5028. *
  5029. * @return {boolean} Whether the element should not be hidden from assistive technologies.
  5030. */
  5031. elementShouldBeHidden: function( element ) {
  5032. var role = element.getAttribute( 'role' ),
  5033. liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
  5034. /*
  5035. * Don't hide scripts, elements that already have `aria-hidden`, and
  5036. * ARIA live regions.
  5037. */
  5038. return ! (
  5039. element.tagName === 'SCRIPT' ||
  5040. element.hasAttribute( 'aria-hidden' ) ||
  5041. element.hasAttribute( 'aria-live' ) ||
  5042. liveRegionsRoles.indexOf( role ) !== -1
  5043. );
  5044. },
  5045. /**
  5046. * Whether the body children are hidden from assistive technologies.
  5047. *
  5048. * @since 5.2.3
  5049. */
  5050. isBodyAriaHidden: false,
  5051. /**
  5052. * Stores an array of DOM elements that should be hidden from assistive
  5053. * technologies, for example when the media modal dialog opens.
  5054. *
  5055. * @since 5.2.3
  5056. */
  5057. ariaHiddenElements: [],
  5058. /**
  5059. * Holds the jQuery collection of ARIA tabs.
  5060. *
  5061. * @since 5.3.0
  5062. */
  5063. tabs: $(),
  5064. /**
  5065. * Sets up tabs in an ARIA tabbed interface.
  5066. *
  5067. * @since 5.3.0
  5068. *
  5069. * @param {Object} event jQuery event object.
  5070. *
  5071. * @return {void}
  5072. */
  5073. setupAriaTabs: function() {
  5074. this.tabs = this.$( '[role="tab"]' );
  5075. // Set up initial attributes.
  5076. this.tabs.attr( {
  5077. 'aria-selected': 'false',
  5078. tabIndex: '-1'
  5079. } );
  5080. // Set up attributes on the initially active tab.
  5081. this.tabs.filter( '.active' )
  5082. .removeAttr( 'tabindex' )
  5083. .attr( 'aria-selected', 'true' );
  5084. },
  5085. /**
  5086. * Enables arrows navigation within the ARIA tabbed interface.
  5087. *
  5088. * @since 5.3.0
  5089. *
  5090. * @param {Object} event jQuery event object.
  5091. *
  5092. * @return {void}
  5093. */
  5094. tabsNavigation: function( event ) {
  5095. var orientation = 'horizontal',
  5096. keys = [ 32, 35, 36, 37, 38, 39, 40 ];
  5097. // Return if not Spacebar, End, Home, or Arrow keys.
  5098. if ( keys.indexOf( event.which ) === -1 ) {
  5099. return;
  5100. }
  5101. // Determine navigation direction.
  5102. if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
  5103. orientation = 'vertical';
  5104. }
  5105. // Make Up and Down arrow keys do nothing with horizontal tabs.
  5106. if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
  5107. return;
  5108. }
  5109. // Make Left and Right arrow keys do nothing with vertical tabs.
  5110. if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
  5111. return;
  5112. }
  5113. this.switchTabs( event, this.tabs );
  5114. },
  5115. /**
  5116. * Switches tabs in the ARIA tabbed interface.
  5117. *
  5118. * @since 5.3.0
  5119. *
  5120. * @param {Object} event jQuery event object.
  5121. *
  5122. * @return {void}
  5123. */
  5124. switchTabs: function( event ) {
  5125. var key = event.which,
  5126. index = this.tabs.index( $( event.target ) ),
  5127. newIndex;
  5128. switch ( key ) {
  5129. // Space bar: Activate current targeted tab.
  5130. case 32: {
  5131. this.activateTab( this.tabs[ index ] );
  5132. break;
  5133. }
  5134. // End key: Activate last tab.
  5135. case 35: {
  5136. event.preventDefault();
  5137. this.activateTab( this.tabs[ this.tabs.length - 1 ] );
  5138. break;
  5139. }
  5140. // Home key: Activate first tab.
  5141. case 36: {
  5142. event.preventDefault();
  5143. this.activateTab( this.tabs[ 0 ] );
  5144. break;
  5145. }
  5146. // Left and up keys: Activate previous tab.
  5147. case 37:
  5148. case 38: {
  5149. event.preventDefault();
  5150. newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
  5151. this.activateTab( this.tabs[ newIndex ] );
  5152. break;
  5153. }
  5154. // Right and down keys: Activate next tab.
  5155. case 39:
  5156. case 40: {
  5157. event.preventDefault();
  5158. newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
  5159. this.activateTab( this.tabs[ newIndex ] );
  5160. break;
  5161. }
  5162. }
  5163. },
  5164. /**
  5165. * Sets a single tab to be focusable and semantically selected.
  5166. *
  5167. * @since 5.3.0
  5168. *
  5169. * @param {Object} tab The tab DOM element.
  5170. *
  5171. * @return {void}
  5172. */
  5173. activateTab: function( tab ) {
  5174. if ( ! tab ) {
  5175. return;
  5176. }
  5177. // The tab is a DOM element: no need for jQuery methods.
  5178. tab.focus();
  5179. // Handle automatic activation.
  5180. if ( this.tabsAutomaticActivation ) {
  5181. tab.removeAttribute( 'tabindex' );
  5182. tab.setAttribute( 'aria-selected', 'true' );
  5183. tab.click();
  5184. return;
  5185. }
  5186. // Handle manual activation.
  5187. $( tab ).on( 'click', function() {
  5188. tab.removeAttribute( 'tabindex' );
  5189. tab.setAttribute( 'aria-selected', 'true' );
  5190. } );
  5191. }
  5192. });
  5193. module.exports = FocusManager;
  5194. /***/ }),
  5195. /***/ 3647:
  5196. /***/ (function(module) {
  5197. /**
  5198. * wp.media.view.Frame
  5199. *
  5200. * A frame is a composite view consisting of one or more regions and one or more
  5201. * states.
  5202. *
  5203. * @memberOf wp.media.view
  5204. *
  5205. * @see wp.media.controller.State
  5206. * @see wp.media.controller.Region
  5207. *
  5208. * @class
  5209. * @augments wp.media.View
  5210. * @augments wp.Backbone.View
  5211. * @augments Backbone.View
  5212. * @mixes wp.media.controller.StateMachine
  5213. */
  5214. var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
  5215. initialize: function() {
  5216. _.defaults( this.options, {
  5217. mode: [ 'select' ]
  5218. });
  5219. this._createRegions();
  5220. this._createStates();
  5221. this._createModes();
  5222. },
  5223. _createRegions: function() {
  5224. // Clone the regions array.
  5225. this.regions = this.regions ? this.regions.slice() : [];
  5226. // Initialize regions.
  5227. _.each( this.regions, function( region ) {
  5228. this[ region ] = new wp.media.controller.Region({
  5229. view: this,
  5230. id: region,
  5231. selector: '.media-frame-' + region
  5232. });
  5233. }, this );
  5234. },
  5235. /**
  5236. * Create the frame's states.
  5237. *
  5238. * @see wp.media.controller.State
  5239. * @see wp.media.controller.StateMachine
  5240. *
  5241. * @fires wp.media.controller.State#ready
  5242. */
  5243. _createStates: function() {
  5244. // Create the default `states` collection.
  5245. this.states = new Backbone.Collection( null, {
  5246. model: wp.media.controller.State
  5247. });
  5248. // Ensure states have a reference to the frame.
  5249. this.states.on( 'add', function( model ) {
  5250. model.frame = this;
  5251. model.trigger('ready');
  5252. }, this );
  5253. if ( this.options.states ) {
  5254. this.states.add( this.options.states );
  5255. }
  5256. },
  5257. /**
  5258. * A frame can be in a mode or multiple modes at one time.
  5259. *
  5260. * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
  5261. */
  5262. _createModes: function() {
  5263. // Store active "modes" that the frame is in. Unrelated to region modes.
  5264. this.activeModes = new Backbone.Collection();
  5265. this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
  5266. _.each( this.options.mode, function( mode ) {
  5267. this.activateMode( mode );
  5268. }, this );
  5269. },
  5270. /**
  5271. * Reset all states on the frame to their defaults.
  5272. *
  5273. * @return {wp.media.view.Frame} Returns itself to allow chaining.
  5274. */
  5275. reset: function() {
  5276. this.states.invoke( 'trigger', 'reset' );
  5277. return this;
  5278. },
  5279. /**
  5280. * Map activeMode collection events to the frame.
  5281. */
  5282. triggerModeEvents: function( model, collection, options ) {
  5283. var collectionEvent,
  5284. modeEventMap = {
  5285. add: 'activate',
  5286. remove: 'deactivate'
  5287. },
  5288. eventToTrigger;
  5289. // Probably a better way to do this.
  5290. _.each( options, function( value, key ) {
  5291. if ( value ) {
  5292. collectionEvent = key;
  5293. }
  5294. } );
  5295. if ( ! _.has( modeEventMap, collectionEvent ) ) {
  5296. return;
  5297. }
  5298. eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
  5299. this.trigger( eventToTrigger );
  5300. },
  5301. /**
  5302. * Activate a mode on the frame.
  5303. *
  5304. * @param string mode Mode ID.
  5305. * @return {this} Returns itself to allow chaining.
  5306. */
  5307. activateMode: function( mode ) {
  5308. // Bail if the mode is already active.
  5309. if ( this.isModeActive( mode ) ) {
  5310. return;
  5311. }
  5312. this.activeModes.add( [ { id: mode } ] );
  5313. // Add a CSS class to the frame so elements can be styled for the mode.
  5314. this.$el.addClass( 'mode-' + mode );
  5315. return this;
  5316. },
  5317. /**
  5318. * Deactivate a mode on the frame.
  5319. *
  5320. * @param string mode Mode ID.
  5321. * @return {this} Returns itself to allow chaining.
  5322. */
  5323. deactivateMode: function( mode ) {
  5324. // Bail if the mode isn't active.
  5325. if ( ! this.isModeActive( mode ) ) {
  5326. return this;
  5327. }
  5328. this.activeModes.remove( this.activeModes.where( { id: mode } ) );
  5329. this.$el.removeClass( 'mode-' + mode );
  5330. /**
  5331. * Frame mode deactivation event.
  5332. *
  5333. * @event wp.media.view.Frame#{mode}:deactivate
  5334. */
  5335. this.trigger( mode + ':deactivate' );
  5336. return this;
  5337. },
  5338. /**
  5339. * Check if a mode is enabled on the frame.
  5340. *
  5341. * @param string mode Mode ID.
  5342. * @return bool
  5343. */
  5344. isModeActive: function( mode ) {
  5345. return Boolean( this.activeModes.where( { id: mode } ).length );
  5346. }
  5347. });
  5348. // Make the `Frame` a `StateMachine`.
  5349. _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
  5350. module.exports = Frame;
  5351. /***/ }),
  5352. /***/ 9142:
  5353. /***/ (function(module) {
  5354. var Select = wp.media.view.MediaFrame.Select,
  5355. l10n = wp.media.view.l10n,
  5356. ImageDetails;
  5357. /**
  5358. * wp.media.view.MediaFrame.ImageDetails
  5359. *
  5360. * A media frame for manipulating an image that's already been inserted
  5361. * into a post.
  5362. *
  5363. * @memberOf wp.media.view.MediaFrame
  5364. *
  5365. * @class
  5366. * @augments wp.media.view.MediaFrame.Select
  5367. * @augments wp.media.view.MediaFrame
  5368. * @augments wp.media.view.Frame
  5369. * @augments wp.media.View
  5370. * @augments wp.Backbone.View
  5371. * @augments Backbone.View
  5372. * @mixes wp.media.controller.StateMachine
  5373. */
  5374. ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
  5375. defaults: {
  5376. id: 'image',
  5377. url: '',
  5378. menu: 'image-details',
  5379. content: 'image-details',
  5380. toolbar: 'image-details',
  5381. type: 'link',
  5382. title: l10n.imageDetailsTitle,
  5383. priority: 120
  5384. },
  5385. initialize: function( options ) {
  5386. this.image = new wp.media.model.PostImage( options.metadata );
  5387. this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
  5388. Select.prototype.initialize.apply( this, arguments );
  5389. },
  5390. bindHandlers: function() {
  5391. Select.prototype.bindHandlers.apply( this, arguments );
  5392. this.on( 'menu:create:image-details', this.createMenu, this );
  5393. this.on( 'content:create:image-details', this.imageDetailsContent, this );
  5394. this.on( 'content:render:edit-image', this.editImageContent, this );
  5395. this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
  5396. // Override the select toolbar.
  5397. this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
  5398. },
  5399. createStates: function() {
  5400. this.states.add([
  5401. new wp.media.controller.ImageDetails({
  5402. image: this.image,
  5403. editable: false
  5404. }),
  5405. new wp.media.controller.ReplaceImage({
  5406. id: 'replace-image',
  5407. library: wp.media.query( { type: 'image' } ),
  5408. image: this.image,
  5409. multiple: false,
  5410. title: l10n.imageReplaceTitle,
  5411. toolbar: 'replace',
  5412. priority: 80,
  5413. displaySettings: true
  5414. }),
  5415. new wp.media.controller.EditImage( {
  5416. image: this.image,
  5417. selection: this.options.selection
  5418. } )
  5419. ]);
  5420. },
  5421. imageDetailsContent: function( options ) {
  5422. options.view = new wp.media.view.ImageDetails({
  5423. controller: this,
  5424. model: this.state().image,
  5425. attachment: this.state().image.attachment
  5426. });
  5427. },
  5428. editImageContent: function() {
  5429. var state = this.state(),
  5430. model = state.get('image'),
  5431. view;
  5432. if ( ! model ) {
  5433. return;
  5434. }
  5435. view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
  5436. this.content.set( view );
  5437. // After bringing in the frame, load the actual editor via an Ajax call.
  5438. view.loadEditor();
  5439. },
  5440. renderImageDetailsToolbar: function() {
  5441. this.toolbar.set( new wp.media.view.Toolbar({
  5442. controller: this,
  5443. items: {
  5444. select: {
  5445. style: 'primary',
  5446. text: l10n.update,
  5447. priority: 80,
  5448. click: function() {
  5449. var controller = this.controller,
  5450. state = controller.state();
  5451. controller.close();
  5452. // Not sure if we want to use wp.media.string.image which will create a shortcode or
  5453. // perhaps wp.html.string to at least to build the <img />.
  5454. state.trigger( 'update', controller.image.toJSON() );
  5455. // Restore and reset the default state.
  5456. controller.setState( controller.options.state );
  5457. controller.reset();
  5458. }
  5459. }
  5460. }
  5461. }) );
  5462. },
  5463. renderReplaceImageToolbar: function() {
  5464. var frame = this,
  5465. lastState = frame.lastState(),
  5466. previous = lastState && lastState.id;
  5467. this.toolbar.set( new wp.media.view.Toolbar({
  5468. controller: this,
  5469. items: {
  5470. back: {
  5471. text: l10n.back,
  5472. priority: 80,
  5473. click: function() {
  5474. if ( previous ) {
  5475. frame.setState( previous );
  5476. } else {
  5477. frame.close();
  5478. }
  5479. }
  5480. },
  5481. replace: {
  5482. style: 'primary',
  5483. text: l10n.replace,
  5484. priority: 20,
  5485. requires: { selection: true },
  5486. click: function() {
  5487. var controller = this.controller,
  5488. state = controller.state(),
  5489. selection = state.get( 'selection' ),
  5490. attachment = selection.single();
  5491. controller.close();
  5492. controller.image.changeAttachment( attachment, state.display( attachment ) );
  5493. // Not sure if we want to use wp.media.string.image which will create a shortcode or
  5494. // perhaps wp.html.string to at least to build the <img />.
  5495. state.trigger( 'replace', controller.image.toJSON() );
  5496. // Restore and reset the default state.
  5497. controller.setState( controller.options.state );
  5498. controller.reset();
  5499. }
  5500. }
  5501. }
  5502. }) );
  5503. }
  5504. });
  5505. module.exports = ImageDetails;
  5506. /***/ }),
  5507. /***/ 9075:
  5508. /***/ (function(module) {
  5509. var Select = wp.media.view.MediaFrame.Select,
  5510. Library = wp.media.controller.Library,
  5511. l10n = wp.media.view.l10n,
  5512. Post;
  5513. /**
  5514. * wp.media.view.MediaFrame.Post
  5515. *
  5516. * The frame for manipulating media on the Edit Post page.
  5517. *
  5518. * @memberOf wp.media.view.MediaFrame
  5519. *
  5520. * @class
  5521. * @augments wp.media.view.MediaFrame.Select
  5522. * @augments wp.media.view.MediaFrame
  5523. * @augments wp.media.view.Frame
  5524. * @augments wp.media.View
  5525. * @augments wp.Backbone.View
  5526. * @augments Backbone.View
  5527. * @mixes wp.media.controller.StateMachine
  5528. */
  5529. Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
  5530. initialize: function() {
  5531. this.counts = {
  5532. audio: {
  5533. count: wp.media.view.settings.attachmentCounts.audio,
  5534. state: 'playlist'
  5535. },
  5536. video: {
  5537. count: wp.media.view.settings.attachmentCounts.video,
  5538. state: 'video-playlist'
  5539. }
  5540. };
  5541. _.defaults( this.options, {
  5542. multiple: true,
  5543. editing: false,
  5544. state: 'insert',
  5545. metadata: {}
  5546. });
  5547. // Call 'initialize' directly on the parent class.
  5548. Select.prototype.initialize.apply( this, arguments );
  5549. this.createIframeStates();
  5550. },
  5551. /**
  5552. * Create the default states.
  5553. */
  5554. createStates: function() {
  5555. var options = this.options;
  5556. this.states.add([
  5557. // Main states.
  5558. new Library({
  5559. id: 'insert',
  5560. title: l10n.insertMediaTitle,
  5561. priority: 20,
  5562. toolbar: 'main-insert',
  5563. filterable: 'all',
  5564. library: wp.media.query( options.library ),
  5565. multiple: options.multiple ? 'reset' : false,
  5566. editable: true,
  5567. // If the user isn't allowed to edit fields,
  5568. // can they still edit it locally?
  5569. allowLocalEdits: true,
  5570. // Show the attachment display settings.
  5571. displaySettings: true,
  5572. // Update user settings when users adjust the
  5573. // attachment display settings.
  5574. displayUserSettings: true
  5575. }),
  5576. new Library({
  5577. id: 'gallery',
  5578. title: l10n.createGalleryTitle,
  5579. priority: 40,
  5580. toolbar: 'main-gallery',
  5581. filterable: 'uploaded',
  5582. multiple: 'add',
  5583. editable: false,
  5584. library: wp.media.query( _.defaults({
  5585. type: 'image'
  5586. }, options.library ) )
  5587. }),
  5588. // Embed states.
  5589. new wp.media.controller.Embed( { metadata: options.metadata } ),
  5590. new wp.media.controller.EditImage( { model: options.editImage } ),
  5591. // Gallery states.
  5592. new wp.media.controller.GalleryEdit({
  5593. library: options.selection,
  5594. editing: options.editing,
  5595. menu: 'gallery'
  5596. }),
  5597. new wp.media.controller.GalleryAdd(),
  5598. new Library({
  5599. id: 'playlist',
  5600. title: l10n.createPlaylistTitle,
  5601. priority: 60,
  5602. toolbar: 'main-playlist',
  5603. filterable: 'uploaded',
  5604. multiple: 'add',
  5605. editable: false,
  5606. library: wp.media.query( _.defaults({
  5607. type: 'audio'
  5608. }, options.library ) )
  5609. }),
  5610. // Playlist states.
  5611. new wp.media.controller.CollectionEdit({
  5612. type: 'audio',
  5613. collectionType: 'playlist',
  5614. title: l10n.editPlaylistTitle,
  5615. SettingsView: wp.media.view.Settings.Playlist,
  5616. library: options.selection,
  5617. editing: options.editing,
  5618. menu: 'playlist',
  5619. dragInfoText: l10n.playlistDragInfo,
  5620. dragInfo: false
  5621. }),
  5622. new wp.media.controller.CollectionAdd({
  5623. type: 'audio',
  5624. collectionType: 'playlist',
  5625. title: l10n.addToPlaylistTitle
  5626. }),
  5627. new Library({
  5628. id: 'video-playlist',
  5629. title: l10n.createVideoPlaylistTitle,
  5630. priority: 60,
  5631. toolbar: 'main-video-playlist',
  5632. filterable: 'uploaded',
  5633. multiple: 'add',
  5634. editable: false,
  5635. library: wp.media.query( _.defaults({
  5636. type: 'video'
  5637. }, options.library ) )
  5638. }),
  5639. new wp.media.controller.CollectionEdit({
  5640. type: 'video',
  5641. collectionType: 'playlist',
  5642. title: l10n.editVideoPlaylistTitle,
  5643. SettingsView: wp.media.view.Settings.Playlist,
  5644. library: options.selection,
  5645. editing: options.editing,
  5646. menu: 'video-playlist',
  5647. dragInfoText: l10n.videoPlaylistDragInfo,
  5648. dragInfo: false
  5649. }),
  5650. new wp.media.controller.CollectionAdd({
  5651. type: 'video',
  5652. collectionType: 'playlist',
  5653. title: l10n.addToVideoPlaylistTitle
  5654. })
  5655. ]);
  5656. if ( wp.media.view.settings.post.featuredImageId ) {
  5657. this.states.add( new wp.media.controller.FeaturedImage() );
  5658. }
  5659. },
  5660. bindHandlers: function() {
  5661. var handlers, checkCounts;
  5662. Select.prototype.bindHandlers.apply( this, arguments );
  5663. this.on( 'activate', this.activate, this );
  5664. // Only bother checking media type counts if one of the counts is zero.
  5665. checkCounts = _.find( this.counts, function( type ) {
  5666. return type.count === 0;
  5667. } );
  5668. if ( typeof checkCounts !== 'undefined' ) {
  5669. this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
  5670. }
  5671. this.on( 'menu:create:gallery', this.createMenu, this );
  5672. this.on( 'menu:create:playlist', this.createMenu, this );
  5673. this.on( 'menu:create:video-playlist', this.createMenu, this );
  5674. this.on( 'toolbar:create:main-insert', this.createToolbar, this );
  5675. this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
  5676. this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
  5677. this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
  5678. this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
  5679. this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
  5680. handlers = {
  5681. menu: {
  5682. 'default': 'mainMenu',
  5683. 'gallery': 'galleryMenu',
  5684. 'playlist': 'playlistMenu',
  5685. 'video-playlist': 'videoPlaylistMenu'
  5686. },
  5687. content: {
  5688. 'embed': 'embedContent',
  5689. 'edit-image': 'editImageContent',
  5690. 'edit-selection': 'editSelectionContent'
  5691. },
  5692. toolbar: {
  5693. 'main-insert': 'mainInsertToolbar',
  5694. 'main-gallery': 'mainGalleryToolbar',
  5695. 'gallery-edit': 'galleryEditToolbar',
  5696. 'gallery-add': 'galleryAddToolbar',
  5697. 'main-playlist': 'mainPlaylistToolbar',
  5698. 'playlist-edit': 'playlistEditToolbar',
  5699. 'playlist-add': 'playlistAddToolbar',
  5700. 'main-video-playlist': 'mainVideoPlaylistToolbar',
  5701. 'video-playlist-edit': 'videoPlaylistEditToolbar',
  5702. 'video-playlist-add': 'videoPlaylistAddToolbar'
  5703. }
  5704. };
  5705. _.each( handlers, function( regionHandlers, region ) {
  5706. _.each( regionHandlers, function( callback, handler ) {
  5707. this.on( region + ':render:' + handler, this[ callback ], this );
  5708. }, this );
  5709. }, this );
  5710. },
  5711. activate: function() {
  5712. // Hide menu items for states tied to particular media types if there are no items.
  5713. _.each( this.counts, function( type ) {
  5714. if ( type.count < 1 ) {
  5715. this.menuItemVisibility( type.state, 'hide' );
  5716. }
  5717. }, this );
  5718. },
  5719. mediaTypeCounts: function( model, attr ) {
  5720. if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
  5721. this.counts[ attr ].count++;
  5722. this.menuItemVisibility( this.counts[ attr ].state, 'show' );
  5723. }
  5724. },
  5725. // Menus.
  5726. /**
  5727. * @param {wp.Backbone.View} view
  5728. */
  5729. mainMenu: function( view ) {
  5730. view.set({
  5731. 'library-separator': new wp.media.View({
  5732. className: 'separator',
  5733. priority: 100,
  5734. attributes: {
  5735. role: 'presentation'
  5736. }
  5737. })
  5738. });
  5739. },
  5740. menuItemVisibility: function( state, visibility ) {
  5741. var menu = this.menu.get();
  5742. if ( visibility === 'hide' ) {
  5743. menu.hide( state );
  5744. } else if ( visibility === 'show' ) {
  5745. menu.show( state );
  5746. }
  5747. },
  5748. /**
  5749. * @param {wp.Backbone.View} view
  5750. */
  5751. galleryMenu: function( view ) {
  5752. var lastState = this.lastState(),
  5753. previous = lastState && lastState.id,
  5754. frame = this;
  5755. view.set({
  5756. cancel: {
  5757. text: l10n.cancelGalleryTitle,
  5758. priority: 20,
  5759. click: function() {
  5760. if ( previous ) {
  5761. frame.setState( previous );
  5762. } else {
  5763. frame.close();
  5764. }
  5765. // Move focus to the modal after canceling a Gallery.
  5766. this.controller.modal.focusManager.focus();
  5767. }
  5768. },
  5769. separateCancel: new wp.media.View({
  5770. className: 'separator',
  5771. priority: 40
  5772. })
  5773. });
  5774. },
  5775. playlistMenu: function( view ) {
  5776. var lastState = this.lastState(),
  5777. previous = lastState && lastState.id,
  5778. frame = this;
  5779. view.set({
  5780. cancel: {
  5781. text: l10n.cancelPlaylistTitle,
  5782. priority: 20,
  5783. click: function() {
  5784. if ( previous ) {
  5785. frame.setState( previous );
  5786. } else {
  5787. frame.close();
  5788. }
  5789. // Move focus to the modal after canceling an Audio Playlist.
  5790. this.controller.modal.focusManager.focus();
  5791. }
  5792. },
  5793. separateCancel: new wp.media.View({
  5794. className: 'separator',
  5795. priority: 40
  5796. })
  5797. });
  5798. },
  5799. videoPlaylistMenu: function( view ) {
  5800. var lastState = this.lastState(),
  5801. previous = lastState && lastState.id,
  5802. frame = this;
  5803. view.set({
  5804. cancel: {
  5805. text: l10n.cancelVideoPlaylistTitle,
  5806. priority: 20,
  5807. click: function() {
  5808. if ( previous ) {
  5809. frame.setState( previous );
  5810. } else {
  5811. frame.close();
  5812. }
  5813. // Move focus to the modal after canceling a Video Playlist.
  5814. this.controller.modal.focusManager.focus();
  5815. }
  5816. },
  5817. separateCancel: new wp.media.View({
  5818. className: 'separator',
  5819. priority: 40
  5820. })
  5821. });
  5822. },
  5823. // Content.
  5824. embedContent: function() {
  5825. var view = new wp.media.view.Embed({
  5826. controller: this,
  5827. model: this.state()
  5828. }).render();
  5829. this.content.set( view );
  5830. },
  5831. editSelectionContent: function() {
  5832. var state = this.state(),
  5833. selection = state.get('selection'),
  5834. view;
  5835. view = new wp.media.view.AttachmentsBrowser({
  5836. controller: this,
  5837. collection: selection,
  5838. selection: selection,
  5839. model: state,
  5840. sortable: true,
  5841. search: false,
  5842. date: false,
  5843. dragInfo: true,
  5844. AttachmentView: wp.media.view.Attachments.EditSelection
  5845. }).render();
  5846. view.toolbar.set( 'backToLibrary', {
  5847. text: l10n.returnToLibrary,
  5848. priority: -100,
  5849. click: function() {
  5850. this.controller.content.mode('browse');
  5851. // Move focus to the modal when jumping back from Edit Selection to Add Media view.
  5852. this.controller.modal.focusManager.focus();
  5853. }
  5854. });
  5855. // Browse our library of attachments.
  5856. this.content.set( view );
  5857. // Trigger the controller to set focus.
  5858. this.trigger( 'edit:selection', this );
  5859. },
  5860. editImageContent: function() {
  5861. var image = this.state().get('image'),
  5862. view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
  5863. this.content.set( view );
  5864. // After creating the wrapper view, load the actual editor via an Ajax call.
  5865. view.loadEditor();
  5866. },
  5867. // Toolbars.
  5868. /**
  5869. * @param {wp.Backbone.View} view
  5870. */
  5871. selectionStatusToolbar: function( view ) {
  5872. var editable = this.state().get('editable');
  5873. view.set( 'selection', new wp.media.view.Selection({
  5874. controller: this,
  5875. collection: this.state().get('selection'),
  5876. priority: -40,
  5877. // If the selection is editable, pass the callback to
  5878. // switch the content mode.
  5879. editable: editable && function() {
  5880. this.controller.content.mode('edit-selection');
  5881. }
  5882. }).render() );
  5883. },
  5884. /**
  5885. * @param {wp.Backbone.View} view
  5886. */
  5887. mainInsertToolbar: function( view ) {
  5888. var controller = this;
  5889. this.selectionStatusToolbar( view );
  5890. view.set( 'insert', {
  5891. style: 'primary',
  5892. priority: 80,
  5893. text: l10n.insertIntoPost,
  5894. requires: { selection: true },
  5895. /**
  5896. * @ignore
  5897. *
  5898. * @fires wp.media.controller.State#insert
  5899. */
  5900. click: function() {
  5901. var state = controller.state(),
  5902. selection = state.get('selection');
  5903. controller.close();
  5904. state.trigger( 'insert', selection ).reset();
  5905. }
  5906. });
  5907. },
  5908. /**
  5909. * @param {wp.Backbone.View} view
  5910. */
  5911. mainGalleryToolbar: function( view ) {
  5912. var controller = this;
  5913. this.selectionStatusToolbar( view );
  5914. view.set( 'gallery', {
  5915. style: 'primary',
  5916. text: l10n.createNewGallery,
  5917. priority: 60,
  5918. requires: { selection: true },
  5919. click: function() {
  5920. var selection = controller.state().get('selection'),
  5921. edit = controller.state('gallery-edit'),
  5922. models = selection.where({ type: 'image' });
  5923. edit.set( 'library', new wp.media.model.Selection( models, {
  5924. props: selection.props.toJSON(),
  5925. multiple: true
  5926. }) );
  5927. // Jump to Edit Gallery view.
  5928. this.controller.setState( 'gallery-edit' );
  5929. // Move focus to the modal after jumping to Edit Gallery view.
  5930. this.controller.modal.focusManager.focus();
  5931. }
  5932. });
  5933. },
  5934. mainPlaylistToolbar: function( view ) {
  5935. var controller = this;
  5936. this.selectionStatusToolbar( view );
  5937. view.set( 'playlist', {
  5938. style: 'primary',
  5939. text: l10n.createNewPlaylist,
  5940. priority: 100,
  5941. requires: { selection: true },
  5942. click: function() {
  5943. var selection = controller.state().get('selection'),
  5944. edit = controller.state('playlist-edit'),
  5945. models = selection.where({ type: 'audio' });
  5946. edit.set( 'library', new wp.media.model.Selection( models, {
  5947. props: selection.props.toJSON(),
  5948. multiple: true
  5949. }) );
  5950. // Jump to Edit Audio Playlist view.
  5951. this.controller.setState( 'playlist-edit' );
  5952. // Move focus to the modal after jumping to Edit Audio Playlist view.
  5953. this.controller.modal.focusManager.focus();
  5954. }
  5955. });
  5956. },
  5957. mainVideoPlaylistToolbar: function( view ) {
  5958. var controller = this;
  5959. this.selectionStatusToolbar( view );
  5960. view.set( 'video-playlist', {
  5961. style: 'primary',
  5962. text: l10n.createNewVideoPlaylist,
  5963. priority: 100,
  5964. requires: { selection: true },
  5965. click: function() {
  5966. var selection = controller.state().get('selection'),
  5967. edit = controller.state('video-playlist-edit'),
  5968. models = selection.where({ type: 'video' });
  5969. edit.set( 'library', new wp.media.model.Selection( models, {
  5970. props: selection.props.toJSON(),
  5971. multiple: true
  5972. }) );
  5973. // Jump to Edit Video Playlist view.
  5974. this.controller.setState( 'video-playlist-edit' );
  5975. // Move focus to the modal after jumping to Edit Video Playlist view.
  5976. this.controller.modal.focusManager.focus();
  5977. }
  5978. });
  5979. },
  5980. featuredImageToolbar: function( toolbar ) {
  5981. this.createSelectToolbar( toolbar, {
  5982. text: l10n.setFeaturedImage,
  5983. state: this.options.state
  5984. });
  5985. },
  5986. mainEmbedToolbar: function( toolbar ) {
  5987. toolbar.view = new wp.media.view.Toolbar.Embed({
  5988. controller: this
  5989. });
  5990. },
  5991. galleryEditToolbar: function() {
  5992. var editing = this.state().get('editing');
  5993. this.toolbar.set( new wp.media.view.Toolbar({
  5994. controller: this,
  5995. items: {
  5996. insert: {
  5997. style: 'primary',
  5998. text: editing ? l10n.updateGallery : l10n.insertGallery,
  5999. priority: 80,
  6000. requires: { library: true },
  6001. /**
  6002. * @fires wp.media.controller.State#update
  6003. */
  6004. click: function() {
  6005. var controller = this.controller,
  6006. state = controller.state();
  6007. controller.close();
  6008. state.trigger( 'update', state.get('library') );
  6009. // Restore and reset the default state.
  6010. controller.setState( controller.options.state );
  6011. controller.reset();
  6012. }
  6013. }
  6014. }
  6015. }) );
  6016. },
  6017. galleryAddToolbar: function() {
  6018. this.toolbar.set( new wp.media.view.Toolbar({
  6019. controller: this,
  6020. items: {
  6021. insert: {
  6022. style: 'primary',
  6023. text: l10n.addToGallery,
  6024. priority: 80,
  6025. requires: { selection: true },
  6026. /**
  6027. * @fires wp.media.controller.State#reset
  6028. */
  6029. click: function() {
  6030. var controller = this.controller,
  6031. state = controller.state(),
  6032. edit = controller.state('gallery-edit');
  6033. edit.get('library').add( state.get('selection').models );
  6034. state.trigger('reset');
  6035. controller.setState('gallery-edit');
  6036. // Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
  6037. this.controller.modal.focusManager.focus();
  6038. }
  6039. }
  6040. }
  6041. }) );
  6042. },
  6043. playlistEditToolbar: function() {
  6044. var editing = this.state().get('editing');
  6045. this.toolbar.set( new wp.media.view.Toolbar({
  6046. controller: this,
  6047. items: {
  6048. insert: {
  6049. style: 'primary',
  6050. text: editing ? l10n.updatePlaylist : l10n.insertPlaylist,
  6051. priority: 80,
  6052. requires: { library: true },
  6053. /**
  6054. * @fires wp.media.controller.State#update
  6055. */
  6056. click: function() {
  6057. var controller = this.controller,
  6058. state = controller.state();
  6059. controller.close();
  6060. state.trigger( 'update', state.get('library') );
  6061. // Restore and reset the default state.
  6062. controller.setState( controller.options.state );
  6063. controller.reset();
  6064. }
  6065. }
  6066. }
  6067. }) );
  6068. },
  6069. playlistAddToolbar: function() {
  6070. this.toolbar.set( new wp.media.view.Toolbar({
  6071. controller: this,
  6072. items: {
  6073. insert: {
  6074. style: 'primary',
  6075. text: l10n.addToPlaylist,
  6076. priority: 80,
  6077. requires: { selection: true },
  6078. /**
  6079. * @fires wp.media.controller.State#reset
  6080. */
  6081. click: function() {
  6082. var controller = this.controller,
  6083. state = controller.state(),
  6084. edit = controller.state('playlist-edit');
  6085. edit.get('library').add( state.get('selection').models );
  6086. state.trigger('reset');
  6087. controller.setState('playlist-edit');
  6088. // Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
  6089. this.controller.modal.focusManager.focus();
  6090. }
  6091. }
  6092. }
  6093. }) );
  6094. },
  6095. videoPlaylistEditToolbar: function() {
  6096. var editing = this.state().get('editing');
  6097. this.toolbar.set( new wp.media.view.Toolbar({
  6098. controller: this,
  6099. items: {
  6100. insert: {
  6101. style: 'primary',
  6102. text: editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
  6103. priority: 140,
  6104. requires: { library: true },
  6105. click: function() {
  6106. var controller = this.controller,
  6107. state = controller.state(),
  6108. library = state.get('library');
  6109. library.type = 'video';
  6110. controller.close();
  6111. state.trigger( 'update', library );
  6112. // Restore and reset the default state.
  6113. controller.setState( controller.options.state );
  6114. controller.reset();
  6115. }
  6116. }
  6117. }
  6118. }) );
  6119. },
  6120. videoPlaylistAddToolbar: function() {
  6121. this.toolbar.set( new wp.media.view.Toolbar({
  6122. controller: this,
  6123. items: {
  6124. insert: {
  6125. style: 'primary',
  6126. text: l10n.addToVideoPlaylist,
  6127. priority: 140,
  6128. requires: { selection: true },
  6129. click: function() {
  6130. var controller = this.controller,
  6131. state = controller.state(),
  6132. edit = controller.state('video-playlist-edit');
  6133. edit.get('library').add( state.get('selection').models );
  6134. state.trigger('reset');
  6135. controller.setState('video-playlist-edit');
  6136. // Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
  6137. this.controller.modal.focusManager.focus();
  6138. }
  6139. }
  6140. }
  6141. }) );
  6142. }
  6143. });
  6144. module.exports = Post;
  6145. /***/ }),
  6146. /***/ 8719:
  6147. /***/ (function(module) {
  6148. var MediaFrame = wp.media.view.MediaFrame,
  6149. l10n = wp.media.view.l10n,
  6150. Select;
  6151. /**
  6152. * wp.media.view.MediaFrame.Select
  6153. *
  6154. * A frame for selecting an item or items from the media library.
  6155. *
  6156. * @memberOf wp.media.view.MediaFrame
  6157. *
  6158. * @class
  6159. * @augments wp.media.view.MediaFrame
  6160. * @augments wp.media.view.Frame
  6161. * @augments wp.media.View
  6162. * @augments wp.Backbone.View
  6163. * @augments Backbone.View
  6164. * @mixes wp.media.controller.StateMachine
  6165. */
  6166. Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
  6167. initialize: function() {
  6168. // Call 'initialize' directly on the parent class.
  6169. MediaFrame.prototype.initialize.apply( this, arguments );
  6170. _.defaults( this.options, {
  6171. selection: [],
  6172. library: {},
  6173. multiple: false,
  6174. state: 'library'
  6175. });
  6176. this.createSelection();
  6177. this.createStates();
  6178. this.bindHandlers();
  6179. },
  6180. /**
  6181. * Attach a selection collection to the frame.
  6182. *
  6183. * A selection is a collection of attachments used for a specific purpose
  6184. * by a media frame. e.g. Selecting an attachment (or many) to insert into
  6185. * post content.
  6186. *
  6187. * @see media.model.Selection
  6188. */
  6189. createSelection: function() {
  6190. var selection = this.options.selection;
  6191. if ( ! (selection instanceof wp.media.model.Selection) ) {
  6192. this.options.selection = new wp.media.model.Selection( selection, {
  6193. multiple: this.options.multiple
  6194. });
  6195. }
  6196. this._selection = {
  6197. attachments: new wp.media.model.Attachments(),
  6198. difference: []
  6199. };
  6200. },
  6201. editImageContent: function() {
  6202. var image = this.state().get('image'),
  6203. view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
  6204. this.content.set( view );
  6205. // After creating the wrapper view, load the actual editor via an Ajax call.
  6206. view.loadEditor();
  6207. },
  6208. /**
  6209. * Create the default states on the frame.
  6210. */
  6211. createStates: function() {
  6212. var options = this.options;
  6213. if ( this.options.states ) {
  6214. return;
  6215. }
  6216. // Add the default states.
  6217. this.states.add([
  6218. // Main states.
  6219. new wp.media.controller.Library({
  6220. library: wp.media.query( options.library ),
  6221. multiple: options.multiple,
  6222. title: options.title,
  6223. priority: 20
  6224. }),
  6225. new wp.media.controller.EditImage( { model: options.editImage } )
  6226. ]);
  6227. },
  6228. /**
  6229. * Bind region mode event callbacks.
  6230. *
  6231. * @see media.controller.Region.render
  6232. */
  6233. bindHandlers: function() {
  6234. this.on( 'router:create:browse', this.createRouter, this );
  6235. this.on( 'router:render:browse', this.browseRouter, this );
  6236. this.on( 'content:create:browse', this.browseContent, this );
  6237. this.on( 'content:render:upload', this.uploadContent, this );
  6238. this.on( 'toolbar:create:select', this.createSelectToolbar, this );
  6239. this.on( 'content:render:edit-image', this.editImageContent, this );
  6240. },
  6241. /**
  6242. * Render callback for the router region in the `browse` mode.
  6243. *
  6244. * @param {wp.media.view.Router} routerView
  6245. */
  6246. browseRouter: function( routerView ) {
  6247. routerView.set({
  6248. upload: {
  6249. text: l10n.uploadFilesTitle,
  6250. priority: 20
  6251. },
  6252. browse: {
  6253. text: l10n.mediaLibraryTitle,
  6254. priority: 40
  6255. }
  6256. });
  6257. },
  6258. /**
  6259. * Render callback for the content region in the `browse` mode.
  6260. *
  6261. * @param {wp.media.controller.Region} contentRegion
  6262. */
  6263. browseContent: function( contentRegion ) {
  6264. var state = this.state();
  6265. this.$el.removeClass('hide-toolbar');
  6266. // Browse our library of attachments.
  6267. contentRegion.view = new wp.media.view.AttachmentsBrowser({
  6268. controller: this,
  6269. collection: state.get('library'),
  6270. selection: state.get('selection'),
  6271. model: state,
  6272. sortable: state.get('sortable'),
  6273. search: state.get('searchable'),
  6274. filters: state.get('filterable'),
  6275. date: state.get('date'),
  6276. display: state.has('display') ? state.get('display') : state.get('displaySettings'),
  6277. dragInfo: state.get('dragInfo'),
  6278. idealColumnWidth: state.get('idealColumnWidth'),
  6279. suggestedWidth: state.get('suggestedWidth'),
  6280. suggestedHeight: state.get('suggestedHeight'),
  6281. AttachmentView: state.get('AttachmentView')
  6282. });
  6283. },
  6284. /**
  6285. * Render callback for the content region in the `upload` mode.
  6286. */
  6287. uploadContent: function() {
  6288. this.$el.removeClass( 'hide-toolbar' );
  6289. this.content.set( new wp.media.view.UploaderInline({
  6290. controller: this
  6291. }) );
  6292. },
  6293. /**
  6294. * Toolbars
  6295. *
  6296. * @param {Object} toolbar
  6297. * @param {Object} [options={}]
  6298. * @this wp.media.controller.Region
  6299. */
  6300. createSelectToolbar: function( toolbar, options ) {
  6301. options = options || this.options.button || {};
  6302. options.controller = this;
  6303. toolbar.view = new wp.media.view.Toolbar.Select( options );
  6304. }
  6305. });
  6306. module.exports = Select;
  6307. /***/ }),
  6308. /***/ 7990:
  6309. /***/ (function(module) {
  6310. /**
  6311. * wp.media.view.Heading
  6312. *
  6313. * A reusable heading component for the media library
  6314. *
  6315. * Used to add accessibility friendly headers in the media library/modal.
  6316. *
  6317. * @class
  6318. * @augments wp.media.View
  6319. * @augments wp.Backbone.View
  6320. * @augments Backbone.View
  6321. */
  6322. var Heading = wp.media.View.extend( {
  6323. tagName: function() {
  6324. return this.options.level || 'h1';
  6325. },
  6326. className: 'media-views-heading',
  6327. initialize: function() {
  6328. if ( this.options.className ) {
  6329. this.$el.addClass( this.options.className );
  6330. }
  6331. this.text = this.options.text;
  6332. },
  6333. render: function() {
  6334. this.$el.html( this.text );
  6335. return this;
  6336. }
  6337. } );
  6338. module.exports = Heading;
  6339. /***/ }),
  6340. /***/ 6217:
  6341. /***/ (function(module) {
  6342. /**
  6343. * wp.media.view.Iframe
  6344. *
  6345. * @memberOf wp.media.view
  6346. *
  6347. * @class
  6348. * @augments wp.media.View
  6349. * @augments wp.Backbone.View
  6350. * @augments Backbone.View
  6351. */
  6352. var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
  6353. className: 'media-iframe',
  6354. /**
  6355. * @return {wp.media.view.Iframe} Returns itself to allow chaining.
  6356. */
  6357. render: function() {
  6358. this.views.detach();
  6359. this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
  6360. this.views.render();
  6361. return this;
  6362. }
  6363. });
  6364. module.exports = Iframe;
  6365. /***/ }),
  6366. /***/ 7598:
  6367. /***/ (function(module) {
  6368. var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
  6369. $ = jQuery,
  6370. ImageDetails;
  6371. /**
  6372. * wp.media.view.ImageDetails
  6373. *
  6374. * @memberOf wp.media.view
  6375. *
  6376. * @class
  6377. * @augments wp.media.view.Settings.AttachmentDisplay
  6378. * @augments wp.media.view.Settings
  6379. * @augments wp.media.View
  6380. * @augments wp.Backbone.View
  6381. * @augments Backbone.View
  6382. */
  6383. ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
  6384. className: 'image-details',
  6385. template: wp.template('image-details'),
  6386. events: _.defaults( AttachmentDisplay.prototype.events, {
  6387. 'click .edit-attachment': 'editAttachment',
  6388. 'click .replace-attachment': 'replaceAttachment',
  6389. 'click .advanced-toggle': 'onToggleAdvanced',
  6390. 'change [data-setting="customWidth"]': 'onCustomSize',
  6391. 'change [data-setting="customHeight"]': 'onCustomSize',
  6392. 'keyup [data-setting="customWidth"]': 'onCustomSize',
  6393. 'keyup [data-setting="customHeight"]': 'onCustomSize'
  6394. } ),
  6395. initialize: function() {
  6396. // Used in AttachmentDisplay.prototype.updateLinkTo.
  6397. this.options.attachment = this.model.attachment;
  6398. this.listenTo( this.model, 'change:url', this.updateUrl );
  6399. this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
  6400. this.listenTo( this.model, 'change:size', this.toggleCustomSize );
  6401. AttachmentDisplay.prototype.initialize.apply( this, arguments );
  6402. },
  6403. prepare: function() {
  6404. var attachment = false;
  6405. if ( this.model.attachment ) {
  6406. attachment = this.model.attachment.toJSON();
  6407. }
  6408. return _.defaults({
  6409. model: this.model.toJSON(),
  6410. attachment: attachment
  6411. }, this.options );
  6412. },
  6413. render: function() {
  6414. var args = arguments;
  6415. if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
  6416. this.model.dfd
  6417. .done( _.bind( function() {
  6418. AttachmentDisplay.prototype.render.apply( this, args );
  6419. this.postRender();
  6420. }, this ) )
  6421. .fail( _.bind( function() {
  6422. this.model.attachment = false;
  6423. AttachmentDisplay.prototype.render.apply( this, args );
  6424. this.postRender();
  6425. }, this ) );
  6426. } else {
  6427. AttachmentDisplay.prototype.render.apply( this, arguments );
  6428. this.postRender();
  6429. }
  6430. return this;
  6431. },
  6432. postRender: function() {
  6433. setTimeout( _.bind( this.scrollToTop, this ), 10 );
  6434. this.toggleLinkSettings();
  6435. if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
  6436. this.toggleAdvanced( true );
  6437. }
  6438. this.trigger( 'post-render' );
  6439. },
  6440. scrollToTop: function() {
  6441. this.$( '.embed-media-settings' ).scrollTop( 0 );
  6442. },
  6443. updateUrl: function() {
  6444. this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
  6445. this.$( '.url' ).val( this.model.get( 'url' ) );
  6446. },
  6447. toggleLinkSettings: function() {
  6448. if ( this.model.get( 'link' ) === 'none' ) {
  6449. this.$( '.link-settings' ).addClass('hidden');
  6450. } else {
  6451. this.$( '.link-settings' ).removeClass('hidden');
  6452. }
  6453. },
  6454. toggleCustomSize: function() {
  6455. if ( this.model.get( 'size' ) !== 'custom' ) {
  6456. this.$( '.custom-size' ).addClass('hidden');
  6457. } else {
  6458. this.$( '.custom-size' ).removeClass('hidden');
  6459. }
  6460. },
  6461. onCustomSize: function( event ) {
  6462. var dimension = $( event.target ).data('setting'),
  6463. num = $( event.target ).val(),
  6464. value;
  6465. // Ignore bogus input.
  6466. if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
  6467. event.preventDefault();
  6468. return;
  6469. }
  6470. if ( dimension === 'customWidth' ) {
  6471. value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
  6472. this.model.set( 'customHeight', value, { silent: true } );
  6473. this.$( '[data-setting="customHeight"]' ).val( value );
  6474. } else {
  6475. value = Math.round( this.model.get( 'aspectRatio' ) * num );
  6476. this.model.set( 'customWidth', value, { silent: true } );
  6477. this.$( '[data-setting="customWidth"]' ).val( value );
  6478. }
  6479. },
  6480. onToggleAdvanced: function( event ) {
  6481. event.preventDefault();
  6482. this.toggleAdvanced();
  6483. },
  6484. toggleAdvanced: function( show ) {
  6485. var $advanced = this.$el.find( '.advanced-section' ),
  6486. mode;
  6487. if ( $advanced.hasClass('advanced-visible') || show === false ) {
  6488. $advanced.removeClass('advanced-visible');
  6489. $advanced.find('.advanced-settings').addClass('hidden');
  6490. mode = 'hide';
  6491. } else {
  6492. $advanced.addClass('advanced-visible');
  6493. $advanced.find('.advanced-settings').removeClass('hidden');
  6494. mode = 'show';
  6495. }
  6496. window.setUserSetting( 'advImgDetails', mode );
  6497. },
  6498. editAttachment: function( event ) {
  6499. var editState = this.controller.states.get( 'edit-image' );
  6500. if ( window.imageEdit && editState ) {
  6501. event.preventDefault();
  6502. editState.set( 'image', this.model.attachment );
  6503. this.controller.setState( 'edit-image' );
  6504. }
  6505. },
  6506. replaceAttachment: function( event ) {
  6507. event.preventDefault();
  6508. this.controller.setState( 'replace-image' );
  6509. }
  6510. });
  6511. module.exports = ImageDetails;
  6512. /***/ }),
  6513. /***/ 6644:
  6514. /***/ (function(module) {
  6515. /**
  6516. * wp.media.view.Label
  6517. *
  6518. * @memberOf wp.media.view
  6519. *
  6520. * @class
  6521. * @augments wp.media.View
  6522. * @augments wp.Backbone.View
  6523. * @augments Backbone.View
  6524. */
  6525. var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
  6526. tagName: 'label',
  6527. className: 'screen-reader-text',
  6528. initialize: function() {
  6529. this.value = this.options.value;
  6530. },
  6531. render: function() {
  6532. this.$el.html( this.value );
  6533. return this;
  6534. }
  6535. });
  6536. module.exports = Label;
  6537. /***/ }),
  6538. /***/ 4861:
  6539. /***/ (function(module) {
  6540. var Frame = wp.media.view.Frame,
  6541. l10n = wp.media.view.l10n,
  6542. $ = jQuery,
  6543. MediaFrame;
  6544. /**
  6545. * wp.media.view.MediaFrame
  6546. *
  6547. * The frame used to create the media modal.
  6548. *
  6549. * @memberOf wp.media.view
  6550. *
  6551. * @class
  6552. * @augments wp.media.view.Frame
  6553. * @augments wp.media.View
  6554. * @augments wp.Backbone.View
  6555. * @augments Backbone.View
  6556. * @mixes wp.media.controller.StateMachine
  6557. */
  6558. MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
  6559. className: 'media-frame',
  6560. template: wp.template('media-frame'),
  6561. regions: ['menu','title','content','toolbar','router'],
  6562. events: {
  6563. 'click .media-frame-menu-toggle': 'toggleMenu'
  6564. },
  6565. /**
  6566. * @constructs
  6567. */
  6568. initialize: function() {
  6569. Frame.prototype.initialize.apply( this, arguments );
  6570. _.defaults( this.options, {
  6571. title: l10n.mediaFrameDefaultTitle,
  6572. modal: true,
  6573. uploader: true
  6574. });
  6575. // Ensure core UI is enabled.
  6576. this.$el.addClass('wp-core-ui');
  6577. // Initialize modal container view.
  6578. if ( this.options.modal ) {
  6579. this.modal = new wp.media.view.Modal({
  6580. controller: this,
  6581. title: this.options.title
  6582. });
  6583. this.modal.content( this );
  6584. }
  6585. // Force the uploader off if the upload limit has been exceeded or
  6586. // if the browser isn't supported.
  6587. if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
  6588. this.options.uploader = false;
  6589. }
  6590. // Initialize window-wide uploader.
  6591. if ( this.options.uploader ) {
  6592. this.uploader = new wp.media.view.UploaderWindow({
  6593. controller: this,
  6594. uploader: {
  6595. dropzone: this.modal ? this.modal.$el : this.$el,
  6596. container: this.$el
  6597. }
  6598. });
  6599. this.views.set( '.media-frame-uploader', this.uploader );
  6600. }
  6601. this.on( 'attach', _.bind( this.views.ready, this.views ), this );
  6602. // Bind default title creation.
  6603. this.on( 'title:create:default', this.createTitle, this );
  6604. this.title.mode('default');
  6605. // Bind default menu.
  6606. this.on( 'menu:create:default', this.createMenu, this );
  6607. // Set the menu ARIA tab panel attributes when the modal opens.
  6608. this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
  6609. // Set the router ARIA tab panel attributes when the modal opens.
  6610. this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
  6611. // Update the menu ARIA tab panel attributes when the content updates.
  6612. this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
  6613. // Update the router ARIA tab panel attributes when the content updates.
  6614. this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
  6615. },
  6616. /**
  6617. * Sets the attributes to be used on the menu ARIA tab panel.
  6618. *
  6619. * @since 5.3.0
  6620. *
  6621. * @return {void}
  6622. */
  6623. setMenuTabPanelAriaAttributes: function() {
  6624. var stateId = this.state().get( 'id' ),
  6625. tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
  6626. ariaLabelledby;
  6627. tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
  6628. if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
  6629. ariaLabelledby = 'menu-item-' + stateId;
  6630. // Set the tab panel attributes only if the tabs are visible.
  6631. tabPanelEl
  6632. .attr( {
  6633. role: 'tabpanel',
  6634. 'aria-labelledby': ariaLabelledby,
  6635. tabIndex: '0'
  6636. } );
  6637. }
  6638. },
  6639. /**
  6640. * Sets the attributes to be used on the router ARIA tab panel.
  6641. *
  6642. * @since 5.3.0
  6643. *
  6644. * @return {void}
  6645. */
  6646. setRouterTabPanelAriaAttributes: function() {
  6647. var tabPanelEl = this.$el.find( '.media-frame-content' ),
  6648. ariaLabelledby;
  6649. tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
  6650. // Set the tab panel attributes only if the tabs are visible.
  6651. if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
  6652. ariaLabelledby = 'menu-item-' + this.content._mode;
  6653. tabPanelEl
  6654. .attr( {
  6655. role: 'tabpanel',
  6656. 'aria-labelledby': ariaLabelledby,
  6657. tabIndex: '0'
  6658. } );
  6659. }
  6660. },
  6661. /**
  6662. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6663. */
  6664. render: function() {
  6665. // Activate the default state if no active state exists.
  6666. if ( ! this.state() && this.options.state ) {
  6667. this.setState( this.options.state );
  6668. }
  6669. /**
  6670. * call 'render' directly on the parent class
  6671. */
  6672. return Frame.prototype.render.apply( this, arguments );
  6673. },
  6674. /**
  6675. * @param {Object} title
  6676. * @this wp.media.controller.Region
  6677. */
  6678. createTitle: function( title ) {
  6679. title.view = new wp.media.View({
  6680. controller: this,
  6681. tagName: 'h1'
  6682. });
  6683. },
  6684. /**
  6685. * @param {Object} menu
  6686. * @this wp.media.controller.Region
  6687. */
  6688. createMenu: function( menu ) {
  6689. menu.view = new wp.media.view.Menu({
  6690. controller: this,
  6691. attributes: {
  6692. role: 'tablist',
  6693. 'aria-orientation': 'vertical'
  6694. }
  6695. });
  6696. this.menuView = menu.view;
  6697. },
  6698. toggleMenu: function( event ) {
  6699. var menu = this.$el.find( '.media-menu' );
  6700. menu.toggleClass( 'visible' );
  6701. $( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
  6702. },
  6703. /**
  6704. * @param {Object} toolbar
  6705. * @this wp.media.controller.Region
  6706. */
  6707. createToolbar: function( toolbar ) {
  6708. toolbar.view = new wp.media.view.Toolbar({
  6709. controller: this
  6710. });
  6711. },
  6712. /**
  6713. * @param {Object} router
  6714. * @this wp.media.controller.Region
  6715. */
  6716. createRouter: function( router ) {
  6717. router.view = new wp.media.view.Router({
  6718. controller: this,
  6719. attributes: {
  6720. role: 'tablist',
  6721. 'aria-orientation': 'horizontal'
  6722. }
  6723. });
  6724. this.routerView = router.view;
  6725. },
  6726. /**
  6727. * @param {Object} options
  6728. */
  6729. createIframeStates: function( options ) {
  6730. var settings = wp.media.view.settings,
  6731. tabs = settings.tabs,
  6732. tabUrl = settings.tabUrl,
  6733. $postId;
  6734. if ( ! tabs || ! tabUrl ) {
  6735. return;
  6736. }
  6737. // Add the post ID to the tab URL if it exists.
  6738. $postId = $('#post_ID');
  6739. if ( $postId.length ) {
  6740. tabUrl += '&post_id=' + $postId.val();
  6741. }
  6742. // Generate the tab states.
  6743. _.each( tabs, function( title, id ) {
  6744. this.state( 'iframe:' + id ).set( _.defaults({
  6745. tab: id,
  6746. src: tabUrl + '&tab=' + id,
  6747. title: title,
  6748. content: 'iframe',
  6749. menu: 'default'
  6750. }, options ) );
  6751. }, this );
  6752. this.on( 'content:create:iframe', this.iframeContent, this );
  6753. this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
  6754. this.on( 'menu:render:default', this.iframeMenu, this );
  6755. this.on( 'open', this.hijackThickbox, this );
  6756. this.on( 'close', this.restoreThickbox, this );
  6757. },
  6758. /**
  6759. * @param {Object} content
  6760. * @this wp.media.controller.Region
  6761. */
  6762. iframeContent: function( content ) {
  6763. this.$el.addClass('hide-toolbar');
  6764. content.view = new wp.media.view.Iframe({
  6765. controller: this
  6766. });
  6767. },
  6768. iframeContentCleanup: function() {
  6769. this.$el.removeClass('hide-toolbar');
  6770. },
  6771. iframeMenu: function( view ) {
  6772. var views = {};
  6773. if ( ! view ) {
  6774. return;
  6775. }
  6776. _.each( wp.media.view.settings.tabs, function( title, id ) {
  6777. views[ 'iframe:' + id ] = {
  6778. text: this.state( 'iframe:' + id ).get('title'),
  6779. priority: 200
  6780. };
  6781. }, this );
  6782. view.set( views );
  6783. },
  6784. hijackThickbox: function() {
  6785. var frame = this;
  6786. if ( ! window.tb_remove || this._tb_remove ) {
  6787. return;
  6788. }
  6789. this._tb_remove = window.tb_remove;
  6790. window.tb_remove = function() {
  6791. frame.close();
  6792. frame.reset();
  6793. frame.setState( frame.options.state );
  6794. frame._tb_remove.call( window );
  6795. };
  6796. },
  6797. restoreThickbox: function() {
  6798. if ( ! this._tb_remove ) {
  6799. return;
  6800. }
  6801. window.tb_remove = this._tb_remove;
  6802. delete this._tb_remove;
  6803. }
  6804. });
  6805. // Map some of the modal's methods to the frame.
  6806. _.each(['open','close','attach','detach','escape'], function( method ) {
  6807. /**
  6808. * @function open
  6809. * @memberOf wp.media.view.MediaFrame
  6810. * @instance
  6811. *
  6812. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6813. */
  6814. /**
  6815. * @function close
  6816. * @memberOf wp.media.view.MediaFrame
  6817. * @instance
  6818. *
  6819. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6820. */
  6821. /**
  6822. * @function attach
  6823. * @memberOf wp.media.view.MediaFrame
  6824. * @instance
  6825. *
  6826. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6827. */
  6828. /**
  6829. * @function detach
  6830. * @memberOf wp.media.view.MediaFrame
  6831. * @instance
  6832. *
  6833. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6834. */
  6835. /**
  6836. * @function escape
  6837. * @memberOf wp.media.view.MediaFrame
  6838. * @instance
  6839. *
  6840. * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
  6841. */
  6842. MediaFrame.prototype[ method ] = function() {
  6843. if ( this.modal ) {
  6844. this.modal[ method ].apply( this.modal, arguments );
  6845. }
  6846. return this;
  6847. };
  6848. });
  6849. module.exports = MediaFrame;
  6850. /***/ }),
  6851. /***/ 917:
  6852. /***/ (function(module) {
  6853. var MenuItem;
  6854. /**
  6855. * wp.media.view.MenuItem
  6856. *
  6857. * @memberOf wp.media.view
  6858. *
  6859. * @class
  6860. * @augments wp.media.View
  6861. * @augments wp.Backbone.View
  6862. * @augments Backbone.View
  6863. */
  6864. MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
  6865. tagName: 'button',
  6866. className: 'media-menu-item',
  6867. attributes: {
  6868. type: 'button',
  6869. role: 'tab'
  6870. },
  6871. events: {
  6872. 'click': '_click'
  6873. },
  6874. /**
  6875. * Allows to override the click event.
  6876. */
  6877. _click: function() {
  6878. var clickOverride = this.options.click;
  6879. if ( clickOverride ) {
  6880. clickOverride.call( this );
  6881. } else {
  6882. this.click();
  6883. }
  6884. },
  6885. click: function() {
  6886. var state = this.options.state;
  6887. if ( state ) {
  6888. this.controller.setState( state );
  6889. // Toggle the menu visibility in the responsive view.
  6890. this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
  6891. }
  6892. },
  6893. /**
  6894. * @return {wp.media.view.MenuItem} returns itself to allow chaining.
  6895. */
  6896. render: function() {
  6897. var options = this.options,
  6898. menuProperty = options.state || options.contentMode;
  6899. if ( options.text ) {
  6900. this.$el.text( options.text );
  6901. } else if ( options.html ) {
  6902. this.$el.html( options.html );
  6903. }
  6904. // Set the menu item ID based on the frame state associated to the menu item.
  6905. this.$el.attr( 'id', 'menu-item-' + menuProperty );
  6906. return this;
  6907. }
  6908. });
  6909. module.exports = MenuItem;
  6910. /***/ }),
  6911. /***/ 2596:
  6912. /***/ (function(module) {
  6913. var MenuItem = wp.media.view.MenuItem,
  6914. PriorityList = wp.media.view.PriorityList,
  6915. Menu;
  6916. /**
  6917. * wp.media.view.Menu
  6918. *
  6919. * @memberOf wp.media.view
  6920. *
  6921. * @class
  6922. * @augments wp.media.view.PriorityList
  6923. * @augments wp.media.View
  6924. * @augments wp.Backbone.View
  6925. * @augments Backbone.View
  6926. */
  6927. Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
  6928. tagName: 'div',
  6929. className: 'media-menu',
  6930. property: 'state',
  6931. ItemView: MenuItem,
  6932. region: 'menu',
  6933. attributes: {
  6934. role: 'tablist',
  6935. 'aria-orientation': 'horizontal'
  6936. },
  6937. initialize: function() {
  6938. this._views = {};
  6939. this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
  6940. delete this.options.views;
  6941. if ( ! this.options.silent ) {
  6942. this.render();
  6943. }
  6944. // Initialize the Focus Manager.
  6945. this.focusManager = new wp.media.view.FocusManager( {
  6946. el: this.el,
  6947. mode: 'tabsNavigation'
  6948. } );
  6949. // The menu is always rendered and can be visible or hidden on some frames.
  6950. this.isVisible = true;
  6951. },
  6952. /**
  6953. * @param {Object} options
  6954. * @param {string} id
  6955. * @return {wp.media.View}
  6956. */
  6957. toView: function( options, id ) {
  6958. options = options || {};
  6959. options[ this.property ] = options[ this.property ] || id;
  6960. return new this.ItemView( options ).render();
  6961. },
  6962. ready: function() {
  6963. /**
  6964. * call 'ready' directly on the parent class
  6965. */
  6966. PriorityList.prototype.ready.apply( this, arguments );
  6967. this.visibility();
  6968. // Set up aria tabs initial attributes.
  6969. this.focusManager.setupAriaTabs();
  6970. },
  6971. set: function() {
  6972. /**
  6973. * call 'set' directly on the parent class
  6974. */
  6975. PriorityList.prototype.set.apply( this, arguments );
  6976. this.visibility();
  6977. },
  6978. unset: function() {
  6979. /**
  6980. * call 'unset' directly on the parent class
  6981. */
  6982. PriorityList.prototype.unset.apply( this, arguments );
  6983. this.visibility();
  6984. },
  6985. visibility: function() {
  6986. var region = this.region,
  6987. view = this.controller[ region ].get(),
  6988. views = this.views.get(),
  6989. hide = ! views || views.length < 2;
  6990. if ( this === view ) {
  6991. // Flag this menu as hidden or visible.
  6992. this.isVisible = ! hide;
  6993. // Set or remove a CSS class to hide the menu.
  6994. this.controller.$el.toggleClass( 'hide-' + region, hide );
  6995. }
  6996. },
  6997. /**
  6998. * @param {string} id
  6999. */
  7000. select: function( id ) {
  7001. var view = this.get( id );
  7002. if ( ! view ) {
  7003. return;
  7004. }
  7005. this.deselect();
  7006. view.$el.addClass('active');
  7007. // Set up again the aria tabs initial attributes after the menu updates.
  7008. this.focusManager.setupAriaTabs();
  7009. },
  7010. deselect: function() {
  7011. this.$el.children().removeClass('active');
  7012. },
  7013. hide: function( id ) {
  7014. var view = this.get( id );
  7015. if ( ! view ) {
  7016. return;
  7017. }
  7018. view.$el.addClass('hidden');
  7019. },
  7020. show: function( id ) {
  7021. var view = this.get( id );
  7022. if ( ! view ) {
  7023. return;
  7024. }
  7025. view.$el.removeClass('hidden');
  7026. }
  7027. });
  7028. module.exports = Menu;
  7029. /***/ }),
  7030. /***/ 3939:
  7031. /***/ (function(module) {
  7032. var $ = jQuery,
  7033. Modal;
  7034. /**
  7035. * wp.media.view.Modal
  7036. *
  7037. * A modal view, which the media modal uses as its default container.
  7038. *
  7039. * @memberOf wp.media.view
  7040. *
  7041. * @class
  7042. * @augments wp.media.View
  7043. * @augments wp.Backbone.View
  7044. * @augments Backbone.View
  7045. */
  7046. Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
  7047. tagName: 'div',
  7048. template: wp.template('media-modal'),
  7049. events: {
  7050. 'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
  7051. 'keydown': 'keydown'
  7052. },
  7053. clickedOpenerEl: null,
  7054. initialize: function() {
  7055. _.defaults( this.options, {
  7056. container: document.body,
  7057. title: '',
  7058. propagate: true,
  7059. hasCloseButton: true
  7060. });
  7061. this.focusManager = new wp.media.view.FocusManager({
  7062. el: this.el
  7063. });
  7064. },
  7065. /**
  7066. * @return {Object}
  7067. */
  7068. prepare: function() {
  7069. return {
  7070. title: this.options.title,
  7071. hasCloseButton: this.options.hasCloseButton
  7072. };
  7073. },
  7074. /**
  7075. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7076. */
  7077. attach: function() {
  7078. if ( this.views.attached ) {
  7079. return this;
  7080. }
  7081. if ( ! this.views.rendered ) {
  7082. this.render();
  7083. }
  7084. this.$el.appendTo( this.options.container );
  7085. // Manually mark the view as attached and trigger ready.
  7086. this.views.attached = true;
  7087. this.views.ready();
  7088. return this.propagate('attach');
  7089. },
  7090. /**
  7091. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7092. */
  7093. detach: function() {
  7094. if ( this.$el.is(':visible') ) {
  7095. this.close();
  7096. }
  7097. this.$el.detach();
  7098. this.views.attached = false;
  7099. return this.propagate('detach');
  7100. },
  7101. /**
  7102. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7103. */
  7104. open: function() {
  7105. var $el = this.$el,
  7106. mceEditor;
  7107. if ( $el.is(':visible') ) {
  7108. return this;
  7109. }
  7110. this.clickedOpenerEl = document.activeElement;
  7111. if ( ! this.views.attached ) {
  7112. this.attach();
  7113. }
  7114. // Disable page scrolling.
  7115. $( 'body' ).addClass( 'modal-open' );
  7116. $el.show();
  7117. // Try to close the onscreen keyboard.
  7118. if ( 'ontouchend' in document ) {
  7119. if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
  7120. mceEditor.iframeElement.focus();
  7121. mceEditor.iframeElement.blur();
  7122. setTimeout( function() {
  7123. mceEditor.iframeElement.blur();
  7124. }, 100 );
  7125. }
  7126. }
  7127. // Set initial focus on the content instead of this view element, to avoid page scrolling.
  7128. this.$( '.media-modal' ).trigger( 'focus' );
  7129. // Hide the page content from assistive technologies.
  7130. this.focusManager.setAriaHiddenOnBodyChildren( $el );
  7131. return this.propagate('open');
  7132. },
  7133. /**
  7134. * @param {Object} options
  7135. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7136. */
  7137. close: function( options ) {
  7138. if ( ! this.views.attached || ! this.$el.is(':visible') ) {
  7139. return this;
  7140. }
  7141. // Pause current audio/video even after closing the modal.
  7142. $( '.mejs-pause button' ).trigger( 'click' );
  7143. // Enable page scrolling.
  7144. $( 'body' ).removeClass( 'modal-open' );
  7145. // Hide the modal element by adding display:none.
  7146. this.$el.hide();
  7147. /*
  7148. * Make visible again to assistive technologies all body children that
  7149. * have been made hidden when the modal opened.
  7150. */
  7151. this.focusManager.removeAriaHiddenFromBodyChildren();
  7152. // Move focus back in useful location once modal is closed.
  7153. if ( null !== this.clickedOpenerEl ) {
  7154. // Move focus back to the element that opened the modal.
  7155. this.clickedOpenerEl.focus();
  7156. } else {
  7157. // Fallback to the admin page main element.
  7158. $( '#wpbody-content' )
  7159. .attr( 'tabindex', '-1' )
  7160. .trigger( 'focus' );
  7161. }
  7162. this.propagate('close');
  7163. if ( options && options.escape ) {
  7164. this.propagate('escape');
  7165. }
  7166. return this;
  7167. },
  7168. /**
  7169. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7170. */
  7171. escape: function() {
  7172. return this.close({ escape: true });
  7173. },
  7174. /**
  7175. * @param {Object} event
  7176. */
  7177. escapeHandler: function( event ) {
  7178. event.preventDefault();
  7179. this.escape();
  7180. },
  7181. /**
  7182. * @param {Array|Object} content Views to register to '.media-modal-content'
  7183. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7184. */
  7185. content: function( content ) {
  7186. this.views.set( '.media-modal-content', content );
  7187. return this;
  7188. },
  7189. /**
  7190. * Triggers a modal event and if the `propagate` option is set,
  7191. * forwards events to the modal's controller.
  7192. *
  7193. * @param {string} id
  7194. * @return {wp.media.view.Modal} Returns itself to allow chaining.
  7195. */
  7196. propagate: function( id ) {
  7197. this.trigger( id );
  7198. if ( this.options.propagate ) {
  7199. this.controller.trigger( id );
  7200. }
  7201. return this;
  7202. },
  7203. /**
  7204. * @param {Object} event
  7205. */
  7206. keydown: function( event ) {
  7207. // Close the modal when escape is pressed.
  7208. if ( 27 === event.which && this.$el.is(':visible') ) {
  7209. this.escape();
  7210. event.stopImmediatePropagation();
  7211. }
  7212. }
  7213. });
  7214. module.exports = Modal;
  7215. /***/ }),
  7216. /***/ 1993:
  7217. /***/ (function(module) {
  7218. /**
  7219. * wp.media.view.PriorityList
  7220. *
  7221. * @memberOf wp.media.view
  7222. *
  7223. * @class
  7224. * @augments wp.media.View
  7225. * @augments wp.Backbone.View
  7226. * @augments Backbone.View
  7227. */
  7228. var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
  7229. tagName: 'div',
  7230. initialize: function() {
  7231. this._views = {};
  7232. this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
  7233. delete this.options.views;
  7234. if ( ! this.options.silent ) {
  7235. this.render();
  7236. }
  7237. },
  7238. /**
  7239. * @param {string} id
  7240. * @param {wp.media.View|Object} view
  7241. * @param {Object} options
  7242. * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
  7243. */
  7244. set: function( id, view, options ) {
  7245. var priority, views, index;
  7246. options = options || {};
  7247. // Accept an object with an `id` : `view` mapping.
  7248. if ( _.isObject( id ) ) {
  7249. _.each( id, function( view, id ) {
  7250. this.set( id, view );
  7251. }, this );
  7252. return this;
  7253. }
  7254. if ( ! (view instanceof Backbone.View) ) {
  7255. view = this.toView( view, id, options );
  7256. }
  7257. view.controller = view.controller || this.controller;
  7258. this.unset( id );
  7259. priority = view.options.priority || 10;
  7260. views = this.views.get() || [];
  7261. _.find( views, function( existing, i ) {
  7262. if ( existing.options.priority > priority ) {
  7263. index = i;
  7264. return true;
  7265. }
  7266. });
  7267. this._views[ id ] = view;
  7268. this.views.add( view, {
  7269. at: _.isNumber( index ) ? index : views.length || 0
  7270. });
  7271. return this;
  7272. },
  7273. /**
  7274. * @param {string} id
  7275. * @return {wp.media.View}
  7276. */
  7277. get: function( id ) {
  7278. return this._views[ id ];
  7279. },
  7280. /**
  7281. * @param {string} id
  7282. * @return {wp.media.view.PriorityList}
  7283. */
  7284. unset: function( id ) {
  7285. var view = this.get( id );
  7286. if ( view ) {
  7287. view.remove();
  7288. }
  7289. delete this._views[ id ];
  7290. return this;
  7291. },
  7292. /**
  7293. * @param {Object} options
  7294. * @return {wp.media.View}
  7295. */
  7296. toView: function( options ) {
  7297. return new wp.media.View( options );
  7298. }
  7299. });
  7300. module.exports = PriorityList;
  7301. /***/ }),
  7302. /***/ 9484:
  7303. /***/ (function(module) {
  7304. /**
  7305. * wp.media.view.RouterItem
  7306. *
  7307. * @memberOf wp.media.view
  7308. *
  7309. * @class
  7310. * @augments wp.media.view.MenuItem
  7311. * @augments wp.media.View
  7312. * @augments wp.Backbone.View
  7313. * @augments Backbone.View
  7314. */
  7315. var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
  7316. /**
  7317. * On click handler to activate the content region's corresponding mode.
  7318. */
  7319. click: function() {
  7320. var contentMode = this.options.contentMode;
  7321. if ( contentMode ) {
  7322. this.controller.content.mode( contentMode );
  7323. }
  7324. }
  7325. });
  7326. module.exports = RouterItem;
  7327. /***/ }),
  7328. /***/ 1562:
  7329. /***/ (function(module) {
  7330. var Menu = wp.media.view.Menu,
  7331. Router;
  7332. /**
  7333. * wp.media.view.Router
  7334. *
  7335. * @memberOf wp.media.view
  7336. *
  7337. * @class
  7338. * @augments wp.media.view.Menu
  7339. * @augments wp.media.view.PriorityList
  7340. * @augments wp.media.View
  7341. * @augments wp.Backbone.View
  7342. * @augments Backbone.View
  7343. */
  7344. Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
  7345. tagName: 'div',
  7346. className: 'media-router',
  7347. property: 'contentMode',
  7348. ItemView: wp.media.view.RouterItem,
  7349. region: 'router',
  7350. attributes: {
  7351. role: 'tablist',
  7352. 'aria-orientation': 'horizontal'
  7353. },
  7354. initialize: function() {
  7355. this.controller.on( 'content:render', this.update, this );
  7356. // Call 'initialize' directly on the parent class.
  7357. Menu.prototype.initialize.apply( this, arguments );
  7358. },
  7359. update: function() {
  7360. var mode = this.controller.content.mode();
  7361. if ( mode ) {
  7362. this.select( mode );
  7363. }
  7364. }
  7365. });
  7366. module.exports = Router;
  7367. /***/ }),
  7368. /***/ 4556:
  7369. /***/ (function(module) {
  7370. var Search;
  7371. /**
  7372. * wp.media.view.Search
  7373. *
  7374. * @memberOf wp.media.view
  7375. *
  7376. * @class
  7377. * @augments wp.media.View
  7378. * @augments wp.Backbone.View
  7379. * @augments Backbone.View
  7380. */
  7381. Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
  7382. tagName: 'input',
  7383. className: 'search',
  7384. id: 'media-search-input',
  7385. attributes: {
  7386. type: 'search'
  7387. },
  7388. events: {
  7389. 'input': 'search'
  7390. },
  7391. /**
  7392. * @return {wp.media.view.Search} Returns itself to allow chaining.
  7393. */
  7394. render: function() {
  7395. this.el.value = this.model.escape('search');
  7396. return this;
  7397. },
  7398. search: _.debounce( function( event ) {
  7399. var searchTerm = event.target.value.trim();
  7400. // Trigger the search only after 2 ASCII characters.
  7401. if ( searchTerm && searchTerm.length > 1 ) {
  7402. this.model.set( 'search', searchTerm );
  7403. } else {
  7404. this.model.unset( 'search' );
  7405. }
  7406. }, 500 )
  7407. });
  7408. module.exports = Search;
  7409. /***/ }),
  7410. /***/ 6191:
  7411. /***/ (function(module) {
  7412. var _n = wp.i18n._n,
  7413. sprintf = wp.i18n.sprintf,
  7414. Selection;
  7415. /**
  7416. * wp.media.view.Selection
  7417. *
  7418. * @memberOf wp.media.view
  7419. *
  7420. * @class
  7421. * @augments wp.media.View
  7422. * @augments wp.Backbone.View
  7423. * @augments Backbone.View
  7424. */
  7425. Selection = wp.media.View.extend(/** @lends wp.media.view.Selection.prototype */{
  7426. tagName: 'div',
  7427. className: 'media-selection',
  7428. template: wp.template('media-selection'),
  7429. events: {
  7430. 'click .edit-selection': 'edit',
  7431. 'click .clear-selection': 'clear'
  7432. },
  7433. initialize: function() {
  7434. _.defaults( this.options, {
  7435. editable: false,
  7436. clearable: true
  7437. });
  7438. /**
  7439. * @member {wp.media.view.Attachments.Selection}
  7440. */
  7441. this.attachments = new wp.media.view.Attachments.Selection({
  7442. controller: this.controller,
  7443. collection: this.collection,
  7444. selection: this.collection,
  7445. model: new Backbone.Model()
  7446. });
  7447. this.views.set( '.selection-view', this.attachments );
  7448. this.collection.on( 'add remove reset', this.refresh, this );
  7449. this.controller.on( 'content:activate', this.refresh, this );
  7450. },
  7451. ready: function() {
  7452. this.refresh();
  7453. },
  7454. refresh: function() {
  7455. // If the selection hasn't been rendered, bail.
  7456. if ( ! this.$el.children().length ) {
  7457. return;
  7458. }
  7459. var collection = this.collection,
  7460. editing = 'edit-selection' === this.controller.content.mode();
  7461. // If nothing is selected, display nothing.
  7462. this.$el.toggleClass( 'empty', ! collection.length );
  7463. this.$el.toggleClass( 'one', 1 === collection.length );
  7464. this.$el.toggleClass( 'editing', editing );
  7465. this.$( '.count' ).text(
  7466. /* translators: %s: Number of selected media attachments. */
  7467. sprintf( _n( '%s item selected', '%s items selected', collection.length ), collection.length )
  7468. );
  7469. },
  7470. edit: function( event ) {
  7471. event.preventDefault();
  7472. if ( this.options.editable ) {
  7473. this.options.editable.call( this, this.collection );
  7474. }
  7475. },
  7476. clear: function( event ) {
  7477. event.preventDefault();
  7478. this.collection.reset();
  7479. // Move focus to the modal.
  7480. this.controller.modal.focusManager.focus();
  7481. }
  7482. });
  7483. module.exports = Selection;
  7484. /***/ }),
  7485. /***/ 859:
  7486. /***/ (function(module) {
  7487. var View = wp.media.View,
  7488. $ = Backbone.$,
  7489. Settings;
  7490. /**
  7491. * wp.media.view.Settings
  7492. *
  7493. * @memberOf wp.media.view
  7494. *
  7495. * @class
  7496. * @augments wp.media.View
  7497. * @augments wp.Backbone.View
  7498. * @augments Backbone.View
  7499. */
  7500. Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
  7501. events: {
  7502. 'click button': 'updateHandler',
  7503. 'change input': 'updateHandler',
  7504. 'change select': 'updateHandler',
  7505. 'change textarea': 'updateHandler'
  7506. },
  7507. initialize: function() {
  7508. this.model = this.model || new Backbone.Model();
  7509. this.listenTo( this.model, 'change', this.updateChanges );
  7510. },
  7511. prepare: function() {
  7512. return _.defaults({
  7513. model: this.model.toJSON()
  7514. }, this.options );
  7515. },
  7516. /**
  7517. * @return {wp.media.view.Settings} Returns itself to allow chaining.
  7518. */
  7519. render: function() {
  7520. View.prototype.render.apply( this, arguments );
  7521. // Select the correct values.
  7522. _( this.model.attributes ).chain().keys().each( this.update, this );
  7523. return this;
  7524. },
  7525. /**
  7526. * @param {string} key
  7527. */
  7528. update: function( key ) {
  7529. var value = this.model.get( key ),
  7530. $setting = this.$('[data-setting="' + key + '"]'),
  7531. $buttons, $value;
  7532. // Bail if we didn't find a matching setting.
  7533. if ( ! $setting.length ) {
  7534. return;
  7535. }
  7536. // Attempt to determine how the setting is rendered and update
  7537. // the selected value.
  7538. // Handle dropdowns.
  7539. if ( $setting.is('select') ) {
  7540. $value = $setting.find('[value="' + value + '"]');
  7541. if ( $value.length ) {
  7542. $setting.find('option').prop( 'selected', false );
  7543. $value.prop( 'selected', true );
  7544. } else {
  7545. // If we can't find the desired value, record what *is* selected.
  7546. this.model.set( key, $setting.find(':selected').val() );
  7547. }
  7548. // Handle button groups.
  7549. } else if ( $setting.hasClass('button-group') ) {
  7550. $buttons = $setting.find( 'button' )
  7551. .removeClass( 'active' )
  7552. .attr( 'aria-pressed', 'false' );
  7553. $buttons.filter( '[value="' + value + '"]' )
  7554. .addClass( 'active' )
  7555. .attr( 'aria-pressed', 'true' );
  7556. // Handle text inputs and textareas.
  7557. } else if ( $setting.is('input[type="text"], textarea') ) {
  7558. if ( ! $setting.is(':focus') ) {
  7559. $setting.val( value );
  7560. }
  7561. // Handle checkboxes.
  7562. } else if ( $setting.is('input[type="checkbox"]') ) {
  7563. $setting.prop( 'checked', !! value && 'false' !== value );
  7564. }
  7565. },
  7566. /**
  7567. * @param {Object} event
  7568. */
  7569. updateHandler: function( event ) {
  7570. var $setting = $( event.target ).closest('[data-setting]'),
  7571. value = event.target.value,
  7572. userSetting;
  7573. event.preventDefault();
  7574. if ( ! $setting.length ) {
  7575. return;
  7576. }
  7577. // Use the correct value for checkboxes.
  7578. if ( $setting.is('input[type="checkbox"]') ) {
  7579. value = $setting[0].checked;
  7580. }
  7581. // Update the corresponding setting.
  7582. this.model.set( $setting.data('setting'), value );
  7583. // If the setting has a corresponding user setting,
  7584. // update that as well.
  7585. userSetting = $setting.data('userSetting');
  7586. if ( userSetting ) {
  7587. window.setUserSetting( userSetting, value );
  7588. }
  7589. },
  7590. updateChanges: function( model ) {
  7591. if ( model.hasChanged() ) {
  7592. _( model.changed ).chain().keys().each( this.update, this );
  7593. }
  7594. }
  7595. });
  7596. module.exports = Settings;
  7597. /***/ }),
  7598. /***/ 2176:
  7599. /***/ (function(module) {
  7600. var Settings = wp.media.view.Settings,
  7601. AttachmentDisplay;
  7602. /**
  7603. * wp.media.view.Settings.AttachmentDisplay
  7604. *
  7605. * @memberOf wp.media.view.Settings
  7606. *
  7607. * @class
  7608. * @augments wp.media.view.Settings
  7609. * @augments wp.media.View
  7610. * @augments wp.Backbone.View
  7611. * @augments Backbone.View
  7612. */
  7613. AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
  7614. className: 'attachment-display-settings',
  7615. template: wp.template('attachment-display-settings'),
  7616. initialize: function() {
  7617. var attachment = this.options.attachment;
  7618. _.defaults( this.options, {
  7619. userSettings: false
  7620. });
  7621. // Call 'initialize' directly on the parent class.
  7622. Settings.prototype.initialize.apply( this, arguments );
  7623. this.listenTo( this.model, 'change:link', this.updateLinkTo );
  7624. if ( attachment ) {
  7625. attachment.on( 'change:uploading', this.render, this );
  7626. }
  7627. },
  7628. dispose: function() {
  7629. var attachment = this.options.attachment;
  7630. if ( attachment ) {
  7631. attachment.off( null, null, this );
  7632. }
  7633. /**
  7634. * call 'dispose' directly on the parent class
  7635. */
  7636. Settings.prototype.dispose.apply( this, arguments );
  7637. },
  7638. /**
  7639. * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
  7640. */
  7641. render: function() {
  7642. var attachment = this.options.attachment;
  7643. if ( attachment ) {
  7644. _.extend( this.options, {
  7645. sizes: attachment.get('sizes'),
  7646. type: attachment.get('type')
  7647. });
  7648. }
  7649. /**
  7650. * call 'render' directly on the parent class
  7651. */
  7652. Settings.prototype.render.call( this );
  7653. this.updateLinkTo();
  7654. return this;
  7655. },
  7656. updateLinkTo: function() {
  7657. var linkTo = this.model.get('link'),
  7658. $input = this.$('.link-to-custom'),
  7659. attachment = this.options.attachment;
  7660. if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
  7661. $input.closest( '.setting' ).addClass( 'hidden' );
  7662. return;
  7663. }
  7664. if ( attachment ) {
  7665. if ( 'post' === linkTo ) {
  7666. $input.val( attachment.get('link') );
  7667. } else if ( 'file' === linkTo ) {
  7668. $input.val( attachment.get('url') );
  7669. } else if ( ! this.model.get('linkUrl') ) {
  7670. $input.val('http://');
  7671. }
  7672. $input.prop( 'readonly', 'custom' !== linkTo );
  7673. }
  7674. $input.closest( '.setting' ).removeClass( 'hidden' );
  7675. if ( $input.length ) {
  7676. $input[0].scrollIntoView();
  7677. }
  7678. }
  7679. });
  7680. module.exports = AttachmentDisplay;
  7681. /***/ }),
  7682. /***/ 6872:
  7683. /***/ (function(module) {
  7684. /**
  7685. * wp.media.view.Settings.Gallery
  7686. *
  7687. * @memberOf wp.media.view.Settings
  7688. *
  7689. * @class
  7690. * @augments wp.media.view.Settings
  7691. * @augments wp.media.View
  7692. * @augments wp.Backbone.View
  7693. * @augments Backbone.View
  7694. */
  7695. var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
  7696. className: 'collection-settings gallery-settings',
  7697. template: wp.template('gallery-settings')
  7698. });
  7699. module.exports = Gallery;
  7700. /***/ }),
  7701. /***/ 8488:
  7702. /***/ (function(module) {
  7703. /**
  7704. * wp.media.view.Settings.Playlist
  7705. *
  7706. * @memberOf wp.media.view.Settings
  7707. *
  7708. * @class
  7709. * @augments wp.media.view.Settings
  7710. * @augments wp.media.View
  7711. * @augments wp.Backbone.View
  7712. * @augments Backbone.View
  7713. */
  7714. var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
  7715. className: 'collection-settings playlist-settings',
  7716. template: wp.template('playlist-settings')
  7717. });
  7718. module.exports = Playlist;
  7719. /***/ }),
  7720. /***/ 9799:
  7721. /***/ (function(module) {
  7722. /**
  7723. * wp.media.view.Sidebar
  7724. *
  7725. * @memberOf wp.media.view
  7726. *
  7727. * @class
  7728. * @augments wp.media.view.PriorityList
  7729. * @augments wp.media.View
  7730. * @augments wp.Backbone.View
  7731. * @augments Backbone.View
  7732. */
  7733. var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
  7734. className: 'media-sidebar'
  7735. });
  7736. module.exports = Sidebar;
  7737. /***/ }),
  7738. /***/ 5187:
  7739. /***/ (function(module) {
  7740. var View = wp.media.view,
  7741. SiteIconCropper;
  7742. /**
  7743. * wp.media.view.SiteIconCropper
  7744. *
  7745. * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
  7746. *
  7747. * Takes imgAreaSelect options from
  7748. * wp.customize.SiteIconControl.calculateImageSelectOptions.
  7749. *
  7750. * @memberOf wp.media.view
  7751. *
  7752. * @class
  7753. * @augments wp.media.view.Cropper
  7754. * @augments wp.media.View
  7755. * @augments wp.Backbone.View
  7756. * @augments Backbone.View
  7757. */
  7758. SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
  7759. className: 'crop-content site-icon',
  7760. ready: function () {
  7761. View.Cropper.prototype.ready.apply( this, arguments );
  7762. this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
  7763. },
  7764. addSidebar: function() {
  7765. this.sidebar = new wp.media.view.Sidebar({
  7766. controller: this.controller
  7767. });
  7768. this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
  7769. controller: this.controller,
  7770. attachment: this.options.attachment
  7771. }) );
  7772. this.controller.cropperView.views.add( this.sidebar );
  7773. }
  7774. });
  7775. module.exports = SiteIconCropper;
  7776. /***/ }),
  7777. /***/ 8260:
  7778. /***/ (function(module) {
  7779. var View = wp.media.View,
  7780. $ = jQuery,
  7781. SiteIconPreview;
  7782. /**
  7783. * wp.media.view.SiteIconPreview
  7784. *
  7785. * Shows a preview of the Site Icon as a favicon and app icon while cropping.
  7786. *
  7787. * @memberOf wp.media.view
  7788. *
  7789. * @class
  7790. * @augments wp.media.View
  7791. * @augments wp.Backbone.View
  7792. * @augments Backbone.View
  7793. */
  7794. SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
  7795. className: 'site-icon-preview',
  7796. template: wp.template( 'site-icon-preview' ),
  7797. ready: function() {
  7798. this.controller.imgSelect.setOptions({
  7799. onInit: this.updatePreview,
  7800. onSelectChange: this.updatePreview
  7801. });
  7802. },
  7803. prepare: function() {
  7804. return {
  7805. url: this.options.attachment.get( 'url' )
  7806. };
  7807. },
  7808. updatePreview: function( img, coords ) {
  7809. var rx = 64 / coords.width,
  7810. ry = 64 / coords.height,
  7811. preview_rx = 16 / coords.width,
  7812. preview_ry = 16 / coords.height;
  7813. $( '#preview-app-icon' ).css({
  7814. width: Math.round(rx * this.imageWidth ) + 'px',
  7815. height: Math.round(ry * this.imageHeight ) + 'px',
  7816. marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
  7817. marginTop: '-' + Math.round(ry * coords.y1) + 'px'
  7818. });
  7819. $( '#preview-favicon' ).css({
  7820. width: Math.round( preview_rx * this.imageWidth ) + 'px',
  7821. height: Math.round( preview_ry * this.imageHeight ) + 'px',
  7822. marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
  7823. marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
  7824. });
  7825. }
  7826. });
  7827. module.exports = SiteIconPreview;
  7828. /***/ }),
  7829. /***/ 2234:
  7830. /***/ (function(module) {
  7831. /**
  7832. * wp.media.view.Spinner
  7833. *
  7834. * Represents a spinner in the Media Library.
  7835. *
  7836. * @since 3.9.0
  7837. *
  7838. * @memberOf wp.media.view
  7839. *
  7840. * @class
  7841. * @augments wp.media.View
  7842. * @augments wp.Backbone.View
  7843. * @augments Backbone.View
  7844. */
  7845. var Spinner = wp.media.View.extend(/** @lends wp.media.view.Spinner.prototype */{
  7846. tagName: 'span',
  7847. className: 'spinner',
  7848. spinnerTimeout: false,
  7849. delay: 400,
  7850. /**
  7851. * Shows the spinner. Delays the visibility by the configured amount.
  7852. *
  7853. * @since 3.9.0
  7854. *
  7855. * @return {wp.media.view.Spinner} The spinner.
  7856. */
  7857. show: function() {
  7858. if ( ! this.spinnerTimeout ) {
  7859. this.spinnerTimeout = _.delay(function( $el ) {
  7860. $el.addClass( 'is-active' );
  7861. }, this.delay, this.$el );
  7862. }
  7863. return this;
  7864. },
  7865. /**
  7866. * Hides the spinner.
  7867. *
  7868. * @since 3.9.0
  7869. *
  7870. * @return {wp.media.view.Spinner} The spinner.
  7871. */
  7872. hide: function() {
  7873. this.$el.removeClass( 'is-active' );
  7874. this.spinnerTimeout = clearTimeout( this.spinnerTimeout );
  7875. return this;
  7876. }
  7877. });
  7878. module.exports = Spinner;
  7879. /***/ }),
  7880. /***/ 9510:
  7881. /***/ (function(module) {
  7882. var View = wp.media.View,
  7883. Toolbar;
  7884. /**
  7885. * wp.media.view.Toolbar
  7886. *
  7887. * A toolbar which consists of a primary and a secondary section. Each sections
  7888. * can be filled with views.
  7889. *
  7890. * @memberOf wp.media.view
  7891. *
  7892. * @class
  7893. * @augments wp.media.View
  7894. * @augments wp.Backbone.View
  7895. * @augments Backbone.View
  7896. */
  7897. Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
  7898. tagName: 'div',
  7899. className: 'media-toolbar',
  7900. initialize: function() {
  7901. var state = this.controller.state(),
  7902. selection = this.selection = state.get('selection'),
  7903. library = this.library = state.get('library');
  7904. this._views = {};
  7905. // The toolbar is composed of two `PriorityList` views.
  7906. this.primary = new wp.media.view.PriorityList();
  7907. this.secondary = new wp.media.view.PriorityList();
  7908. this.primary.$el.addClass('media-toolbar-primary search-form');
  7909. this.secondary.$el.addClass('media-toolbar-secondary');
  7910. this.views.set([ this.secondary, this.primary ]);
  7911. if ( this.options.items ) {
  7912. this.set( this.options.items, { silent: true });
  7913. }
  7914. if ( ! this.options.silent ) {
  7915. this.render();
  7916. }
  7917. if ( selection ) {
  7918. selection.on( 'add remove reset', this.refresh, this );
  7919. }
  7920. if ( library ) {
  7921. library.on( 'add remove reset', this.refresh, this );
  7922. }
  7923. },
  7924. /**
  7925. * @return {wp.media.view.Toolbar} Returns itsef to allow chaining
  7926. */
  7927. dispose: function() {
  7928. if ( this.selection ) {
  7929. this.selection.off( null, null, this );
  7930. }
  7931. if ( this.library ) {
  7932. this.library.off( null, null, this );
  7933. }
  7934. /**
  7935. * call 'dispose' directly on the parent class
  7936. */
  7937. return View.prototype.dispose.apply( this, arguments );
  7938. },
  7939. ready: function() {
  7940. this.refresh();
  7941. },
  7942. /**
  7943. * @param {string} id
  7944. * @param {Backbone.View|Object} view
  7945. * @param {Object} [options={}]
  7946. * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
  7947. */
  7948. set: function( id, view, options ) {
  7949. var list;
  7950. options = options || {};
  7951. // Accept an object with an `id` : `view` mapping.
  7952. if ( _.isObject( id ) ) {
  7953. _.each( id, function( view, id ) {
  7954. this.set( id, view, { silent: true });
  7955. }, this );
  7956. } else {
  7957. if ( ! ( view instanceof Backbone.View ) ) {
  7958. view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
  7959. view = new wp.media.view.Button( view ).render();
  7960. }
  7961. view.controller = view.controller || this.controller;
  7962. this._views[ id ] = view;
  7963. list = view.options.priority < 0 ? 'secondary' : 'primary';
  7964. this[ list ].set( id, view, options );
  7965. }
  7966. if ( ! options.silent ) {
  7967. this.refresh();
  7968. }
  7969. return this;
  7970. },
  7971. /**
  7972. * @param {string} id
  7973. * @return {wp.media.view.Button}
  7974. */
  7975. get: function( id ) {
  7976. return this._views[ id ];
  7977. },
  7978. /**
  7979. * @param {string} id
  7980. * @param {Object} options
  7981. * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
  7982. */
  7983. unset: function( id, options ) {
  7984. delete this._views[ id ];
  7985. this.primary.unset( id, options );
  7986. this.secondary.unset( id, options );
  7987. if ( ! options || ! options.silent ) {
  7988. this.refresh();
  7989. }
  7990. return this;
  7991. },
  7992. refresh: function() {
  7993. var state = this.controller.state(),
  7994. library = state.get('library'),
  7995. selection = state.get('selection');
  7996. _.each( this._views, function( button ) {
  7997. if ( ! button.model || ! button.options || ! button.options.requires ) {
  7998. return;
  7999. }
  8000. var requires = button.options.requires,
  8001. disabled = false;
  8002. // Prevent insertion of attachments if any of them are still uploading.
  8003. if ( selection && selection.models ) {
  8004. disabled = _.some( selection.models, function( attachment ) {
  8005. return attachment.get('uploading') === true;
  8006. });
  8007. }
  8008. if ( requires.selection && selection && ! selection.length ) {
  8009. disabled = true;
  8010. } else if ( requires.library && library && ! library.length ) {
  8011. disabled = true;
  8012. }
  8013. button.model.set( 'disabled', disabled );
  8014. });
  8015. }
  8016. });
  8017. module.exports = Toolbar;
  8018. /***/ }),
  8019. /***/ 7128:
  8020. /***/ (function(module) {
  8021. var Select = wp.media.view.Toolbar.Select,
  8022. l10n = wp.media.view.l10n,
  8023. Embed;
  8024. /**
  8025. * wp.media.view.Toolbar.Embed
  8026. *
  8027. * @memberOf wp.media.view.Toolbar
  8028. *
  8029. * @class
  8030. * @augments wp.media.view.Toolbar.Select
  8031. * @augments wp.media.view.Toolbar
  8032. * @augments wp.media.View
  8033. * @augments wp.Backbone.View
  8034. * @augments Backbone.View
  8035. */
  8036. Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
  8037. initialize: function() {
  8038. _.defaults( this.options, {
  8039. text: l10n.insertIntoPost,
  8040. requires: false
  8041. });
  8042. // Call 'initialize' directly on the parent class.
  8043. Select.prototype.initialize.apply( this, arguments );
  8044. },
  8045. refresh: function() {
  8046. var url = this.controller.state().props.get('url');
  8047. this.get('select').model.set( 'disabled', ! url || url === 'http://' );
  8048. /**
  8049. * call 'refresh' directly on the parent class
  8050. */
  8051. Select.prototype.refresh.apply( this, arguments );
  8052. }
  8053. });
  8054. module.exports = Embed;
  8055. /***/ }),
  8056. /***/ 6850:
  8057. /***/ (function(module) {
  8058. var Toolbar = wp.media.view.Toolbar,
  8059. l10n = wp.media.view.l10n,
  8060. Select;
  8061. /**
  8062. * wp.media.view.Toolbar.Select
  8063. *
  8064. * @memberOf wp.media.view.Toolbar
  8065. *
  8066. * @class
  8067. * @augments wp.media.view.Toolbar
  8068. * @augments wp.media.View
  8069. * @augments wp.Backbone.View
  8070. * @augments Backbone.View
  8071. */
  8072. Select = Toolbar.extend(/** @lends wp.media.view.Toolbar.Select.prototype */{
  8073. initialize: function() {
  8074. var options = this.options;
  8075. _.bindAll( this, 'clickSelect' );
  8076. _.defaults( options, {
  8077. event: 'select',
  8078. state: false,
  8079. reset: true,
  8080. close: true,
  8081. text: l10n.select,
  8082. // Does the button rely on the selection?
  8083. requires: {
  8084. selection: true
  8085. }
  8086. });
  8087. options.items = _.defaults( options.items || {}, {
  8088. select: {
  8089. style: 'primary',
  8090. text: options.text,
  8091. priority: 80,
  8092. click: this.clickSelect,
  8093. requires: options.requires
  8094. }
  8095. });
  8096. // Call 'initialize' directly on the parent class.
  8097. Toolbar.prototype.initialize.apply( this, arguments );
  8098. },
  8099. clickSelect: function() {
  8100. var options = this.options,
  8101. controller = this.controller;
  8102. if ( options.close ) {
  8103. controller.close();
  8104. }
  8105. if ( options.event ) {
  8106. controller.state().trigger( options.event );
  8107. }
  8108. if ( options.state ) {
  8109. controller.setState( options.state );
  8110. }
  8111. if ( options.reset ) {
  8112. controller.reset();
  8113. }
  8114. }
  8115. });
  8116. module.exports = Select;
  8117. /***/ }),
  8118. /***/ 841:
  8119. /***/ (function(module) {
  8120. var View = wp.media.View,
  8121. l10n = wp.media.view.l10n,
  8122. $ = jQuery,
  8123. EditorUploader;
  8124. /**
  8125. * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
  8126. * and relays drag'n'dropped files to a media workflow.
  8127. *
  8128. * wp.media.view.EditorUploader
  8129. *
  8130. * @memberOf wp.media.view
  8131. *
  8132. * @class
  8133. * @augments wp.media.View
  8134. * @augments wp.Backbone.View
  8135. * @augments Backbone.View
  8136. */
  8137. EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
  8138. tagName: 'div',
  8139. className: 'uploader-editor',
  8140. template: wp.template( 'uploader-editor' ),
  8141. localDrag: false,
  8142. overContainer: false,
  8143. overDropzone: false,
  8144. draggingFile: null,
  8145. /**
  8146. * Bind drag'n'drop events to callbacks.
  8147. */
  8148. initialize: function() {
  8149. this.initialized = false;
  8150. // Bail if not enabled or UA does not support drag'n'drop or File API.
  8151. if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
  8152. return this;
  8153. }
  8154. this.$document = $(document);
  8155. this.dropzones = [];
  8156. this.files = [];
  8157. this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
  8158. this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
  8159. this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
  8160. this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
  8161. this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
  8162. this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
  8163. this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
  8164. this.localDrag = event.type === 'dragstart';
  8165. if ( event.type === 'drop' ) {
  8166. this.containerDragleave();
  8167. }
  8168. }, this ) );
  8169. this.initialized = true;
  8170. return this;
  8171. },
  8172. /**
  8173. * Check browser support for drag'n'drop.
  8174. *
  8175. * @return {boolean}
  8176. */
  8177. browserSupport: function() {
  8178. var supports = false, div = document.createElement('div');
  8179. supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
  8180. supports = supports && !! ( window.File && window.FileList && window.FileReader );
  8181. return supports;
  8182. },
  8183. isDraggingFile: function( event ) {
  8184. if ( this.draggingFile !== null ) {
  8185. return this.draggingFile;
  8186. }
  8187. if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
  8188. return false;
  8189. }
  8190. this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
  8191. _.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
  8192. return this.draggingFile;
  8193. },
  8194. refresh: function( e ) {
  8195. var dropzone_id;
  8196. for ( dropzone_id in this.dropzones ) {
  8197. // Hide the dropzones only if dragging has left the screen.
  8198. this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
  8199. }
  8200. if ( ! _.isUndefined( e ) ) {
  8201. $( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
  8202. }
  8203. if ( ! this.overContainer && ! this.overDropzone ) {
  8204. this.draggingFile = null;
  8205. }
  8206. return this;
  8207. },
  8208. render: function() {
  8209. if ( ! this.initialized ) {
  8210. return this;
  8211. }
  8212. View.prototype.render.apply( this, arguments );
  8213. $( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
  8214. return this;
  8215. },
  8216. attach: function( index, editor ) {
  8217. // Attach a dropzone to an editor.
  8218. var dropzone = this.$el.clone();
  8219. this.dropzones.push( dropzone );
  8220. $( editor ).append( dropzone );
  8221. return this;
  8222. },
  8223. /**
  8224. * When a file is dropped on the editor uploader, open up an editor media workflow
  8225. * and upload the file immediately.
  8226. *
  8227. * @param {jQuery.Event} event The 'drop' event.
  8228. */
  8229. drop: function( event ) {
  8230. var $wrap, uploadView;
  8231. this.containerDragleave( event );
  8232. this.dropzoneDragleave( event );
  8233. this.files = event.originalEvent.dataTransfer.files;
  8234. if ( this.files.length < 1 ) {
  8235. return;
  8236. }
  8237. // Set the active editor to the drop target.
  8238. $wrap = $( event.target ).parents( '.wp-editor-wrap' );
  8239. if ( $wrap.length > 0 && $wrap[0].id ) {
  8240. window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
  8241. }
  8242. if ( ! this.workflow ) {
  8243. this.workflow = wp.media.editor.open( window.wpActiveEditor, {
  8244. frame: 'post',
  8245. state: 'insert',
  8246. title: l10n.addMedia,
  8247. multiple: true
  8248. });
  8249. uploadView = this.workflow.uploader;
  8250. if ( uploadView.uploader && uploadView.uploader.ready ) {
  8251. this.addFiles.apply( this );
  8252. } else {
  8253. this.workflow.on( 'uploader:ready', this.addFiles, this );
  8254. }
  8255. } else {
  8256. this.workflow.state().reset();
  8257. this.addFiles.apply( this );
  8258. this.workflow.open();
  8259. }
  8260. return false;
  8261. },
  8262. /**
  8263. * Add the files to the uploader.
  8264. */
  8265. addFiles: function() {
  8266. if ( this.files.length ) {
  8267. this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
  8268. this.files = [];
  8269. }
  8270. return this;
  8271. },
  8272. containerDragover: function( event ) {
  8273. if ( this.localDrag || ! this.isDraggingFile( event ) ) {
  8274. return;
  8275. }
  8276. this.overContainer = true;
  8277. this.refresh();
  8278. },
  8279. containerDragleave: function() {
  8280. this.overContainer = false;
  8281. // Throttle dragleave because it's called when bouncing from some elements to others.
  8282. _.delay( _.bind( this.refresh, this ), 50 );
  8283. },
  8284. dropzoneDragover: function( event ) {
  8285. if ( this.localDrag || ! this.isDraggingFile( event ) ) {
  8286. return;
  8287. }
  8288. this.overDropzone = true;
  8289. this.refresh( event );
  8290. return false;
  8291. },
  8292. dropzoneDragleave: function( e ) {
  8293. this.overDropzone = false;
  8294. _.delay( _.bind( this.refresh, this, e ), 50 );
  8295. },
  8296. click: function( e ) {
  8297. // In the rare case where the dropzone gets stuck, hide it on click.
  8298. this.containerDragleave( e );
  8299. this.dropzoneDragleave( e );
  8300. this.localDrag = false;
  8301. }
  8302. });
  8303. module.exports = EditorUploader;
  8304. /***/ }),
  8305. /***/ 6353:
  8306. /***/ (function(module) {
  8307. var View = wp.media.View,
  8308. UploaderInline;
  8309. /**
  8310. * wp.media.view.UploaderInline
  8311. *
  8312. * The inline uploader that shows up in the 'Upload Files' tab.
  8313. *
  8314. * @memberOf wp.media.view
  8315. *
  8316. * @class
  8317. * @augments wp.media.View
  8318. * @augments wp.Backbone.View
  8319. * @augments Backbone.View
  8320. */
  8321. UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
  8322. tagName: 'div',
  8323. className: 'uploader-inline',
  8324. template: wp.template('uploader-inline'),
  8325. events: {
  8326. 'click .close': 'hide'
  8327. },
  8328. initialize: function() {
  8329. _.defaults( this.options, {
  8330. message: '',
  8331. status: true,
  8332. canClose: false
  8333. });
  8334. if ( ! this.options.$browser && this.controller.uploader ) {
  8335. this.options.$browser = this.controller.uploader.$browser;
  8336. }
  8337. if ( _.isUndefined( this.options.postId ) ) {
  8338. this.options.postId = wp.media.view.settings.post.id;
  8339. }
  8340. if ( this.options.status ) {
  8341. this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
  8342. controller: this.controller
  8343. }) );
  8344. }
  8345. },
  8346. prepare: function() {
  8347. var suggestedWidth = this.controller.state().get('suggestedWidth'),
  8348. suggestedHeight = this.controller.state().get('suggestedHeight'),
  8349. data = {};
  8350. data.message = this.options.message;
  8351. data.canClose = this.options.canClose;
  8352. if ( suggestedWidth && suggestedHeight ) {
  8353. data.suggestedWidth = suggestedWidth;
  8354. data.suggestedHeight = suggestedHeight;
  8355. }
  8356. return data;
  8357. },
  8358. /**
  8359. * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
  8360. */
  8361. dispose: function() {
  8362. if ( this.disposing ) {
  8363. /**
  8364. * call 'dispose' directly on the parent class
  8365. */
  8366. return View.prototype.dispose.apply( this, arguments );
  8367. }
  8368. /*
  8369. * Run remove on `dispose`, so we can be sure to refresh the
  8370. * uploader with a view-less DOM. Track whether we're disposing
  8371. * so we don't trigger an infinite loop.
  8372. */
  8373. this.disposing = true;
  8374. return this.remove();
  8375. },
  8376. /**
  8377. * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
  8378. */
  8379. remove: function() {
  8380. /**
  8381. * call 'remove' directly on the parent class
  8382. */
  8383. var result = View.prototype.remove.apply( this, arguments );
  8384. _.defer( _.bind( this.refresh, this ) );
  8385. return result;
  8386. },
  8387. refresh: function() {
  8388. var uploader = this.controller.uploader;
  8389. if ( uploader ) {
  8390. uploader.refresh();
  8391. }
  8392. },
  8393. /**
  8394. * @return {wp.media.view.UploaderInline}
  8395. */
  8396. ready: function() {
  8397. var $browser = this.options.$browser,
  8398. $placeholder;
  8399. if ( this.controller.uploader ) {
  8400. $placeholder = this.$('.browser');
  8401. // Check if we've already replaced the placeholder.
  8402. if ( $placeholder[0] === $browser[0] ) {
  8403. return;
  8404. }
  8405. $browser.detach().text( $placeholder.text() );
  8406. $browser[0].className = $placeholder[0].className;
  8407. $browser[0].setAttribute( 'aria-labelledby', $browser[0].id + ' ' + $placeholder[0].getAttribute('aria-labelledby') );
  8408. $placeholder.replaceWith( $browser.show() );
  8409. }
  8410. this.refresh();
  8411. return this;
  8412. },
  8413. show: function() {
  8414. this.$el.removeClass( 'hidden' );
  8415. if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
  8416. this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
  8417. }
  8418. },
  8419. hide: function() {
  8420. this.$el.addClass( 'hidden' );
  8421. if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
  8422. this.controller.$uploaderToggler
  8423. .attr( 'aria-expanded', 'false' )
  8424. // Move focus back to the toggle button when closing the uploader.
  8425. .trigger( 'focus' );
  8426. }
  8427. }
  8428. });
  8429. module.exports = UploaderInline;
  8430. /***/ }),
  8431. /***/ 9411:
  8432. /***/ (function(module) {
  8433. /**
  8434. * wp.media.view.UploaderStatusError
  8435. *
  8436. * @memberOf wp.media.view
  8437. *
  8438. * @class
  8439. * @augments wp.media.View
  8440. * @augments wp.Backbone.View
  8441. * @augments Backbone.View
  8442. */
  8443. var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
  8444. className: 'upload-error',
  8445. template: wp.template('uploader-status-error')
  8446. });
  8447. module.exports = UploaderStatusError;
  8448. /***/ }),
  8449. /***/ 2894:
  8450. /***/ (function(module) {
  8451. var View = wp.media.View,
  8452. UploaderStatus;
  8453. /**
  8454. * wp.media.view.UploaderStatus
  8455. *
  8456. * An uploader status for on-going uploads.
  8457. *
  8458. * @memberOf wp.media.view
  8459. *
  8460. * @class
  8461. * @augments wp.media.View
  8462. * @augments wp.Backbone.View
  8463. * @augments Backbone.View
  8464. */
  8465. UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
  8466. className: 'media-uploader-status',
  8467. template: wp.template('uploader-status'),
  8468. events: {
  8469. 'click .upload-dismiss-errors': 'dismiss'
  8470. },
  8471. initialize: function() {
  8472. this.queue = wp.Uploader.queue;
  8473. this.queue.on( 'add remove reset', this.visibility, this );
  8474. this.queue.on( 'add remove reset change:percent', this.progress, this );
  8475. this.queue.on( 'add remove reset change:uploading', this.info, this );
  8476. this.errors = wp.Uploader.errors;
  8477. this.errors.reset();
  8478. this.errors.on( 'add remove reset', this.visibility, this );
  8479. this.errors.on( 'add', this.error, this );
  8480. },
  8481. /**
  8482. * @return {wp.media.view.UploaderStatus}
  8483. */
  8484. dispose: function() {
  8485. wp.Uploader.queue.off( null, null, this );
  8486. /**
  8487. * call 'dispose' directly on the parent class
  8488. */
  8489. View.prototype.dispose.apply( this, arguments );
  8490. return this;
  8491. },
  8492. visibility: function() {
  8493. this.$el.toggleClass( 'uploading', !! this.queue.length );
  8494. this.$el.toggleClass( 'errors', !! this.errors.length );
  8495. this.$el.toggle( !! this.queue.length || !! this.errors.length );
  8496. },
  8497. ready: function() {
  8498. _.each({
  8499. '$bar': '.media-progress-bar div',
  8500. '$index': '.upload-index',
  8501. '$total': '.upload-total',
  8502. '$filename': '.upload-filename'
  8503. }, function( selector, key ) {
  8504. this[ key ] = this.$( selector );
  8505. }, this );
  8506. this.visibility();
  8507. this.progress();
  8508. this.info();
  8509. },
  8510. progress: function() {
  8511. var queue = this.queue,
  8512. $bar = this.$bar;
  8513. if ( ! $bar || ! queue.length ) {
  8514. return;
  8515. }
  8516. $bar.width( ( queue.reduce( function( memo, attachment ) {
  8517. if ( ! attachment.get('uploading') ) {
  8518. return memo + 100;
  8519. }
  8520. var percent = attachment.get('percent');
  8521. return memo + ( _.isNumber( percent ) ? percent : 100 );
  8522. }, 0 ) / queue.length ) + '%' );
  8523. },
  8524. info: function() {
  8525. var queue = this.queue,
  8526. index = 0, active;
  8527. if ( ! queue.length ) {
  8528. return;
  8529. }
  8530. active = this.queue.find( function( attachment, i ) {
  8531. index = i;
  8532. return attachment.get('uploading');
  8533. });
  8534. if ( this.$index && this.$total && this.$filename ) {
  8535. this.$index.text( index + 1 );
  8536. this.$total.text( queue.length );
  8537. this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
  8538. }
  8539. },
  8540. /**
  8541. * @param {string} filename
  8542. * @return {string}
  8543. */
  8544. filename: function( filename ) {
  8545. return _.escape( filename );
  8546. },
  8547. /**
  8548. * @param {Backbone.Model} error
  8549. */
  8550. error: function( error ) {
  8551. var statusError = new wp.media.view.UploaderStatusError( {
  8552. filename: this.filename( error.get( 'file' ).name ),
  8553. message: error.get( 'message' )
  8554. } );
  8555. var buttonClose = this.$el.find( 'button' );
  8556. // Can show additional info here while retrying to create image sub-sizes.
  8557. this.views.add( '.upload-errors', statusError, { at: 0 } );
  8558. _.delay( function() {
  8559. buttonClose.trigger( 'focus' );
  8560. wp.a11y.speak( error.get( 'message' ), 'assertive' );
  8561. }, 1000 );
  8562. },
  8563. dismiss: function() {
  8564. var errors = this.views.get('.upload-errors');
  8565. if ( errors ) {
  8566. _.invoke( errors, 'remove' );
  8567. }
  8568. wp.Uploader.errors.reset();
  8569. // Move focus to the modal after the dismiss button gets removed from the DOM.
  8570. if ( this.controller.modal ) {
  8571. this.controller.modal.focusManager.focus();
  8572. }
  8573. }
  8574. });
  8575. module.exports = UploaderStatus;
  8576. /***/ }),
  8577. /***/ 5823:
  8578. /***/ (function(module) {
  8579. var $ = jQuery,
  8580. UploaderWindow;
  8581. /**
  8582. * wp.media.view.UploaderWindow
  8583. *
  8584. * An uploader window that allows for dragging and dropping media.
  8585. *
  8586. * @memberOf wp.media.view
  8587. *
  8588. * @class
  8589. * @augments wp.media.View
  8590. * @augments wp.Backbone.View
  8591. * @augments Backbone.View
  8592. *
  8593. * @param {object} [options] Options hash passed to the view.
  8594. * @param {object} [options.uploader] Uploader properties.
  8595. * @param {jQuery} [options.uploader.browser]
  8596. * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
  8597. * @param {object} [options.uploader.params]
  8598. */
  8599. UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
  8600. tagName: 'div',
  8601. className: 'uploader-window',
  8602. template: wp.template('uploader-window'),
  8603. initialize: function() {
  8604. var uploader;
  8605. this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
  8606. uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
  8607. dropzone: this.$el,
  8608. browser: this.$browser,
  8609. params: {}
  8610. });
  8611. // Ensure the dropzone is a jQuery collection.
  8612. if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
  8613. uploader.dropzone = $( uploader.dropzone );
  8614. }
  8615. this.controller.on( 'activate', this.refresh, this );
  8616. this.controller.on( 'detach', function() {
  8617. this.$browser.remove();
  8618. }, this );
  8619. },
  8620. refresh: function() {
  8621. if ( this.uploader ) {
  8622. this.uploader.refresh();
  8623. }
  8624. },
  8625. ready: function() {
  8626. var postId = wp.media.view.settings.post.id,
  8627. dropzone;
  8628. // If the uploader already exists, bail.
  8629. if ( this.uploader ) {
  8630. return;
  8631. }
  8632. if ( postId ) {
  8633. this.options.uploader.params.post_id = postId;
  8634. }
  8635. this.uploader = new wp.Uploader( this.options.uploader );
  8636. dropzone = this.uploader.dropzone;
  8637. dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
  8638. dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
  8639. $( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
  8640. },
  8641. _ready: function() {
  8642. this.controller.trigger( 'uploader:ready' );
  8643. },
  8644. show: function() {
  8645. var $el = this.$el.show();
  8646. // Ensure that the animation is triggered by waiting until
  8647. // the transparent element is painted into the DOM.
  8648. _.defer( function() {
  8649. $el.css({ opacity: 1 });
  8650. });
  8651. },
  8652. hide: function() {
  8653. var $el = this.$el.css({ opacity: 0 });
  8654. wp.media.transition( $el ).done( function() {
  8655. // Transition end events are subject to race conditions.
  8656. // Make sure that the value is set as intended.
  8657. if ( '0' === $el.css('opacity') ) {
  8658. $el.hide();
  8659. }
  8660. });
  8661. // https://core.trac.wordpress.org/ticket/27341
  8662. _.delay( function() {
  8663. if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
  8664. $el.hide();
  8665. }
  8666. }, 500 );
  8667. }
  8668. });
  8669. module.exports = UploaderWindow;
  8670. /***/ }),
  8671. /***/ 487:
  8672. /***/ (function(module) {
  8673. /**
  8674. * wp.media.View
  8675. *
  8676. * The base view class for media.
  8677. *
  8678. * Undelegating events, removing events from the model, and
  8679. * removing events from the controller mirror the code for
  8680. * `Backbone.View.dispose` in Backbone 0.9.8 development.
  8681. *
  8682. * This behavior has since been removed, and should not be used
  8683. * outside of the media manager.
  8684. *
  8685. * @memberOf wp.media
  8686. *
  8687. * @class
  8688. * @augments wp.Backbone.View
  8689. * @augments Backbone.View
  8690. */
  8691. var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
  8692. constructor: function( options ) {
  8693. if ( options && options.controller ) {
  8694. this.controller = options.controller;
  8695. }
  8696. wp.Backbone.View.apply( this, arguments );
  8697. },
  8698. /**
  8699. * @todo The internal comment mentions this might have been a stop-gap
  8700. * before Backbone 0.9.8 came out. Figure out if Backbone core takes
  8701. * care of this in Backbone.View now.
  8702. *
  8703. * @return {wp.media.View} Returns itself to allow chaining.
  8704. */
  8705. dispose: function() {
  8706. /*
  8707. * Undelegating events, removing events from the model, and
  8708. * removing events from the controller mirror the code for
  8709. * `Backbone.View.dispose` in Backbone 0.9.8 development.
  8710. */
  8711. this.undelegateEvents();
  8712. if ( this.model && this.model.off ) {
  8713. this.model.off( null, null, this );
  8714. }
  8715. if ( this.collection && this.collection.off ) {
  8716. this.collection.off( null, null, this );
  8717. }
  8718. // Unbind controller events.
  8719. if ( this.controller && this.controller.off ) {
  8720. this.controller.off( null, null, this );
  8721. }
  8722. return this;
  8723. },
  8724. /**
  8725. * @return {wp.media.View} Returns itself to allow chaining.
  8726. */
  8727. remove: function() {
  8728. this.dispose();
  8729. /**
  8730. * call 'remove' directly on the parent class
  8731. */
  8732. return wp.Backbone.View.prototype.remove.apply( this, arguments );
  8733. }
  8734. });
  8735. module.exports = View;
  8736. /***/ })
  8737. /******/ });
  8738. /************************************************************************/
  8739. /******/ // The module cache
  8740. /******/ var __webpack_module_cache__ = {};
  8741. /******/
  8742. /******/ // The require function
  8743. /******/ function __webpack_require__(moduleId) {
  8744. /******/ // Check if module is in cache
  8745. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  8746. /******/ if (cachedModule !== undefined) {
  8747. /******/ return cachedModule.exports;
  8748. /******/ }
  8749. /******/ // Create a new module (and put it into the cache)
  8750. /******/ var module = __webpack_module_cache__[moduleId] = {
  8751. /******/ // no module.id needed
  8752. /******/ // no module.loaded needed
  8753. /******/ exports: {}
  8754. /******/ };
  8755. /******/
  8756. /******/ // Execute the module function
  8757. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  8758. /******/
  8759. /******/ // Return the exports of the module
  8760. /******/ return module.exports;
  8761. /******/ }
  8762. /******/
  8763. /************************************************************************/
  8764. var __webpack_exports__ = {};
  8765. // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
  8766. !function() {
  8767. /**
  8768. * @output wp-includes/js/media-views.js
  8769. */
  8770. var media = wp.media,
  8771. $ = jQuery,
  8772. l10n;
  8773. media.isTouchDevice = ( 'ontouchend' in document );
  8774. // Link any localized strings.
  8775. l10n = media.view.l10n = window._wpMediaViewsL10n || {};
  8776. // Link any settings.
  8777. media.view.settings = l10n.settings || {};
  8778. delete l10n.settings;
  8779. // Copy the `post` setting over to the model settings.
  8780. media.model.settings.post = media.view.settings.post;
  8781. // Check if the browser supports CSS 3.0 transitions.
  8782. $.support.transition = (function(){
  8783. var style = document.documentElement.style,
  8784. transitions = {
  8785. WebkitTransition: 'webkitTransitionEnd',
  8786. MozTransition: 'transitionend',
  8787. OTransition: 'oTransitionEnd otransitionend',
  8788. transition: 'transitionend'
  8789. }, transition;
  8790. transition = _.find( _.keys( transitions ), function( transition ) {
  8791. return ! _.isUndefined( style[ transition ] );
  8792. });
  8793. return transition && {
  8794. end: transitions[ transition ]
  8795. };
  8796. }());
  8797. /**
  8798. * A shared event bus used to provide events into
  8799. * the media workflows that 3rd-party devs can use to hook
  8800. * in.
  8801. */
  8802. media.events = _.extend( {}, Backbone.Events );
  8803. /**
  8804. * Makes it easier to bind events using transitions.
  8805. *
  8806. * @param {string} selector
  8807. * @param {number} sensitivity
  8808. * @return {Promise}
  8809. */
  8810. media.transition = function( selector, sensitivity ) {
  8811. var deferred = $.Deferred();
  8812. sensitivity = sensitivity || 2000;
  8813. if ( $.support.transition ) {
  8814. if ( ! (selector instanceof $) ) {
  8815. selector = $( selector );
  8816. }
  8817. // Resolve the deferred when the first element finishes animating.
  8818. selector.first().one( $.support.transition.end, deferred.resolve );
  8819. // Just in case the event doesn't trigger, fire a callback.
  8820. _.delay( deferred.resolve, sensitivity );
  8821. // Otherwise, execute on the spot.
  8822. } else {
  8823. deferred.resolve();
  8824. }
  8825. return deferred.promise();
  8826. };
  8827. media.controller.Region = __webpack_require__( 4903 );
  8828. media.controller.StateMachine = __webpack_require__( 5466 );
  8829. media.controller.State = __webpack_require__( 5826 );
  8830. media.selectionSync = __webpack_require__( 3526 );
  8831. media.controller.Library = __webpack_require__( 9024 );
  8832. media.controller.ImageDetails = __webpack_require__( 3849 );
  8833. media.controller.GalleryEdit = __webpack_require__( 6328 );
  8834. media.controller.GalleryAdd = __webpack_require__( 7323 );
  8835. media.controller.CollectionEdit = __webpack_require__( 1817 );
  8836. media.controller.CollectionAdd = __webpack_require__( 1517 );
  8837. media.controller.FeaturedImage = __webpack_require__( 5095 );
  8838. media.controller.ReplaceImage = __webpack_require__( 8493 );
  8839. media.controller.EditImage = __webpack_require__( 7658 );
  8840. media.controller.MediaLibrary = __webpack_require__( 3742 );
  8841. media.controller.Embed = __webpack_require__( 9067 );
  8842. media.controller.Cropper = __webpack_require__( 2288 );
  8843. media.controller.CustomizeImageCropper = __webpack_require__( 6934 );
  8844. media.controller.SiteIconCropper = __webpack_require__( 5274 );
  8845. media.View = __webpack_require__( 487 );
  8846. media.view.Frame = __webpack_require__( 3647 );
  8847. media.view.MediaFrame = __webpack_require__( 4861 );
  8848. media.view.MediaFrame.Select = __webpack_require__( 8719 );
  8849. media.view.MediaFrame.Post = __webpack_require__( 9075 );
  8850. media.view.MediaFrame.ImageDetails = __webpack_require__( 9142 );
  8851. media.view.Modal = __webpack_require__( 3939 );
  8852. media.view.FocusManager = __webpack_require__( 6557 );
  8853. media.view.UploaderWindow = __webpack_require__( 5823 );
  8854. media.view.EditorUploader = __webpack_require__( 841 );
  8855. media.view.UploaderInline = __webpack_require__( 6353 );
  8856. media.view.UploaderStatus = __webpack_require__( 2894 );
  8857. media.view.UploaderStatusError = __webpack_require__( 9411 );
  8858. media.view.Toolbar = __webpack_require__( 9510 );
  8859. media.view.Toolbar.Select = __webpack_require__( 6850 );
  8860. media.view.Toolbar.Embed = __webpack_require__( 7128 );
  8861. media.view.Button = __webpack_require__( 3157 );
  8862. media.view.ButtonGroup = __webpack_require__( 4094 );
  8863. media.view.PriorityList = __webpack_require__( 1993 );
  8864. media.view.MenuItem = __webpack_require__( 917 );
  8865. media.view.Menu = __webpack_require__( 2596 );
  8866. media.view.RouterItem = __webpack_require__( 9484 );
  8867. media.view.Router = __webpack_require__( 1562 );
  8868. media.view.Sidebar = __webpack_require__( 9799 );
  8869. media.view.Attachment = __webpack_require__( 5019 );
  8870. media.view.Attachment.Library = __webpack_require__( 9254 );
  8871. media.view.Attachment.EditLibrary = __webpack_require__( 4640 );
  8872. media.view.Attachments = __webpack_require__( 8408 );
  8873. media.view.Search = __webpack_require__( 4556 );
  8874. media.view.AttachmentFilters = __webpack_require__( 4906 );
  8875. media.view.DateFilter = __webpack_require__( 9663 );
  8876. media.view.AttachmentFilters.Uploaded = __webpack_require__( 7040 );
  8877. media.view.AttachmentFilters.All = __webpack_require__( 2868 );
  8878. media.view.AttachmentsBrowser = __webpack_require__( 9239 );
  8879. media.view.Selection = __webpack_require__( 6191 );
  8880. media.view.Attachment.Selection = __webpack_require__( 9003 );
  8881. media.view.Attachments.Selection = __webpack_require__( 1223 );
  8882. media.view.Attachment.EditSelection = __webpack_require__( 1009 );
  8883. media.view.Settings = __webpack_require__( 859 );
  8884. media.view.Settings.AttachmentDisplay = __webpack_require__( 2176 );
  8885. media.view.Settings.Gallery = __webpack_require__( 6872 );
  8886. media.view.Settings.Playlist = __webpack_require__( 8488 );
  8887. media.view.Attachment.Details = __webpack_require__( 7274 );
  8888. media.view.AttachmentCompat = __webpack_require__( 8093 );
  8889. media.view.Iframe = __webpack_require__( 6217 );
  8890. media.view.Embed = __webpack_require__( 5138 );
  8891. media.view.Label = __webpack_require__( 6644 );
  8892. media.view.EmbedUrl = __webpack_require__( 4848 );
  8893. media.view.EmbedLink = __webpack_require__( 6959 );
  8894. media.view.EmbedImage = __webpack_require__( 1338 );
  8895. media.view.ImageDetails = __webpack_require__( 7598 );
  8896. media.view.Cropper = __webpack_require__( 7137 );
  8897. media.view.SiteIconCropper = __webpack_require__( 5187 );
  8898. media.view.SiteIconPreview = __webpack_require__( 8260 );
  8899. media.view.EditImage = __webpack_require__( 5970 );
  8900. media.view.Spinner = __webpack_require__( 2234 );
  8901. media.view.Heading = __webpack_require__( 7990 );
  8902. }();
  8903. /******/ })()
  8904. ;