modernizr-exclude.js 309 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013
  1. /*!
  2. * modernizr v3.7.0
  3. * Build https://modernizr.com/download?-adownload-ambientlight-apng-appearance-arrow-atobbtoa-audio-audioautoplay-audioloop-audiopreload-backdropfilter-backgroundblendmode-backgroundcliptext-backgroundsize-batteryapi-bdi-beacon-bgpositionshorthand-bgpositionxy-bgrepeatspace_bgrepeatround-bgsizecover-blobconstructor-bloburls-blobworkers-borderimage-borderradius-boxdecorationbreak-boxshadow-boxsizing-canvas-canvasblending-canvastext-canvaswinding-capture-checked-classlist-connectioneffectivetype-contains-contenteditable-contextmenu-cookies-cors-createelementattrs_createelement_attrs-cryptography-cssall-cssanimations-csscalc-csschunit-csscolumns-cssescape-cssexunit-cssfilters-cssgradients-cssgrid_cssgridlegacy-csshyphens_softhyphens_softhyphensfind-cssinvalid-cssmask-csspointerevents-csspositionsticky-csspseudoanimations-csspseudotransitions-cssreflections-cssremunit-cssresize-cssscrollbar-csstransforms-csstransforms3d-csstransformslevel2-csstransitions-cssvalid-cssvhunit-cssvmaxunit-cssvminunit-cssvwunit-cubicbezierrange-customelements-customevent-customproperties-customprotocolhandler-dart-datachannel-datalistelem-dataset-datauri-dataview-dataworkers-details-devicemotion_deviceorientation-directory-display_runin-displaytable-documentfragment-ellipsis-es5-es5array-es5date-es5function-es5object-es5string-es5syntax-es5undefined-es6array-es6collections-es6math-es6number-es6object-es6string-eventlistener-eventsource-exiforientation-fetch-fileinput-filereader-filesystem-flash-flexbox-flexboxlegacy-flexboxtweener-flexwrap-focuswithin-fontdisplay-fontface-forcetouch-formattribute-formvalidation-framed-fullscreen-gamepads-generatedcontent-generators-geolocation-getrandomvalues-getusermedia-hairline-hashchange-hidden-hiddenscroll-history-hovermq-hsla-htmlimports-ie8compat-imgcrossorigin-indexeddb-indexeddbblob-inlinesvg-input-inputformaction-inputformenctype-inputformmethod-inputformnovalidate-inputformtarget-inputsearchevent-inputtypes-intersectionobserver-intl-jpeg2000-jpegxr-json-lastchild-ligatures-localizednumber-localstorage-lowbandwidth-lowbattery-matchmedia-mathml-mediaqueries-mediasource-messagechannel-microdata-multiplebgs-mutationobserver-nthchild-objectfit-olreversed-oninput-opacity-outputelem-overflowscrolling-pagevisibility-passiveeventlisteners-peerconnection-performance-picture-placeholder-pointerevents-pointerlock-pointermq-postmessage-preserve3d-progressbar_meter-promises-proximity-publicKeyCredential-queryselector-quotamanagement-regions-requestanimationframe-requestautocomplete-rgba-ruby-sandbox-scriptasync-scriptdefer-scrollsnappoints-seamless-serviceworker-sessionstorage-shapes-sharedworkers-siblinggeneral-sizes-smil-speechrecognition-speechsynthesis-srcdoc-srcset-strictmode-stylescoped-subpixelfont-supports-svg-svgasimg-svgclippaths-svgfilters-svgforeignobject-target-template-templatestrings-textalignlast-textareamaxlength-textdecoration-textshadow-texttrackapi_track-time-todataurljpeg_todataurlpng_todataurlwebp-touchevents-transferables-typedarrays-unicode-unicoderange-unknownelements-urlparser-urlsearchparams-userdata-userselect-variablefonts-vibrate-video-videoautoplay-videocrossorigin-videoloop-videopreload-vml-webanimations-webaudio-webgl-webglextensions-webintents-webp-webpalpha-webpanimation-webplossless_webp_lossless-websockets-websocketsbinary-websqldatabase-webworkers-willchange-wrapflow-xdomainrequest-xhr2-xhrresponsetype-xhrresponsetypearraybuffer-xhrresponsetypeblob-xhrresponsetypedocument-xhrresponsetypejson-xhrresponsetypetext-addtest-printshiv-setclasses-testprop-dontmin
  4. *
  5. * Copyright (c)
  6. * Faruk Ates
  7. * Paul Irish
  8. * Alex Sexton
  9. * Ryan Seddon
  10. * Patrick Kettner
  11. * Stu Cox
  12. * Richard Herrera
  13. * MIT License
  14. */
  15. /*
  16. * Modernizr tests which native CSS3 and HTML5 features are available in the
  17. * current UA and makes the results available to you in two ways: as properties on
  18. * a global `Modernizr` object, and as classes on the `<html>` element. This
  19. * information allows you to progressively enhance your pages with a granular level
  20. * of control over the experience.
  21. */
  22. ;(function(window, document, undefined){
  23. var tests = [];
  24. /**
  25. * ModernizrProto is the constructor for Modernizr
  26. *
  27. * @class
  28. * @access public
  29. */
  30. var ModernizrProto = {
  31. // The current version, dummy
  32. _version: '3.7.0',
  33. // Any settings that don't work as separate modules
  34. // can go in here as configuration.
  35. _config: {
  36. 'classPrefix': '',
  37. 'enableClasses': true,
  38. 'enableJSClass': true,
  39. 'usePrefixes': true
  40. },
  41. // Queue of tests
  42. _q: [],
  43. // Stub these for people who are listening
  44. on: function(test, cb) {
  45. // I don't really think people should do this, but we can
  46. // safe guard it a bit.
  47. // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
  48. // This is in case people listen to synchronous tests. I would leave it out,
  49. // but the code to *disallow* sync tests in the real version of this
  50. // function is actually larger than this.
  51. var self = this;
  52. setTimeout(function() {
  53. cb(self[test]);
  54. }, 0);
  55. },
  56. addTest: function(name, fn, options) {
  57. tests.push({name: name, fn: fn, options: options});
  58. },
  59. addAsyncTest: function(fn) {
  60. tests.push({name: null, fn: fn});
  61. }
  62. };
  63. // Fake some of Object.create so we can force non test results to be non "own" properties.
  64. var Modernizr = function() {};
  65. Modernizr.prototype = ModernizrProto;
  66. // Leak modernizr globally when you `require` it rather than force it here.
  67. // Overwrite name so constructor name is nicer :D
  68. Modernizr = new Modernizr();
  69. var classes = [];
  70. /**
  71. * is returns a boolean if the typeof an obj is exactly type.
  72. *
  73. * @access private
  74. * @function is
  75. * @param {*} obj - A thing we want to check the type of
  76. * @param {string} type - A string to compare the typeof against
  77. * @returns {boolean} true if the typeof the first parameter is exactly the specified type, false otherwise
  78. */
  79. function is(obj, type) {
  80. return typeof obj === type;
  81. }
  82. ;
  83. /**
  84. * Run through all tests and detect their support in the current UA.
  85. *
  86. * @access private
  87. * @returns {void}
  88. */
  89. function testRunner() {
  90. var featureNames;
  91. var feature;
  92. var aliasIdx;
  93. var result;
  94. var nameIdx;
  95. var featureName;
  96. var featureNameSplit;
  97. for (var featureIdx in tests) {
  98. if (tests.hasOwnProperty(featureIdx)) {
  99. featureNames = [];
  100. feature = tests[featureIdx];
  101. // run the test, throw the return value into the Modernizr,
  102. // then based on that boolean, define an appropriate className
  103. // and push it into an array of classes we'll join later.
  104. //
  105. // If there is no name, it's an 'async' test that is run,
  106. // but not directly added to the object. That should
  107. // be done with a post-run addTest call.
  108. if (feature.name) {
  109. featureNames.push(feature.name.toLowerCase());
  110. if (feature.options && feature.options.aliases && feature.options.aliases.length) {
  111. // Add all the aliases into the names list
  112. for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
  113. featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
  114. }
  115. }
  116. }
  117. // Run the test, or use the raw value if it's not a function
  118. result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
  119. // Set each of the names on the Modernizr object
  120. for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
  121. featureName = featureNames[nameIdx];
  122. // Support dot properties as sub tests. We don't do checking to make sure
  123. // that the implied parent tests have been added. You must call them in
  124. // order (either in the test, or make the parent test a dependency).
  125. //
  126. // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
  127. // hashtag famous last words
  128. featureNameSplit = featureName.split('.');
  129. if (featureNameSplit.length === 1) {
  130. Modernizr[featureNameSplit[0]] = result;
  131. } else {
  132. // cast to a Boolean, if not one already
  133. if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
  134. Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
  135. }
  136. Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
  137. }
  138. classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
  139. }
  140. }
  141. }
  142. }
  143. ;
  144. /**
  145. * docElement is a convenience wrapper to grab the root element of the document
  146. *
  147. * @access private
  148. * @returns {HTMLElement|SVGElement} The root element of the document
  149. */
  150. var docElement = document.documentElement;
  151. /**
  152. * A convenience helper to check if the document we are running in is an SVG document
  153. *
  154. * @access private
  155. * @returns {boolean}
  156. */
  157. var isSVG = docElement.nodeName.toLowerCase() === 'svg';
  158. /**
  159. * setClasses takes an array of class names and adds them to the root element
  160. *
  161. * @access private
  162. * @function setClasses
  163. * @param {string[]} classes - Array of class names
  164. */
  165. // Pass in an and array of class names, e.g.:
  166. // ['no-webp', 'borderradius', ...]
  167. function setClasses(classes) {
  168. var className = docElement.className;
  169. var classPrefix = Modernizr._config.classPrefix || '';
  170. if (isSVG) {
  171. className = className.baseVal;
  172. }
  173. // Change `no-js` to `js` (independently of the `enableClasses` option)
  174. // Handle classPrefix on this too
  175. if (Modernizr._config.enableJSClass) {
  176. var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
  177. className = className.replace(reJS, '$1' + classPrefix + 'js$2');
  178. }
  179. if (Modernizr._config.enableClasses) {
  180. // Add the new classes
  181. if (classes.length > 0) {
  182. className += ' ' + classPrefix + classes.join(' ' + classPrefix);
  183. }
  184. if (isSVG) {
  185. docElement.className.baseVal = className;
  186. } else {
  187. docElement.className = className;
  188. }
  189. }
  190. }
  191. ;
  192. /**
  193. * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
  194. *
  195. * @author kangax
  196. * @access private
  197. * @function hasOwnProp
  198. * @param {object} object - The object to check for a property
  199. * @param {string} property - The property to check for
  200. * @returns {boolean}
  201. */
  202. // hasOwnProperty shim by kangax needed for Safari 2.0 support
  203. var hasOwnProp;
  204. (function() {
  205. var _hasOwnProperty = ({}).hasOwnProperty;
  206. /* istanbul ignore else */
  207. /* we have no way of testing IE 5.5 or safari 2,
  208. * so just assume the else gets hit */
  209. if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
  210. hasOwnProp = function(object, property) {
  211. return _hasOwnProperty.call(object, property);
  212. };
  213. }
  214. else {
  215. hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
  216. return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
  217. };
  218. }
  219. })();
  220. // _l tracks listeners for async tests, as well as tests that execute after the initial run
  221. ModernizrProto._l = {};
  222. /**
  223. * Modernizr.on is a way to listen for the completion of async tests. Being
  224. * asynchronous, they may not finish before your scripts run. As a result you
  225. * will get a possibly false negative `undefined` value.
  226. *
  227. * @memberOf Modernizr
  228. * @name Modernizr.on
  229. * @access public
  230. * @function on
  231. * @param {string} feature - String name of the feature detect
  232. * @param {Function} cb - Callback function returning a Boolean - true if feature is supported, false if not
  233. * @returns {void}
  234. * @example
  235. *
  236. * ```js
  237. * Modernizr.on('flash', function( result ) {
  238. * if (result) {
  239. * // the browser has flash
  240. * } else {
  241. * // the browser does not have flash
  242. * }
  243. * });
  244. * ```
  245. */
  246. ModernizrProto.on = function(feature, cb) {
  247. // Create the list of listeners if it doesn't exist
  248. if (!this._l[feature]) {
  249. this._l[feature] = [];
  250. }
  251. // Push this test on to the listener list
  252. this._l[feature].push(cb);
  253. // If it's already been resolved, trigger it on next tick
  254. if (Modernizr.hasOwnProperty(feature)) {
  255. // Next Tick
  256. setTimeout(function() {
  257. Modernizr._trigger(feature, Modernizr[feature]);
  258. }, 0);
  259. }
  260. };
  261. /**
  262. * _trigger is the private function used to signal test completion and run any
  263. * callbacks registered through [Modernizr.on](#modernizr-on)
  264. *
  265. * @memberOf Modernizr
  266. * @name Modernizr._trigger
  267. * @access private
  268. * @function _trigger
  269. * @param {string} feature - string name of the feature detect
  270. * @param {Function|boolean} [res] - A feature detection function, or the boolean =
  271. * result of a feature detection function
  272. * @returns {void}
  273. */
  274. ModernizrProto._trigger = function(feature, res) {
  275. if (!this._l[feature]) {
  276. return;
  277. }
  278. var cbs = this._l[feature];
  279. // Force async
  280. setTimeout(function() {
  281. var i, cb;
  282. for (i = 0; i < cbs.length; i++) {
  283. cb = cbs[i];
  284. cb(res);
  285. }
  286. }, 0);
  287. // Don't trigger these again
  288. delete this._l[feature];
  289. };
  290. /**
  291. * addTest allows you to define your own feature detects that are not currently
  292. * included in Modernizr (under the covers it's the exact same code Modernizr
  293. * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)).
  294. * Just like the official detects, the result
  295. * will be added onto the Modernizr object, as well as an appropriate className set on
  296. * the html element when configured to do so
  297. *
  298. * @memberOf Modernizr
  299. * @name Modernizr.addTest
  300. * @optionName Modernizr.addTest()
  301. * @optionProp addTest
  302. * @access public
  303. * @function addTest
  304. * @param {string|Object} feature - The string name of the feature detect, or an
  305. * object of feature detect names and test
  306. * @param {Function|boolean} test - Function returning true if feature is supported,
  307. * false if not. Otherwise a boolean representing the results of a feature detection
  308. * @returns {Object} the Modernizr object to allow chaining
  309. * @example
  310. *
  311. * The most common way of creating your own feature detects is by calling
  312. * `Modernizr.addTest` with a string (preferably just lowercase, without any
  313. * punctuation), and a function you want executed that will return a boolean result
  314. *
  315. * ```js
  316. * Modernizr.addTest('itsTuesday', function() {
  317. * var d = new Date();
  318. * return d.getDay() === 2;
  319. * });
  320. * ```
  321. *
  322. * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
  323. * and to `false` every other day of the week. One thing to notice is that the names of
  324. * feature detect functions are always lowercased when added to the Modernizr object. That
  325. * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
  326. *
  327. *
  328. * Since we only look at the returned value from any feature detection function,
  329. * you do not need to actually use a function. For simple detections, just passing
  330. * in a statement that will return a boolean value works just fine.
  331. *
  332. * ```js
  333. * Modernizr.addTest('hasjquery', 'jQuery' in window);
  334. * ```
  335. *
  336. * Just like before, when the above runs `Modernizr.hasjquery` will be true if
  337. * jQuery has been included on the page. Not using a function saves a small amount
  338. * of overhead for the browser, as well as making your code much more readable.
  339. *
  340. * Finally, you also have the ability to pass in an object of feature names and
  341. * their tests. This is handy if you want to add multiple detections in one go.
  342. * The keys should always be a string, and the value can be either a boolean or
  343. * function that returns a boolean.
  344. *
  345. * ```js
  346. * var detects = {
  347. * 'hasjquery': 'jQuery' in window,
  348. * 'itstuesday': function() {
  349. * var d = new Date();
  350. * return d.getDay() === 2;
  351. * }
  352. * }
  353. *
  354. * Modernizr.addTest(detects);
  355. * ```
  356. *
  357. * There is really no difference between the first methods and this one, it is
  358. * just a convenience to let you write more readable code.
  359. */
  360. function addTest(feature, test) {
  361. if (typeof feature === 'object') {
  362. for (var key in feature) {
  363. if (hasOwnProp(feature, key)) {
  364. addTest(key, feature[ key ]);
  365. }
  366. }
  367. } else {
  368. feature = feature.toLowerCase();
  369. var featureNameSplit = feature.split('.');
  370. var last = Modernizr[featureNameSplit[0]];
  371. // Again, we don't check for parent test existence. Get that right, though.
  372. if (featureNameSplit.length === 2) {
  373. last = last[featureNameSplit[1]];
  374. }
  375. if (typeof last !== 'undefined') {
  376. // we're going to quit if you're trying to overwrite an existing test
  377. // if we were to allow it, we'd do this:
  378. // var re = new RegExp("\\b(no-)?" + feature + "\\b");
  379. // docElement.className = docElement.className.replace( re, '' );
  380. // but, no rly, stuff 'em.
  381. return Modernizr;
  382. }
  383. test = typeof test === 'function' ? test() : test;
  384. // Set the value (this is the magic, right here).
  385. if (featureNameSplit.length === 1) {
  386. Modernizr[featureNameSplit[0]] = test;
  387. } else {
  388. // cast to a Boolean, if not one already
  389. if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
  390. Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
  391. }
  392. Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
  393. }
  394. // Set a single class (either `feature` or `no-feature`)
  395. setClasses([(!!test && test !== false ? '' : 'no-') + featureNameSplit.join('-')]);
  396. // Trigger the event
  397. Modernizr._trigger(feature, test);
  398. }
  399. return Modernizr; // allow chaining.
  400. }
  401. // After all the tests are run, add self to the Modernizr prototype
  402. Modernizr._q.push(function() {
  403. ModernizrProto.addTest = addTest;
  404. });
  405. /**
  406. * @optionName html5printshiv
  407. * @optionProp html5printshiv
  408. */
  409. // Take the html5 variable out of the html5shiv scope so we can return it.
  410. var html5;
  411. if (!isSVG) {
  412. /**
  413. * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
  414. */
  415. ;(function(window, document) {
  416. /*jshint evil:true */
  417. /** version */
  418. var version = '3.7.3';
  419. /** Preset options */
  420. var options = window.html5 || {};
  421. /** Used to skip problem elements */
  422. var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
  423. /** Not all elements can be cloned in IE **/
  424. var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
  425. /** Detect whether the browser supports default html5 styles */
  426. var supportsHtml5Styles;
  427. /** Name of the expando, to work with multiple documents or to re-shiv one document */
  428. var expando = '_html5shiv';
  429. /** The id for the the documents expando */
  430. var expanID = 0;
  431. /** Cached data for each document */
  432. var expandoData = {};
  433. /** Detect whether the browser supports unknown elements */
  434. var supportsUnknownElements;
  435. (function() {
  436. try {
  437. var a = document.createElement('a');
  438. a.innerHTML = '<xyz></xyz>';
  439. //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
  440. supportsHtml5Styles = ('hidden' in a);
  441. supportsUnknownElements = a.childNodes.length == 1 || (function() {
  442. // assign a false positive if unable to shiv
  443. (document.createElement)('a');
  444. var frag = document.createDocumentFragment();
  445. return (
  446. typeof frag.cloneNode == 'undefined' ||
  447. typeof frag.createDocumentFragment == 'undefined' ||
  448. typeof frag.createElement == 'undefined'
  449. );
  450. }());
  451. } catch(e) {
  452. // assign a false positive if detection fails => unable to shiv
  453. supportsHtml5Styles = true;
  454. supportsUnknownElements = true;
  455. }
  456. }());
  457. /*--------------------------------------------------------------------------*/
  458. /**
  459. * Creates a style sheet with the given CSS text and adds it to the document.
  460. * @private
  461. * @param {Document} ownerDocument The document.
  462. * @param {String} cssText The CSS text.
  463. * @returns {StyleSheet} The style element.
  464. */
  465. function addStyleSheet(ownerDocument, cssText) {
  466. var p = ownerDocument.createElement('p'),
  467. parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
  468. p.innerHTML = 'x<style>' + cssText + '</style>';
  469. return parent.insertBefore(p.lastChild, parent.firstChild);
  470. }
  471. /**
  472. * Returns the value of `html5.elements` as an array.
  473. * @private
  474. * @returns {Array} An array of shived element node names.
  475. */
  476. function getElements() {
  477. var elements = html5.elements;
  478. return typeof elements == 'string' ? elements.split(' ') : elements;
  479. }
  480. /**
  481. * Extends the built-in list of html5 elements
  482. * @memberOf html5
  483. * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
  484. * @param {Document} ownerDocument The context document.
  485. */
  486. function addElements(newElements, ownerDocument) {
  487. var elements = html5.elements;
  488. if(typeof elements != 'string'){
  489. elements = elements.join(' ');
  490. }
  491. if(typeof newElements != 'string'){
  492. newElements = newElements.join(' ');
  493. }
  494. html5.elements = elements +' '+ newElements;
  495. shivDocument(ownerDocument);
  496. }
  497. /**
  498. * Returns the data associated to the given document
  499. * @private
  500. * @param {Document} ownerDocument The document.
  501. * @returns {Object} An object of data.
  502. */
  503. function getExpandoData(ownerDocument) {
  504. var data = expandoData[ownerDocument[expando]];
  505. if (!data) {
  506. data = {};
  507. expanID++;
  508. ownerDocument[expando] = expanID;
  509. expandoData[expanID] = data;
  510. }
  511. return data;
  512. }
  513. /**
  514. * returns a shived element for the given nodeName and document
  515. * @memberOf html5
  516. * @param {String} nodeName name of the element
  517. * @param {Document} ownerDocument The context document.
  518. * @returns {Object} The shived element.
  519. */
  520. function createElement(nodeName, ownerDocument, data){
  521. if (!ownerDocument) {
  522. ownerDocument = document;
  523. }
  524. if(supportsUnknownElements){
  525. return ownerDocument.createElement(nodeName);
  526. }
  527. if (!data) {
  528. data = getExpandoData(ownerDocument);
  529. }
  530. var node;
  531. if (data.cache[nodeName]) {
  532. node = data.cache[nodeName].cloneNode();
  533. } else if (saveClones.test(nodeName)) {
  534. node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
  535. } else {
  536. node = data.createElem(nodeName);
  537. }
  538. // Avoid adding some elements to fragments in IE < 9 because
  539. // * Attributes like `name` or `type` cannot be set/changed once an element
  540. // is inserted into a document/fragment
  541. // * Link elements with `src` attributes that are inaccessible, as with
  542. // a 403 response, will cause the tab/window to crash
  543. // * Script elements appended to fragments will execute when their `src`
  544. // or `text` property is set
  545. return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
  546. }
  547. /**
  548. * returns a shived DocumentFragment for the given document
  549. * @memberOf html5
  550. * @param {Document} ownerDocument The context document.
  551. * @returns {Object} The shived DocumentFragment.
  552. */
  553. function createDocumentFragment(ownerDocument, data){
  554. if (!ownerDocument) {
  555. ownerDocument = document;
  556. }
  557. if(supportsUnknownElements){
  558. return ownerDocument.createDocumentFragment();
  559. }
  560. data = data || getExpandoData(ownerDocument);
  561. var clone = data.frag.cloneNode(),
  562. i = 0,
  563. elems = getElements(),
  564. l = elems.length;
  565. for(;i<l;i++){
  566. clone.createElement(elems[i]);
  567. }
  568. return clone;
  569. }
  570. /**
  571. * Shivs the `createElement` and `createDocumentFragment` methods of the document.
  572. * @private
  573. * @param {Document|DocumentFragment} ownerDocument The document.
  574. * @param {Object} data of the document.
  575. */
  576. function shivMethods(ownerDocument, data) {
  577. if (!data.cache) {
  578. data.cache = {};
  579. data.createElem = ownerDocument.createElement;
  580. data.createFrag = ownerDocument.createDocumentFragment;
  581. data.frag = data.createFrag();
  582. }
  583. ownerDocument.createElement = function(nodeName) {
  584. //abort shiv
  585. if (!html5.shivMethods) {
  586. return data.createElem(nodeName);
  587. }
  588. return createElement(nodeName, ownerDocument, data);
  589. };
  590. ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
  591. 'var n=f.cloneNode(),c=n.createElement;' +
  592. 'h.shivMethods&&(' +
  593. // unroll the `createElement` calls
  594. getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
  595. data.createElem(nodeName);
  596. data.frag.createElement(nodeName);
  597. return 'c("' + nodeName + '")';
  598. }) +
  599. ');return n}'
  600. )(html5, data.frag);
  601. }
  602. /*--------------------------------------------------------------------------*/
  603. /**
  604. * Shivs the given document.
  605. * @memberOf html5
  606. * @param {Document} ownerDocument The document to shiv.
  607. * @returns {Document} The shived document.
  608. */
  609. function shivDocument(ownerDocument) {
  610. if (!ownerDocument) {
  611. ownerDocument = document;
  612. }
  613. var data = getExpandoData(ownerDocument);
  614. if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
  615. data.hasCSS = !!addStyleSheet(ownerDocument,
  616. // corrects block display not defined in IE6/7/8/9
  617. 'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
  618. // adds styling not present in IE6/7/8/9
  619. 'mark{background:#FF0;color:#000}' +
  620. // hides non-rendered elements
  621. 'template{display:none}'
  622. );
  623. }
  624. if (!supportsUnknownElements) {
  625. shivMethods(ownerDocument, data);
  626. }
  627. return ownerDocument;
  628. }
  629. /*--------------------------------------------------------------------------*/
  630. /**
  631. * The `html5` object is exposed so that more elements can be shived and
  632. * existing shiving can be detected on iframes.
  633. * @type Object
  634. * @example
  635. *
  636. * // options can be changed before the script is included
  637. * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
  638. */
  639. var html5 = {
  640. /**
  641. * An array or space separated string of node names of the elements to shiv.
  642. * @memberOf html5
  643. * @type Array|String
  644. */
  645. 'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
  646. /**
  647. * current version of html5shiv
  648. */
  649. 'version': version,
  650. /**
  651. * A flag to indicate that the HTML5 style sheet should be inserted.
  652. * @memberOf html5
  653. * @type Boolean
  654. */
  655. 'shivCSS': (options.shivCSS !== false),
  656. /**
  657. * Is equal to true if a browser supports creating unknown/HTML5 elements
  658. * @memberOf html5
  659. * @type boolean
  660. */
  661. 'supportsUnknownElements': supportsUnknownElements,
  662. /**
  663. * A flag to indicate that the document's `createElement` and `createDocumentFragment`
  664. * methods should be overwritten.
  665. * @memberOf html5
  666. * @type Boolean
  667. */
  668. 'shivMethods': (options.shivMethods !== false),
  669. /**
  670. * A string to describe the type of `html5` object ("default" or "default print").
  671. * @memberOf html5
  672. * @type String
  673. */
  674. 'type': 'default',
  675. // shivs the document according to the specified `html5` object options
  676. 'shivDocument': shivDocument,
  677. //creates a shived element
  678. createElement: createElement,
  679. //creates a shived documentFragment
  680. createDocumentFragment: createDocumentFragment,
  681. //extends list of elements
  682. addElements: addElements
  683. };
  684. /*--------------------------------------------------------------------------*/
  685. // expose html5
  686. window.html5 = html5;
  687. // shiv the document
  688. shivDocument(document);
  689. /*------------------------------- Print Shiv -------------------------------*/
  690. /** Used to filter media types */
  691. var reMedia = /^$|\b(?:all|print)\b/;
  692. /** Used to namespace printable elements */
  693. var shivNamespace = 'html5shiv';
  694. /** Detect whether the browser supports shivable style sheets */
  695. var supportsShivableSheets = !supportsUnknownElements && (function() {
  696. // assign a false negative if unable to shiv
  697. var docEl = document.documentElement;
  698. return !(
  699. typeof document.namespaces == 'undefined' ||
  700. typeof document.parentWindow == 'undefined' ||
  701. typeof docEl.applyElement == 'undefined' ||
  702. typeof docEl.removeNode == 'undefined' ||
  703. typeof window.attachEvent == 'undefined'
  704. );
  705. }());
  706. /*--------------------------------------------------------------------------*/
  707. /**
  708. * Wraps all HTML5 elements in the given document with printable elements.
  709. * (eg. the "header" element is wrapped with the "html5shiv:header" element)
  710. * @private
  711. * @param {Document} ownerDocument The document.
  712. * @returns {Array} An array wrappers added.
  713. */
  714. function addWrappers(ownerDocument) {
  715. var node,
  716. nodes = ownerDocument.getElementsByTagName('*'),
  717. index = nodes.length,
  718. reElements = RegExp('^(?:' + getElements().join('|') + ')$', 'i'),
  719. result = [];
  720. while (index--) {
  721. node = nodes[index];
  722. if (reElements.test(node.nodeName)) {
  723. result.push(node.applyElement(createWrapper(node)));
  724. }
  725. }
  726. return result;
  727. }
  728. /**
  729. * Creates a printable wrapper for the given element.
  730. * @private
  731. * @param {Element} element The element.
  732. * @returns {Element} The wrapper.
  733. */
  734. function createWrapper(element) {
  735. var node,
  736. nodes = element.attributes,
  737. index = nodes.length,
  738. wrapper = element.ownerDocument.createElement(shivNamespace + ':' + element.nodeName);
  739. // copy element attributes to the wrapper
  740. while (index--) {
  741. node = nodes[index];
  742. node.specified && wrapper.setAttribute(node.nodeName, node.nodeValue);
  743. }
  744. // copy element styles to the wrapper
  745. wrapper.style.cssText = element.style.cssText;
  746. return wrapper;
  747. }
  748. /**
  749. * Shivs the given CSS text.
  750. * (eg. header{} becomes html5shiv\:header{})
  751. * @private
  752. * @param {String} cssText The CSS text to shiv.
  753. * @returns {String} The shived CSS text.
  754. */
  755. function shivCssText(cssText) {
  756. var pair,
  757. parts = cssText.split('{'),
  758. index = parts.length,
  759. reElements = RegExp('(^|[\\s,>+~])(' + getElements().join('|') + ')(?=[[\\s,>+~#.:]|$)', 'gi'),
  760. replacement = '$1' + shivNamespace + '\\:$2';
  761. while (index--) {
  762. pair = parts[index] = parts[index].split('}');
  763. pair[pair.length - 1] = pair[pair.length - 1].replace(reElements, replacement);
  764. parts[index] = pair.join('}');
  765. }
  766. return parts.join('{');
  767. }
  768. /**
  769. * Removes the given wrappers, leaving the original elements.
  770. * @private
  771. * @params {Array} wrappers An array of printable wrappers.
  772. */
  773. function removeWrappers(wrappers) {
  774. var index = wrappers.length;
  775. while (index--) {
  776. wrappers[index].removeNode();
  777. }
  778. }
  779. /*--------------------------------------------------------------------------*/
  780. /**
  781. * Shivs the given document for print.
  782. * @memberOf html5
  783. * @param {Document} ownerDocument The document to shiv.
  784. * @returns {Document} The shived document.
  785. */
  786. function shivPrint(ownerDocument) {
  787. var shivedSheet,
  788. wrappers,
  789. data = getExpandoData(ownerDocument),
  790. namespaces = ownerDocument.namespaces,
  791. ownerWindow = ownerDocument.parentWindow;
  792. if (!supportsShivableSheets || ownerDocument.printShived) {
  793. return ownerDocument;
  794. }
  795. if (typeof namespaces[shivNamespace] == 'undefined') {
  796. namespaces.add(shivNamespace);
  797. }
  798. function removeSheet() {
  799. clearTimeout(data._removeSheetTimer);
  800. if (shivedSheet) {
  801. shivedSheet.removeNode(true);
  802. }
  803. shivedSheet= null;
  804. }
  805. ownerWindow.attachEvent('onbeforeprint', function() {
  806. removeSheet();
  807. var imports,
  808. length,
  809. sheet,
  810. collection = ownerDocument.styleSheets,
  811. cssText = [],
  812. index = collection.length,
  813. sheets = Array(index);
  814. // convert styleSheets collection to an array
  815. while (index--) {
  816. sheets[index] = collection[index];
  817. }
  818. // concat all style sheet CSS text
  819. while ((sheet = sheets.pop())) {
  820. // IE does not enforce a same origin policy for external style sheets...
  821. // but has trouble with some dynamically created stylesheets
  822. if (!sheet.disabled && reMedia.test(sheet.media)) {
  823. try {
  824. imports = sheet.imports;
  825. length = imports.length;
  826. } catch(er){
  827. length = 0;
  828. }
  829. for (index = 0; index < length; index++) {
  830. sheets.push(imports[index]);
  831. }
  832. try {
  833. cssText.push(sheet.cssText);
  834. } catch(er){}
  835. }
  836. }
  837. // wrap all HTML5 elements with printable elements and add the shived style sheet
  838. cssText = shivCssText(cssText.reverse().join(''));
  839. wrappers = addWrappers(ownerDocument);
  840. shivedSheet = addStyleSheet(ownerDocument, cssText);
  841. });
  842. ownerWindow.attachEvent('onafterprint', function() {
  843. // remove wrappers, leaving the original elements, and remove the shived style sheet
  844. removeWrappers(wrappers);
  845. clearTimeout(data._removeSheetTimer);
  846. data._removeSheetTimer = setTimeout(removeSheet, 500);
  847. });
  848. ownerDocument.printShived = true;
  849. return ownerDocument;
  850. }
  851. /*--------------------------------------------------------------------------*/
  852. // expose API
  853. html5.type += ' print';
  854. html5.shivPrint = shivPrint;
  855. // shiv for print
  856. shivPrint(document);
  857. if(typeof module == 'object' && module.exports){
  858. module.exports = html5;
  859. }
  860. }(typeof window !== "undefined" ? window : this, document));
  861. }
  862. ;
  863. /**
  864. * contains checks to see if a string contains another string
  865. *
  866. * @access private
  867. * @function contains
  868. * @param {string} str - The string we want to check for substrings
  869. * @param {string} substr - The substring we want to search the first string for
  870. * @returns {boolean} true if and only if the first string 'str' contains the second string 'substr'
  871. */
  872. function contains(str, substr) {
  873. return !!~('' + str).indexOf(substr);
  874. }
  875. ;
  876. /**
  877. * createElement is a convenience wrapper around document.createElement. Since we
  878. * use createElement all over the place, this allows for (slightly) smaller code
  879. * as well as abstracting away issues with creating elements in contexts other than
  880. * HTML documents (e.g. SVG documents).
  881. *
  882. * @access private
  883. * @function createElement
  884. * @returns {HTMLElement|SVGElement} An HTML or SVG element
  885. */
  886. function createElement() {
  887. if (typeof document.createElement !== 'function') {
  888. // This is the case in IE7, where the type of createElement is "object".
  889. // For this reason, we cannot call apply() as Object is not a Function.
  890. return document.createElement(arguments[0]);
  891. } else if (isSVG) {
  892. return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
  893. } else {
  894. return document.createElement.apply(document, arguments);
  895. }
  896. }
  897. ;
  898. /**
  899. * Create our "modernizr" element that we do most feature tests on.
  900. *
  901. * @access private
  902. */
  903. var modElem = {
  904. elem: createElement('modernizr')
  905. };
  906. // Clean up this element
  907. Modernizr._q.push(function() {
  908. delete modElem.elem;
  909. });
  910. var mStyle = {
  911. style: modElem.elem.style
  912. };
  913. // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
  914. // the front of the queue.
  915. Modernizr._q.unshift(function() {
  916. delete mStyle.style;
  917. });
  918. /**
  919. * getBody returns the body of a document, or an element that can stand in for
  920. * the body if a real body does not exist
  921. *
  922. * @access private
  923. * @function getBody
  924. * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
  925. * artificially created element that stands in for the body
  926. */
  927. function getBody() {
  928. // After page load injecting a fake body doesn't work so check if body exists
  929. var body = document.body;
  930. if (!body) {
  931. // Can't use the real body create a fake one.
  932. body = createElement(isSVG ? 'svg' : 'body');
  933. body.fake = true;
  934. }
  935. return body;
  936. }
  937. ;
  938. /**
  939. * injectElementWithStyles injects an element with style element and some CSS rules
  940. *
  941. * @access private
  942. * @function injectElementWithStyles
  943. * @param {string} rule - String representing a css rule
  944. * @param {Function} callback - A function that is used to test the injected element
  945. * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
  946. * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
  947. * @returns {boolean} the result of the specified callback test
  948. */
  949. function injectElementWithStyles(rule, callback, nodes, testnames) {
  950. var mod = 'modernizr';
  951. var style;
  952. var ret;
  953. var node;
  954. var docOverflow;
  955. var div = createElement('div');
  956. var body = getBody();
  957. if (parseInt(nodes, 10)) {
  958. // In order not to give false positives we create a node for each test
  959. // This also allows the method to scale for unspecified uses
  960. while (nodes--) {
  961. node = createElement('div');
  962. node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
  963. div.appendChild(node);
  964. }
  965. }
  966. style = createElement('style');
  967. style.type = 'text/css';
  968. style.id = 's' + mod;
  969. // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
  970. // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
  971. (!body.fake ? div : body).appendChild(style);
  972. body.appendChild(div);
  973. if (style.styleSheet) {
  974. style.styleSheet.cssText = rule;
  975. } else {
  976. style.appendChild(document.createTextNode(rule));
  977. }
  978. div.id = mod;
  979. if (body.fake) {
  980. //avoid crashing IE8, if background image is used
  981. body.style.background = '';
  982. //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
  983. body.style.overflow = 'hidden';
  984. docOverflow = docElement.style.overflow;
  985. docElement.style.overflow = 'hidden';
  986. docElement.appendChild(body);
  987. }
  988. ret = callback(div, rule);
  989. // If this is done after page load we don't want to remove the body so check if body exists
  990. if (body.fake) {
  991. body.parentNode.removeChild(body);
  992. docElement.style.overflow = docOverflow;
  993. // Trigger layout so kinetic scrolling isn't disabled in iOS6+
  994. // eslint-disable-next-line
  995. docElement.offsetHeight;
  996. } else {
  997. div.parentNode.removeChild(div);
  998. }
  999. return !!ret;
  1000. }
  1001. ;
  1002. /**
  1003. * domToCSS takes a camelCase string and converts it to kebab-case
  1004. * e.g. boxSizing -> box-sizing
  1005. *
  1006. * @access private
  1007. * @function domToCSS
  1008. * @param {string} name - String name of camelCase prop we want to convert
  1009. * @returns {string} The kebab-case version of the supplied name
  1010. */
  1011. function domToCSS(name) {
  1012. return name.replace(/([A-Z])/g, function(str, m1) {
  1013. return '-' + m1.toLowerCase();
  1014. }).replace(/^ms-/, '-ms-');
  1015. }
  1016. ;
  1017. /**
  1018. * wrapper around getComputedStyle, to fix issues with Firefox returning null when
  1019. * called inside of a hidden iframe
  1020. *
  1021. * @access private
  1022. * @function computedStyle
  1023. * @param {HTMLElement|SVGElement} elem - The element we want to find the computed styles of
  1024. * @param {string|null} [pseudo] - An optional pseudo element selector (e.g. :before), of null if none
  1025. * @param {string} prop - A CSS property
  1026. * @returns {CSSStyleDeclaration} the value of the specified CSS property
  1027. */
  1028. function computedStyle(elem, pseudo, prop) {
  1029. var result;
  1030. if ('getComputedStyle' in window) {
  1031. result = getComputedStyle.call(window, elem, pseudo);
  1032. var console = window.console;
  1033. if (result !== null) {
  1034. if (prop) {
  1035. result = result.getPropertyValue(prop);
  1036. }
  1037. } else {
  1038. if (console) {
  1039. var method = console.error ? 'error' : 'log';
  1040. console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate');
  1041. }
  1042. }
  1043. } else {
  1044. result = !pseudo && elem.currentStyle && elem.currentStyle[prop];
  1045. }
  1046. return result;
  1047. }
  1048. ;
  1049. /**
  1050. * nativeTestProps allows for us to use native feature detection functionality if available.
  1051. * some prefixed form, or false, in the case of an unsupported rule
  1052. *
  1053. * @access private
  1054. * @function nativeTestProps
  1055. * @param {array} props - An array of property names
  1056. * @param {string} value - A string representing the value we want to check via @supports
  1057. * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
  1058. */
  1059. // Accepts a list of property names and a single value
  1060. // Returns `undefined` if native detection not available
  1061. function nativeTestProps(props, value) {
  1062. var i = props.length;
  1063. // Start with the JS API: https://www.w3.org/TR/css3-conditional/#the-css-interface
  1064. if ('CSS' in window && 'supports' in window.CSS) {
  1065. // Try every prefixed variant of the property
  1066. while (i--) {
  1067. if (window.CSS.supports(domToCSS(props[i]), value)) {
  1068. return true;
  1069. }
  1070. }
  1071. return false;
  1072. }
  1073. // Otherwise fall back to at-rule (for Opera 12.x)
  1074. else if ('CSSSupportsRule' in window) {
  1075. // Build a condition string for every prefixed variant
  1076. var conditionText = [];
  1077. while (i--) {
  1078. conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
  1079. }
  1080. conditionText = conditionText.join(' or ');
  1081. return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
  1082. return computedStyle(node, null, 'position') === 'absolute';
  1083. });
  1084. }
  1085. return undefined;
  1086. }
  1087. ;
  1088. /**
  1089. * cssToDOM takes a kebab-case string and converts it to camelCase
  1090. * e.g. box-sizing -> boxSizing
  1091. *
  1092. * @access private
  1093. * @function cssToDOM
  1094. * @param {string} name - String name of kebab-case prop we want to convert
  1095. * @returns {string} The camelCase version of the supplied name
  1096. */
  1097. function cssToDOM(name) {
  1098. return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
  1099. return m1 + m2.toUpperCase();
  1100. }).replace(/^-/, '');
  1101. }
  1102. ;
  1103. // testProps is a generic CSS / DOM property test.
  1104. // In testing support for a given CSS property, it's legit to test:
  1105. // `elem.style[styleName] !== undefined`
  1106. // If the property is supported it will return an empty string,
  1107. // if unsupported it will return undefined.
  1108. // We'll take advantage of this quick test and skip setting a style
  1109. // on our modernizr element, but instead just testing undefined vs
  1110. // empty string.
  1111. // Property names can be provided in either camelCase or kebab-case.
  1112. function testProps(props, prefixed, value, skipValueTest) {
  1113. skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
  1114. // Try native detect first
  1115. if (!is(value, 'undefined')) {
  1116. var result = nativeTestProps(props, value);
  1117. if (!is(result, 'undefined')) {
  1118. return result;
  1119. }
  1120. }
  1121. // Otherwise do it properly
  1122. var afterInit, i, propsLength, prop, before;
  1123. // If we don't have a style element, that means we're running async or after
  1124. // the core tests, so we'll need to create our own elements to use
  1125. // inside of an SVG element, in certain browsers, the `style` element is only
  1126. // defined for valid tags. Therefore, if `modernizr` does not have one, we
  1127. // fall back to a less used element and hope for the best.
  1128. // for strict XHTML browsers the hardly used samp element is used
  1129. var elems = ['modernizr', 'tspan', 'samp'];
  1130. while (!mStyle.style && elems.length) {
  1131. afterInit = true;
  1132. mStyle.modElem = createElement(elems.shift());
  1133. mStyle.style = mStyle.modElem.style;
  1134. }
  1135. // Delete the objects if we created them.
  1136. function cleanElems() {
  1137. if (afterInit) {
  1138. delete mStyle.style;
  1139. delete mStyle.modElem;
  1140. }
  1141. }
  1142. propsLength = props.length;
  1143. for (i = 0; i < propsLength; i++) {
  1144. prop = props[i];
  1145. before = mStyle.style[prop];
  1146. if (contains(prop, '-')) {
  1147. prop = cssToDOM(prop);
  1148. }
  1149. if (mStyle.style[prop] !== undefined) {
  1150. // If value to test has been passed in, do a set-and-check test.
  1151. // 0 (integer) is a valid property value, so check that `value` isn't
  1152. // undefined, rather than just checking it's truthy.
  1153. if (!skipValueTest && !is(value, 'undefined')) {
  1154. // Needs a try catch block because of old IE. This is slow, but will
  1155. // be avoided in most cases because `skipValueTest` will be used.
  1156. try {
  1157. mStyle.style[prop] = value;
  1158. } catch (e) {}
  1159. // If the property value has changed, we assume the value used is
  1160. // supported. If `value` is empty string, it'll fail here (because
  1161. // it hasn't changed), which matches how browsers have implemented
  1162. // CSS.supports()
  1163. if (mStyle.style[prop] !== before) {
  1164. cleanElems();
  1165. return prefixed === 'pfx' ? prop : true;
  1166. }
  1167. }
  1168. // Otherwise just return true, or the property name if this is a
  1169. // `prefixed()` call
  1170. else {
  1171. cleanElems();
  1172. return prefixed === 'pfx' ? prop : true;
  1173. }
  1174. }
  1175. }
  1176. cleanElems();
  1177. return false;
  1178. }
  1179. ;
  1180. /**
  1181. * testProp() investigates whether a given style property is recognized
  1182. * Property names can be provided in either camelCase or kebab-case.
  1183. *
  1184. * @memberOf Modernizr
  1185. * @name Modernizr.testProp
  1186. * @access public
  1187. * @optionName Modernizr.testProp()
  1188. * @optionProp testProp
  1189. * @function testProp
  1190. * @param {string} prop - Name of the CSS property to check
  1191. * @param {string} [value] - Name of the CSS value to check
  1192. * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
  1193. * @returns {boolean} an empty string if the property is supported, undefined if its unsupported
  1194. * @example
  1195. *
  1196. * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
  1197. * version of the string.
  1198. *
  1199. * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
  1200. *
  1201. * ```js
  1202. * Modernizr.testProp('pointerEvents') // true
  1203. * ```
  1204. *
  1205. * You can also provide a value as an optional second argument to check if a
  1206. * specific value is supported
  1207. *
  1208. * ```js
  1209. * Modernizr.testProp('pointerEvents', 'none') // true
  1210. * Modernizr.testProp('pointerEvents', 'penguin') // false
  1211. * ```
  1212. */
  1213. var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
  1214. return testProps([prop], undefined, value, useValue);
  1215. };
  1216. /**
  1217. * Modernizr.hasEvent() detects support for a given event
  1218. *
  1219. * @memberOf Modernizr
  1220. * @name Modernizr.hasEvent
  1221. * @optionName Modernizr.hasEvent()
  1222. * @optionProp hasEvent
  1223. * @access public
  1224. * @function hasEvent
  1225. * @param {string|*} eventName - the name of an event to test for (e.g. "resize")
  1226. * @param {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
  1227. * @returns {boolean}
  1228. * @example
  1229. * `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
  1230. * By default, it does this detection on a div element
  1231. *
  1232. * ```js
  1233. * hasEvent('blur') // true;
  1234. * ```
  1235. *
  1236. * However, you are able to give an object as a second argument to hasEvent to
  1237. * detect an event on something other than a div.
  1238. *
  1239. * ```js
  1240. * hasEvent('devicelight', window) // true;
  1241. * ```
  1242. */
  1243. var hasEvent = (function() {
  1244. // Detect whether event support can be detected via `in`. Test on a DOM element
  1245. // using the "blur" event b/c it should always exist. bit.ly/event-detection
  1246. var needsFallback = !('onblur' in docElement);
  1247. function inner(eventName, element) {
  1248. var isSupported;
  1249. if (!eventName) { return false; }
  1250. if (!element || typeof element === 'string') {
  1251. element = createElement(element || 'div');
  1252. }
  1253. // Testing via the `in` operator is sufficient for modern browsers and IE.
  1254. // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
  1255. // "resize", whereas `in` "catches" those.
  1256. eventName = 'on' + eventName;
  1257. isSupported = eventName in element;
  1258. // Fallback technique for old Firefox - bit.ly/event-detection
  1259. if (!isSupported && needsFallback) {
  1260. if (!element.setAttribute) {
  1261. // Switch to generic element if it lacks `setAttribute`.
  1262. // It could be the `document`, `window`, or something else.
  1263. element = createElement('div');
  1264. }
  1265. element.setAttribute(eventName, '');
  1266. isSupported = typeof element[eventName] === 'function';
  1267. if (element[eventName] !== undefined) {
  1268. // If property was created, "remove it" by setting value to `undefined`.
  1269. element[eventName] = undefined;
  1270. }
  1271. element.removeAttribute(eventName);
  1272. }
  1273. return isSupported;
  1274. }
  1275. return inner;
  1276. })();
  1277. ModernizrProto.hasEvent = hasEvent;
  1278. /*!
  1279. {
  1280. "name": "Ambient Light Events",
  1281. "property": "ambientlight",
  1282. "notes": [{
  1283. "name": "W3C Spec",
  1284. "href": "https://www.w3.org/TR/ambient-light/"
  1285. }]
  1286. }
  1287. !*/
  1288. /* DOC
  1289. Detects support for the API that provides information about the ambient light levels, as detected by the device's light detector, in terms of lux units.
  1290. */
  1291. Modernizr.addTest('ambientlight', hasEvent('devicelight', window));
  1292. /*!
  1293. {
  1294. "name": "HTML5 Audio Element",
  1295. "property": "audio",
  1296. "tags": ["html5", "audio", "media"]
  1297. }
  1298. !*/
  1299. /* DOC
  1300. Detects the audio element
  1301. */
  1302. // This tests evaluates support of the audio element, as well as
  1303. // testing what types of content it supports.
  1304. //
  1305. // We're using the Boolean constructor here, so that we can extend the value
  1306. // e.g. Modernizr.audio // true
  1307. // Modernizr.audio.ogg // 'probably'
  1308. //
  1309. // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
  1310. // thx to NielsLeenheer and zcorpan
  1311. // Note: in some older browsers, "no" was a return value instead of empty string.
  1312. // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
  1313. // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
  1314. Modernizr.addTest('audio', function() {
  1315. var elem = createElement('audio');
  1316. var bool = false;
  1317. try {
  1318. bool = !!elem.canPlayType;
  1319. if (bool) {
  1320. bool = new Boolean(bool);
  1321. bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"') .replace(/^no$/, '');
  1322. bool.mp3 = elem.canPlayType('audio/mpeg; codecs="mp3"') .replace(/^no$/, '');
  1323. bool.opus = elem.canPlayType('audio/ogg; codecs="opus"') ||
  1324. elem.canPlayType('audio/webm; codecs="opus"') .replace(/^no$/, '');
  1325. // Mimetypes accepted:
  1326. // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
  1327. // bit.ly/iphoneoscodecs
  1328. bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/, '');
  1329. bool.m4a = (elem.canPlayType('audio/x-m4a;') ||
  1330. elem.canPlayType('audio/aac;')) .replace(/^no$/, '');
  1331. }
  1332. } catch (e) {}
  1333. return bool;
  1334. });
  1335. /**
  1336. * If the browsers follow the spec, then they would expose vendor-specific styles as:
  1337. * elem.style.WebkitBorderRadius
  1338. * instead of something like the following (which is technically incorrect):
  1339. * elem.style.webkitBorderRadius
  1340. * WebKit ghosts their properties in lowercase but Opera & Moz do not.
  1341. * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
  1342. * erik.eae.net/archives/2008/03/10/21.48.10/
  1343. * More here: github.com/Modernizr/Modernizr/issues/issue/21
  1344. *
  1345. * @access private
  1346. * @returns {string} The string representing the vendor-specific style properties
  1347. */
  1348. var omPrefixes = 'Moz O ms Webkit';
  1349. var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
  1350. ModernizrProto._cssomPrefixes = cssomPrefixes;
  1351. /**
  1352. * List of JavaScript DOM values used for tests
  1353. *
  1354. * @memberOf Modernizr
  1355. * @name Modernizr._domPrefixes
  1356. * @optionName Modernizr._domPrefixes
  1357. * @optionProp domPrefixes
  1358. * @access public
  1359. * @example
  1360. *
  1361. * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
  1362. * than kebab-case properties, all properties are their Capitalized variant
  1363. *
  1364. * ```js
  1365. * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
  1366. * ```
  1367. */
  1368. var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
  1369. ModernizrProto._domPrefixes = domPrefixes;
  1370. /**
  1371. * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
  1372. *
  1373. * @access private
  1374. * @function fnBind
  1375. * @param {Function} fn - a function you want to change `this` reference to
  1376. * @param {Object} that - the `this` you want to call the function with
  1377. * @returns {Function} The wrapped version of the supplied function
  1378. */
  1379. function fnBind(fn, that) {
  1380. return function() {
  1381. return fn.apply(that, arguments);
  1382. };
  1383. }
  1384. ;
  1385. /**
  1386. * testDOMProps is a generic DOM property test; if a browser supports
  1387. * a certain property, it won't return undefined for it.
  1388. *
  1389. * @access private
  1390. * @function testDOMProps
  1391. * @param {Array<string>} props - An array of properties to test for
  1392. * @param {Object} obj - An object or Element you want to use to test the parameters again
  1393. * @param {boolean|Object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
  1394. * @returns {false|*} returns false if the prop is unsupported, otherwise the value that is supported
  1395. */
  1396. function testDOMProps(props, obj, elem) {
  1397. var item;
  1398. for (var i in props) {
  1399. if (props[i] in obj) {
  1400. // return the property name as a string
  1401. if (elem === false) {
  1402. return props[i];
  1403. }
  1404. item = obj[props[i]];
  1405. // let's bind a function
  1406. if (is(item, 'function')) {
  1407. // bind to obj unless overridden
  1408. return fnBind(item, elem || obj);
  1409. }
  1410. // return the unbound function or obj or value
  1411. return item;
  1412. }
  1413. }
  1414. return false;
  1415. }
  1416. ;
  1417. /**
  1418. * testPropsAll tests a list of DOM properties we want to check against.
  1419. * We specify literally ALL possible (known and/or likely) properties on
  1420. * the element including the non-vendor prefixed one, for forward-
  1421. * compatibility.
  1422. *
  1423. * @access private
  1424. * @function testPropsAll
  1425. * @param {string} prop - A string of the property to test for
  1426. * @param {string|Object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
  1427. * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
  1428. * @param {string} [value] - A string of a css value
  1429. * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
  1430. * @returns {false|string} returns the string version of the property, or false if it is unsupported
  1431. */
  1432. function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
  1433. var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
  1434. props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
  1435. // did they call .prefixed('boxSizing') or are we just testing a prop?
  1436. if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
  1437. return testProps(props, prefixed, value, skipValueTest);
  1438. // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
  1439. } else {
  1440. props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
  1441. return testDOMProps(props, prefixed, elem);
  1442. }
  1443. }
  1444. // Modernizr.testAllProps() investigates whether a given style property,
  1445. // or any of its vendor-prefixed variants, is recognized
  1446. //
  1447. // Note that the property names must be provided in the camelCase variant.
  1448. // Modernizr.testAllProps('boxSizing')
  1449. ModernizrProto.testAllProps = testPropsAll;
  1450. /**
  1451. * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
  1452. * some prefixed form, or false, in the case of an unsupported rule
  1453. *
  1454. * @memberOf Modernizr
  1455. * @name Modernizr.atRule
  1456. * @optionName Modernizr.atRule()
  1457. * @optionProp atRule
  1458. * @access public
  1459. * @function atRule
  1460. * @param {string} prop - String name of the @-rule to test for
  1461. * @returns {string|boolean} The string representing the (possibly prefixed)
  1462. * valid version of the @-rule, or `false` when it is unsupported.
  1463. * @example
  1464. * ```js
  1465. * var keyframes = Modernizr.atRule('@keyframes');
  1466. *
  1467. * if (keyframes) {
  1468. * // keyframes are supported
  1469. * // could be `@-webkit-keyframes` or `@keyframes`
  1470. * } else {
  1471. * // keyframes === `false`
  1472. * }
  1473. * ```
  1474. */
  1475. var atRule = function(prop) {
  1476. var length = prefixes.length;
  1477. var cssrule = window.CSSRule;
  1478. var rule;
  1479. if (typeof cssrule === 'undefined') {
  1480. return undefined;
  1481. }
  1482. if (!prop) {
  1483. return false;
  1484. }
  1485. // remove literal @ from beginning of provided property
  1486. prop = prop.replace(/^@/, '');
  1487. // CSSRules use underscores instead of dashes
  1488. rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
  1489. if (rule in cssrule) {
  1490. return '@' + prop;
  1491. }
  1492. for (var i = 0; i < length; i++) {
  1493. // prefixes gives us something like -o-, and we want O_
  1494. var prefix = prefixes[i];
  1495. var thisRule = prefix.toUpperCase() + '_' + rule;
  1496. if (thisRule in cssrule) {
  1497. return '@-' + prefix.toLowerCase() + '-' + prop;
  1498. }
  1499. }
  1500. return false;
  1501. };
  1502. ModernizrProto.atRule = atRule;
  1503. /**
  1504. * prefixed returns the prefixed or nonprefixed property name variant of your input
  1505. *
  1506. * @memberOf Modernizr
  1507. * @name Modernizr.prefixed
  1508. * @optionName Modernizr.prefixed()
  1509. * @optionProp prefixed
  1510. * @access public
  1511. * @function prefixed
  1512. * @param {string} prop - String name of the property to test for
  1513. * @param {Object} [obj] - An object to test for the prefixed properties on
  1514. * @param {HTMLElement} [elem] - An element used to test specific properties against
  1515. * @returns {string|false} The string representing the (possibly prefixed) valid
  1516. * version of the property, or `false` when it is unsupported.
  1517. * @example
  1518. *
  1519. * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
  1520. * opposed to the css style kebab-case) form and returns the (possibly prefixed)
  1521. * version of that property that the browser actually supports.
  1522. *
  1523. * For example, in older Firefox...
  1524. * ```js
  1525. * prefixed('boxSizing')
  1526. * ```
  1527. * returns 'MozBoxSizing'
  1528. *
  1529. * In newer Firefox, as well as any other browser that support the unprefixed
  1530. * version would simply return `boxSizing`. Any browser that does not support
  1531. * the property at all, it will return `false`.
  1532. *
  1533. * By default, prefixed is checked against a DOM element. If you want to check
  1534. * for a property on another object, just pass it as a second argument
  1535. *
  1536. * ```js
  1537. * var rAF = prefixed('requestAnimationFrame', window);
  1538. *
  1539. * raf(function() {
  1540. * renderFunction();
  1541. * })
  1542. * ```
  1543. *
  1544. * Note that this will return _the actual function_ - not the name of the function.
  1545. * If you need the actual name of the property, pass in `false` as a third argument
  1546. *
  1547. * ```js
  1548. * var rAFProp = prefixed('requestAnimationFrame', window, false);
  1549. *
  1550. * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
  1551. * ```
  1552. *
  1553. * One common use case for prefixed is if you're trying to determine which transition
  1554. * end event to bind to, you might do something like...
  1555. * ```js
  1556. * var transEndEventNames = {
  1557. * 'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
  1558. * 'MozTransition' : 'transitionend', * only for FF < 15
  1559. * 'transition' : 'transitionend' * IE10, Opera, Chrome, FF 15+, Saf 7+
  1560. * };
  1561. *
  1562. * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
  1563. * ```
  1564. *
  1565. * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
  1566. */
  1567. var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
  1568. if (prop.indexOf('@') === 0) {
  1569. return atRule(prop);
  1570. }
  1571. if (prop.indexOf('-') !== -1) {
  1572. // Convert kebab-case to camelCase
  1573. prop = cssToDOM(prop);
  1574. }
  1575. if (!obj) {
  1576. return testPropsAll(prop, 'pfx');
  1577. } else {
  1578. // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
  1579. return testPropsAll(prop, obj, elem);
  1580. }
  1581. };
  1582. /*!
  1583. {
  1584. "name": "Battery API",
  1585. "property": "batteryapi",
  1586. "aliases": ["battery-api"],
  1587. "builderAliases": ["battery_api"],
  1588. "tags": ["device", "media"],
  1589. "authors": ["Paul Sayre", "Alex Bradley (@abrad1212)"],
  1590. "notes": [{
  1591. "name": "MDN Docs",
  1592. "href": "https://developer.mozilla.org/en/DOM/window.navigator.mozBattery"
  1593. }]
  1594. }
  1595. !*/
  1596. /* DOC
  1597. Detect support for the Battery API, for accessing information about the system's battery charge level.
  1598. */
  1599. Modernizr.addTest('batteryapi', !!prefixed('battery', navigator) || !!prefixed('getBattery', navigator), {aliases: ['battery-api']});
  1600. /*!
  1601. {
  1602. "name": "Blob constructor",
  1603. "property": "blobconstructor",
  1604. "aliases": ["blob-constructor"],
  1605. "builderAliases": ["blob_constructor"],
  1606. "caniuse": "blobbuilder",
  1607. "notes": [{
  1608. "name": "W3C Spec",
  1609. "href": "https://w3c.github.io/FileAPI/#constructorBlob"
  1610. }],
  1611. "polyfills": ["blobjs"]
  1612. }
  1613. !*/
  1614. /* DOC
  1615. Detects support for the Blob constructor, for creating file-like objects of immutable, raw data.
  1616. */
  1617. Modernizr.addTest('blobconstructor', function() {
  1618. try {
  1619. return !!new Blob();
  1620. } catch (e) {
  1621. return false;
  1622. }
  1623. }, {
  1624. aliases: ['blob-constructor']
  1625. });
  1626. /*!
  1627. {
  1628. "name": "Canvas",
  1629. "property": "canvas",
  1630. "caniuse": "canvas",
  1631. "tags": ["canvas", "graphics"],
  1632. "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
  1633. }
  1634. !*/
  1635. /* DOC
  1636. Detects support for the `<canvas>` element for 2D drawing.
  1637. */
  1638. // On the S60 and BB Storm, getContext exists, but always returns undefined
  1639. // so we actually have to call getContext() to verify
  1640. // github.com/Modernizr/Modernizr/issues/issue/97/
  1641. Modernizr.addTest('canvas', function() {
  1642. var elem = createElement('canvas');
  1643. return !!(elem.getContext && elem.getContext('2d'));
  1644. });
  1645. /*!
  1646. {
  1647. "name": "Canvas text",
  1648. "property": "canvastext",
  1649. "caniuse": "canvas-text",
  1650. "tags": ["canvas", "graphics"],
  1651. "polyfills": ["canvastext"]
  1652. }
  1653. !*/
  1654. /* DOC
  1655. Detects support for the text APIs for `<canvas>` elements.
  1656. */
  1657. Modernizr.addTest('canvastext', function() {
  1658. if (Modernizr.canvas === false) {
  1659. return false;
  1660. }
  1661. return typeof createElement('canvas').getContext('2d').fillText === 'function';
  1662. });
  1663. /*!
  1664. {
  1665. "name": "Content Editable",
  1666. "property": "contenteditable",
  1667. "caniuse": "contenteditable",
  1668. "notes": [{
  1669. "name": "WHATWG Spec",
  1670. "href": "https://html.spec.whatwg.org/multipage/interaction.html#contenteditable"
  1671. }]
  1672. }
  1673. !*/
  1674. /* DOC
  1675. Detects support for the `contenteditable` attribute of elements, allowing their DOM text contents to be edited directly by the user.
  1676. */
  1677. Modernizr.addTest('contenteditable', function() {
  1678. // early bail out
  1679. if (!('contentEditable' in docElement)) {
  1680. return;
  1681. }
  1682. // some mobile browsers (android < 3.0, iOS < 5) claim to support
  1683. // contentEditable, but but don't really. This test checks to see
  1684. // confirms whether or not it actually supports it.
  1685. var div = createElement('div');
  1686. div.contentEditable = true;
  1687. return div.contentEditable === 'true';
  1688. });
  1689. /*!
  1690. {
  1691. "name": "Context menus",
  1692. "property": "contextmenu",
  1693. "caniuse": "menu",
  1694. "notes": [{
  1695. "name": "W3C Spec",
  1696. "href": "https://www.w3.org/TR/html5/interactive-elements.html#context-menus"
  1697. },{
  1698. "name": "thewebrocks.com Demo",
  1699. "href": "http://thewebrocks.com/demos/context-menu/"
  1700. }],
  1701. "polyfills": ["jquery-contextmenu"]
  1702. }
  1703. !*/
  1704. /* DOC
  1705. Detects support for custom context menus.
  1706. */
  1707. Modernizr.addTest(
  1708. 'contextmenu',
  1709. ('contextMenu' in docElement && 'HTMLMenuItemElement' in window)
  1710. );
  1711. /*!
  1712. {
  1713. "name": "Cookies",
  1714. "property": "cookies",
  1715. "tags": ["storage"],
  1716. "authors": ["tauren"]
  1717. }
  1718. !*/
  1719. /* DOC
  1720. Detects whether cookie support is enabled.
  1721. */
  1722. // https://github.com/Modernizr/Modernizr/issues/191
  1723. Modernizr.addTest('cookies', function() {
  1724. // navigator.cookieEnabled cannot detect custom or nuanced cookie blocking
  1725. // configurations. For example, when blocking cookies via the Advanced
  1726. // Privacy Settings in IE9, it always returns true. And there have been
  1727. // issues in the past with site-specific exceptions.
  1728. // Don't rely on it.
  1729. // try..catch because some in situations `document.cookie` is exposed but throws a
  1730. // SecurityError if you try to access it; e.g. documents created from data URIs
  1731. // or in sandboxed iframes (depending on flags/context)
  1732. try {
  1733. // Create cookie
  1734. document.cookie = 'cookietest=1';
  1735. var ret = document.cookie.indexOf('cookietest=') !== -1;
  1736. // Delete cookie
  1737. document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
  1738. return ret;
  1739. }
  1740. catch (e) {
  1741. return false;
  1742. }
  1743. });
  1744. /*!
  1745. {
  1746. "name": "Cross-Origin Resource Sharing",
  1747. "property": "cors",
  1748. "caniuse": "cors",
  1749. "authors": ["Theodoor van Donge"],
  1750. "notes": [{
  1751. "name": "MDN Docs",
  1752. "href": "https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS"
  1753. }],
  1754. "polyfills": ["pmxdr", "ppx", "flxhr"]
  1755. }
  1756. !*/
  1757. /* DOC
  1758. Detects support for Cross-Origin Resource Sharing: method of performing XMLHttpRequests across domains.
  1759. */
  1760. Modernizr.addTest('cors', 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest());
  1761. /*!
  1762. {
  1763. "name": "Web Cryptography",
  1764. "property": "cryptography",
  1765. "caniuse": "cryptography",
  1766. "tags": ["crypto"],
  1767. "authors": ["roblarsen"],
  1768. "notes": [{
  1769. "name": "W3C Editor's Draft Spec",
  1770. "href": "https://www.w3.org/TR/WebCryptoAPI/"
  1771. }],
  1772. "polyfills": ["polycrypt"]
  1773. }
  1774. !*/
  1775. /* DOC
  1776. Detects support for the cryptographic functionality available under window.crypto.subtle
  1777. */
  1778. var crypto = prefixed('crypto', window);
  1779. Modernizr.addTest('crypto', !!prefixed('subtle', crypto));
  1780. /*!
  1781. {
  1782. "name": "Custom Elements API",
  1783. "property": "customelements",
  1784. "tags": ["customelements"],
  1785. "polyfills": ["customelements"],
  1786. "notes": [{
  1787. "name": "Specs for Custom Elements",
  1788. "href": "https://www.w3.org/TR/custom-elements/"
  1789. }]
  1790. }
  1791. !*/
  1792. /* DOC
  1793. Detects support for the Custom Elements API, to create custom html elements via js
  1794. */
  1795. Modernizr.addTest('customelements', 'customElements' in window);
  1796. /*!
  1797. {
  1798. "name": "Custom protocol handler",
  1799. "property": "customprotocolhandler",
  1800. "authors": ["Ben Schwarz"],
  1801. "builderAliases": ["custom_protocol_handler"],
  1802. "notes": [{
  1803. "name": "WHATWG Spec",
  1804. "href": "https://html.spec.whatwg.org/dev/system-state.html#custom-handlers"
  1805. },{
  1806. "name": "MDN Docs",
  1807. "href": "https://developer.mozilla.org/en-US/docs/Web/API/navigator.registerProtocolHandler"
  1808. }]
  1809. }
  1810. !*/
  1811. /* DOC
  1812. Detects support for the `window.registerProtocolHandler()` API to allow websites to register themselves as possible handlers for particular protocols.
  1813. */
  1814. Modernizr.addTest('customprotocolhandler', function() {
  1815. // early bailout where it doesn't exist at all
  1816. if (!navigator.registerProtocolHandler) {
  1817. return false;
  1818. }
  1819. // registerProtocolHandler was stubbed in webkit for a while, and didn't
  1820. // actually do anything. We intentionally set it improperly to test for
  1821. // the proper sort of failure
  1822. try {
  1823. navigator.registerProtocolHandler('thisShouldFail');
  1824. }
  1825. catch (e) {
  1826. return e instanceof TypeError;
  1827. }
  1828. return false;
  1829. });
  1830. /*!
  1831. {
  1832. "name": "CustomEvent",
  1833. "property": "customevent",
  1834. "tags": ["customevent"],
  1835. "authors": ["Alberto Elias"],
  1836. "notes": [{
  1837. "name": "W3C Spec",
  1838. "href": "https://www.w3.org/TR/DOM-Level-3-Events/#interface-CustomEvent"
  1839. }, {
  1840. "name": "MDN Docs",
  1841. "href": "https://developer.mozilla.org/en/docs/Web/API/CustomEvent"
  1842. }],
  1843. "polyfills": ["eventlistener"]
  1844. }
  1845. !*/
  1846. /* DOC
  1847. Detects support for CustomEvent.
  1848. */
  1849. Modernizr.addTest('customevent', 'CustomEvent' in window && typeof window.CustomEvent === 'function');
  1850. /*!
  1851. {
  1852. "name": "Dart",
  1853. "property": "dart",
  1854. "authors": ["Theodoor van Donge"],
  1855. "notes": [{
  1856. "name": "Language website",
  1857. "href": "https://www.dartlang.org/"
  1858. }]
  1859. }
  1860. !*/
  1861. /* DOC
  1862. Detects native support for the Dart programming language.
  1863. */
  1864. Modernizr.addTest('dart', !!prefixed('startDart', navigator));
  1865. /*!
  1866. {
  1867. "name": "DataView",
  1868. "property": "dataview",
  1869. "authors": ["Addy Osmani"],
  1870. "builderAliases": ["dataview_api"],
  1871. "notes": [{
  1872. "name": "MDN Docs",
  1873. "href": "https://developer.mozilla.org/en/JavaScript_typed_arrays/DataView"
  1874. }],
  1875. "polyfills": ["jdataview"]
  1876. }
  1877. !*/
  1878. /* DOC
  1879. Detects support for the DataView interface for reading data from an ArrayBuffer as part of the Typed Array spec.
  1880. */
  1881. Modernizr.addTest('dataview', (typeof DataView !== 'undefined' && 'getFloat64' in DataView.prototype));
  1882. /*!
  1883. {
  1884. "name": "Event Listener",
  1885. "property": "eventlistener",
  1886. "authors": ["Andrew Betts (@triblondon)"],
  1887. "notes": [{
  1888. "name": "W3C Spec",
  1889. "href": "https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Registration-interfaces"
  1890. }],
  1891. "polyfills": ["eventlistener"]
  1892. }
  1893. !*/
  1894. /* DOC
  1895. Detects native support for addEventListener
  1896. */
  1897. Modernizr.addTest('eventlistener', 'addEventListener' in window);
  1898. /*!
  1899. {
  1900. "name": "EXIF Orientation",
  1901. "property": "exiforientation",
  1902. "tags": ["image"],
  1903. "builderAliases": ["exif_orientation"],
  1904. "async": true,
  1905. "authors": ["Paul Sayre"],
  1906. "notes": [{
  1907. "name": "Article by Dave Perrett",
  1908. "href": "https://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/"
  1909. },{
  1910. "name": "Article by Calvin Hass",
  1911. "href": "https://www.impulseadventure.com/photo/exif-orientation.html"
  1912. }]
  1913. }
  1914. !*/
  1915. /* DOC
  1916. Detects support for EXIF Orientation in JPEG images.
  1917. iOS looks at the EXIF Orientation flag in JPEGs and rotates the image accordingly. Most desktop browsers just ignore this data.
  1918. */
  1919. // Bug trackers:
  1920. // bugzil.la/298619 (unimplemented)
  1921. // crbug.com/56845 (looks incomplete)
  1922. // webk.it/19688 (available upstream but its up all ports to turn on individually)
  1923. Modernizr.addAsyncTest(function() {
  1924. var img = new Image();
  1925. img.onerror = function() {
  1926. addTest('exiforientation', false, {aliases: ['exif-orientation']});
  1927. };
  1928. img.onload = function() {
  1929. addTest('exiforientation', img.width !== 2, {aliases: ['exif-orientation']});
  1930. };
  1931. // There may be a way to shrink this more, it's a 1x2 white jpg with the orientation flag set to 6
  1932. img.src = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAAABABIBAwABAAAABgASAAAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigD/2Q==';
  1933. });
  1934. /*!
  1935. {
  1936. "name": "Flash",
  1937. "property": "flash",
  1938. "tags": ["flash"],
  1939. "polyfills": ["shumway"]
  1940. }
  1941. !*/
  1942. /* DOC
  1943. Detects Flash support as well as Flash-blocking plugins
  1944. */
  1945. Modernizr.addAsyncTest(function() {
  1946. var attachBody = function(body) {
  1947. if (!docElement.contains(body)) {
  1948. docElement.appendChild(body);
  1949. }
  1950. };
  1951. var removeFakeBody = function(body) {
  1952. // If we’re rockin’ an attached fake body, clean it up
  1953. if (body.fake && body.parentNode) {
  1954. body.parentNode.removeChild(body);
  1955. }
  1956. };
  1957. var runTest = function(result, embed) {
  1958. var bool = !!result;
  1959. if (bool) {
  1960. bool = new Boolean(bool);
  1961. bool.blocked = (result === 'blocked');
  1962. }
  1963. addTest('flash', function() { return bool; });
  1964. if (embed && body.contains(embed)) {
  1965. // in case embed has been wrapped, as with ClickToPlugin
  1966. while (embed.parentNode !== body) {
  1967. embed = embed.parentNode;
  1968. }
  1969. body.removeChild(embed);
  1970. }
  1971. };
  1972. var easy_detect;
  1973. var activex;
  1974. // we wrap activex in a try/catch because when Flash is disabled through
  1975. // ActiveX controls, it throws an error.
  1976. try {
  1977. // Pan is an API that exists for Flash objects.
  1978. activex = 'ActiveXObject' in window && 'Pan' in new window.ActiveXObject('ShockwaveFlash.ShockwaveFlash');
  1979. } catch (e) {}
  1980. easy_detect = !(('plugins' in navigator && 'Shockwave Flash' in navigator.plugins) || activex);
  1981. if (easy_detect || isSVG) {
  1982. runTest(false);
  1983. }
  1984. else {
  1985. // Flash seems to be installed, but it might be blocked. We have to
  1986. // actually create an element to see what happens to it.
  1987. var embed = createElement('embed');
  1988. var body = getBody();
  1989. var blockedDetect;
  1990. var inline_style;
  1991. embed.type = 'application/x-shockwave-flash';
  1992. // Need to do this in the body (fake or otherwise) otherwise IE8 complains
  1993. body.appendChild(embed);
  1994. // Pan doesn't exist in the embed if its IE (its on the ActiveXObject)
  1995. // so this check is for all other browsers.
  1996. if (!('Pan' in embed) && !activex) {
  1997. attachBody(body);
  1998. runTest('blocked', embed);
  1999. removeFakeBody(body);
  2000. return;
  2001. }
  2002. blockedDetect = function() {
  2003. // if we used a fake body originally, we need to restart this test, since
  2004. // we haven't been attached to the DOM, and therefore none of the blockers
  2005. // have had time to work.
  2006. attachBody(body);
  2007. if (!docElement.contains(body)) {
  2008. body = document.body || body;
  2009. embed = createElement('embed');
  2010. embed.type = 'application/x-shockwave-flash';
  2011. body.appendChild(embed);
  2012. return setTimeout(blockedDetect, 1000);
  2013. }
  2014. if (!docElement.contains(embed)) {
  2015. runTest('blocked');
  2016. }
  2017. else {
  2018. inline_style = embed.style.cssText;
  2019. if (inline_style !== '') {
  2020. // the style of the element has changed automatically. This is a
  2021. // really poor heuristic, but for lower end Flash blocks, it the
  2022. // only change they can make.
  2023. runTest('blocked', embed);
  2024. }
  2025. else {
  2026. runTest(true, embed);
  2027. }
  2028. }
  2029. removeFakeBody(body);
  2030. };
  2031. // If we have got this far, there is still a chance a userland plugin
  2032. // is blocking us (either changing the styles, or automatically removing
  2033. // the element). Both of these require us to take a step back for a moment
  2034. // to allow for them to get time of the thread, hence a setTimeout.
  2035. //
  2036. setTimeout(blockedDetect, 10);
  2037. }
  2038. });
  2039. /*!
  2040. {
  2041. "name": "Force Touch Events",
  2042. "property": "forcetouch",
  2043. "authors": ["Kraig Walker"],
  2044. "notes": [{
  2045. "name": "Responding to Force Touch Events from JavaScript",
  2046. "href": "https://developer.apple.com/library/archive/documentation/AppleApplications/Conceptual/SafariJSProgTopics/RespondingtoForceTouchEventsfromJavaScript.html"
  2047. }]
  2048. }
  2049. !*/
  2050. /* DOC
  2051. Tests whether the browser supports the detection of Force Touch Events.
  2052. Force Touch Events allow custom behaviours and interactions to take place based on the given pressure or change in pressure from a compatible trackpad.
  2053. Force Touch events are available in OS X 10.11 and later on devices equipped with Force Touch trackpads.
  2054. */
  2055. Modernizr.addTest('forcetouch', function() {
  2056. // github.com/Modernizr/Modernizr/issues/1613
  2057. // Test if the browser supports the force touch event progression (see notes link)
  2058. if (!hasEvent(prefixed('mouseforcewillbegin', window, false), window)) {
  2059. return false;
  2060. }
  2061. // Test if the browser provides thresholds defining a "force touch" from a normal touch/click event
  2062. return MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN && MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN;
  2063. });
  2064. /*!
  2065. {
  2066. "name": "Fullscreen API",
  2067. "property": "fullscreen",
  2068. "caniuse": "fullscreen",
  2069. "notes": [{
  2070. "name": "MDN Docs",
  2071. "href": "https://developer.mozilla.org/en/API/Fullscreen"
  2072. }],
  2073. "polyfills": ["screenfulljs"],
  2074. "builderAliases": ["fullscreen_api"]
  2075. }
  2076. !*/
  2077. /* DOC
  2078. Detects support for the ability to make the current website take over the user's entire screen
  2079. */
  2080. // github.com/Modernizr/Modernizr/issues/739
  2081. Modernizr.addTest('fullscreen', !!(prefixed('exitFullscreen', document, false) || prefixed('cancelFullScreen', document, false)));
  2082. /*!
  2083. {
  2084. "name": "GamePad API",
  2085. "property": "gamepads",
  2086. "authors": ["Eric Bidelman"],
  2087. "tags": ["media"],
  2088. "notes": [{
  2089. "name": "W3C Spec",
  2090. "href": "https://www.w3.org/TR/gamepad/"
  2091. },{
  2092. "name": "HTML5 Rocks Tutorial",
  2093. "href": "https://www.html5rocks.com/en/tutorials/doodles/gamepad/#toc-featuredetect"
  2094. }]
  2095. }
  2096. !*/
  2097. /* DOC
  2098. Detects support for the Gamepad API, for access to gamepads and controllers.
  2099. */
  2100. Modernizr.addTest('gamepads', !!prefixed('getGamepads', navigator));
  2101. /*!
  2102. {
  2103. "name": "Geolocation API",
  2104. "property": "geolocation",
  2105. "caniuse": "geolocation",
  2106. "tags": ["media"],
  2107. "notes": [{
  2108. "name": "MDN Docs",
  2109. "href": "https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation"
  2110. }],
  2111. "polyfills": [
  2112. "joshuabell-polyfill",
  2113. "webshims",
  2114. "geo-location-javascript",
  2115. "geolocation-api-polyfill"
  2116. ]
  2117. }
  2118. !*/
  2119. /* DOC
  2120. Detects support for the Geolocation API for users to provide their location to web applications.
  2121. */
  2122. // geolocation is often considered a trivial feature detect...
  2123. // Turns out, it's quite tricky to get right:
  2124. //
  2125. // Using !!navigator.geolocation does two things we don't want. It:
  2126. // 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
  2127. // 2. Disables page caching in WebKit: webk.it/43956
  2128. //
  2129. // Meanwhile, in Firefox < 8, an about:config setting could expose
  2130. // a false positive that would throw an exception: bugzil.la/688158
  2131. Modernizr.addTest('geolocation', 'geolocation' in navigator);
  2132. /*!
  2133. {
  2134. "name": "Hashchange event",
  2135. "property": "hashchange",
  2136. "caniuse": "hashchange",
  2137. "tags": ["history"],
  2138. "notes": [{
  2139. "name": "MDN Docs",
  2140. "href": "https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange"
  2141. }],
  2142. "polyfills": [
  2143. "jquery-hashchange",
  2144. "moo-historymanager",
  2145. "jquery-ajaxy",
  2146. "hasher",
  2147. "shistory"
  2148. ]
  2149. }
  2150. !*/
  2151. /* DOC
  2152. Detects support for the `hashchange` event, fired when the current location fragment changes.
  2153. */
  2154. Modernizr.addTest('hashchange', function() {
  2155. if (hasEvent('hashchange', window) === false) {
  2156. return false;
  2157. }
  2158. // documentMode logic from YUI to filter out IE8 Compat Mode
  2159. // which false positives.
  2160. return (document.documentMode === undefined || document.documentMode > 7);
  2161. });
  2162. /**
  2163. * testStyles injects an element with style element and some CSS rules
  2164. *
  2165. * @memberOf Modernizr
  2166. * @name Modernizr.testStyles
  2167. * @optionName Modernizr.testStyles()
  2168. * @optionProp testStyles
  2169. * @access public
  2170. * @function testStyles
  2171. * @param {string} rule - String representing a css rule
  2172. * @param {function} callback - A function that is used to test the injected element
  2173. * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
  2174. * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
  2175. * @returns {boolean}
  2176. * @example
  2177. *
  2178. * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
  2179. * along with (possibly multiple) DOM elements. This lets you check for features
  2180. * that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules).
  2181. *
  2182. * ```js
  2183. * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
  2184. * // elem is the first DOM node in the page (by default #modernizr)
  2185. * // rule is the first argument you supplied - the CSS rule in string form
  2186. *
  2187. * addTest('widthworks', elem.style.width === '9px')
  2188. * });
  2189. * ```
  2190. *
  2191. * If your test requires multiple nodes, you can include a third argument
  2192. * indicating how many additional div elements to include on the page. The
  2193. * additional nodes are injected as children of the `elem` that is returned as
  2194. * the first argument to the callback.
  2195. *
  2196. * ```js
  2197. * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
  2198. * document.getElementById('modernizr').style.width === '1px'; // true
  2199. * document.getElementById('modernizr2').style.width === '2px'; // true
  2200. * elem.firstChild === document.getElementById('modernizr2'); // true
  2201. * }, 1);
  2202. * ```
  2203. *
  2204. * By default, all of the additional elements have an ID of `modernizr[n]`, where
  2205. * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
  2206. * the second additional is `#modernizr3`, etc.).
  2207. * If you want to have more meaningful IDs for your function, you can provide
  2208. * them as the fourth argument, as an array of strings
  2209. *
  2210. * ```js
  2211. * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
  2212. * elem.firstChild === document.getElementById('foo'); // true
  2213. * elem.lastChild === document.getElementById('bar'); // true
  2214. * }, 2, ['foo', 'bar']);
  2215. * ```
  2216. */
  2217. var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
  2218. /*!
  2219. {
  2220. "name": "Hidden Scrollbar",
  2221. "property": "hiddenscroll",
  2222. "authors": ["Oleg Korsunsky"],
  2223. "tags": ["overlay"],
  2224. "notes": [{
  2225. "name": "Overlay Scrollbar description",
  2226. "href": "https://developer.apple.com/library/mac/releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_7.html#//apple_ref/doc/uid/TP40010355-SW39"
  2227. },{
  2228. "name": "Video example of overlay scrollbars",
  2229. "href": "https://gfycat.com/FoolishMeaslyAtlanticsharpnosepuffer"
  2230. }]
  2231. }
  2232. !*/
  2233. /* DOC
  2234. Detects overlay scrollbars (when scrollbars on overflowed blocks are visible). This is found most commonly on mobile and OS X.
  2235. */
  2236. Modernizr.addTest('hiddenscroll', function() {
  2237. return testStyles('#modernizr {width:100px;height:100px;overflow:scroll}', function(elem) {
  2238. return elem.offsetWidth === elem.clientWidth;
  2239. });
  2240. });
  2241. /*!
  2242. {
  2243. "name": "History API",
  2244. "property": "history",
  2245. "caniuse": "history",
  2246. "tags": ["history"],
  2247. "authors": ["Hay Kranen", "Alexander Farkas"],
  2248. "notes": [{
  2249. "name": "W3C Spec",
  2250. "href": "https://www.w3.org/TR/html51/browsers.html#the-history-interface"
  2251. }, {
  2252. "name": "MDN Docs",
  2253. "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
  2254. }],
  2255. "polyfills": ["historyjs", "html5historyapi"]
  2256. }
  2257. !*/
  2258. /* DOC
  2259. Detects support for the History API for manipulating the browser session history.
  2260. */
  2261. Modernizr.addTest('history', function() {
  2262. // Issue #733
  2263. // The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support
  2264. // Unfortunately support is really buggy and there is no clean way to detect
  2265. // these bugs, so we fall back to a user agent sniff :(
  2266. var ua = navigator.userAgent;
  2267. // We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
  2268. // itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
  2269. if ((ua.indexOf('Android 2.') !== -1 ||
  2270. (ua.indexOf('Android 4.0') !== -1)) &&
  2271. ua.indexOf('Mobile Safari') !== -1 &&
  2272. ua.indexOf('Chrome') === -1 &&
  2273. ua.indexOf('Windows Phone') === -1 &&
  2274. // Since all documents on file:// share an origin, the History apis are
  2275. // blocked there as well
  2276. location.protocol !== 'file:'
  2277. ) {
  2278. return false;
  2279. }
  2280. // Return the regular check
  2281. return (window.history && 'pushState' in window.history);
  2282. });
  2283. /*!
  2284. {
  2285. "name": "HTML Imports",
  2286. "property": "htmlimports",
  2287. "tags": ["html", "import"],
  2288. "polyfills": ["polymer-htmlimports"],
  2289. "notes": [{
  2290. "name": "W3C Spec",
  2291. "href": "https://w3c.github.io/webcomponents/spec/imports/"
  2292. }, {
  2293. "name": "HTML Imports - #include for the web",
  2294. "href": "https://www.html5rocks.com/en/tutorials/webcomponents/imports/"
  2295. }]
  2296. }
  2297. !*/
  2298. /* DOC
  2299. Detects support for HTML import, a feature that is used for loading in Web Components.
  2300. */
  2301. Modernizr.addTest('htmlimports', 'import' in createElement('link'));
  2302. /*!
  2303. {
  2304. "name": "IE8 compat mode",
  2305. "property": "ie8compat",
  2306. "authors": ["Erich Ocean"]
  2307. }
  2308. !*/
  2309. /* DOC
  2310. Detects whether or not the current browser is IE8 in compatibility mode (i.e. acting as IE7).
  2311. */
  2312. // In this case, IE8 will be acting as IE7. You may choose to remove features in this case.
  2313. // related:
  2314. // james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/
  2315. Modernizr.addTest('ie8compat', (!window.addEventListener && !!document.documentMode && document.documentMode === 7));
  2316. /*!
  2317. {
  2318. "name": "IndexedDB",
  2319. "property": "indexeddb",
  2320. "caniuse": "indexeddb",
  2321. "tags": ["storage"],
  2322. "polyfills": ["indexeddb"],
  2323. "async": true
  2324. }
  2325. !*/
  2326. /* DOC
  2327. Detects support for the IndexedDB client-side storage API (final spec).
  2328. */
  2329. // Vendors had inconsistent prefixing with the experimental Indexed DB:
  2330. // - Webkit's implementation is accessible through webkitIndexedDB
  2331. // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
  2332. // For speed, we don't test the legacy (and beta-only) indexedDB
  2333. Modernizr.addAsyncTest(function() {
  2334. var indexeddb;
  2335. try {
  2336. // Firefox throws a Security Error when cookies are disabled
  2337. indexeddb = prefixed('indexedDB', window);
  2338. } catch (e) {
  2339. }
  2340. if (indexeddb) {
  2341. var testDBName = 'modernizr-' + Math.random();
  2342. var req;
  2343. try {
  2344. req = indexeddb.open(testDBName);
  2345. } catch (e) {
  2346. addTest('indexeddb', false);
  2347. return;
  2348. }
  2349. req.onerror = function(event) {
  2350. if (req.error && (req.error.name === 'InvalidStateError' || req.error.name === 'UnknownError')) {
  2351. addTest('indexeddb', false);
  2352. event.preventDefault();
  2353. } else {
  2354. addTest('indexeddb', true);
  2355. detectDeleteDatabase(indexeddb, testDBName);
  2356. }
  2357. };
  2358. req.onsuccess = function() {
  2359. addTest('indexeddb', true);
  2360. detectDeleteDatabase(indexeddb, testDBName);
  2361. };
  2362. } else {
  2363. addTest('indexeddb', false);
  2364. }
  2365. });
  2366. function detectDeleteDatabase(indexeddb, testDBName) {
  2367. var deleteReq = indexeddb.deleteDatabase(testDBName);
  2368. deleteReq.onsuccess = function() {
  2369. addTest('indexeddb.deletedatabase', true);
  2370. };
  2371. deleteReq.onerror = function() {
  2372. addTest('indexeddb.deletedatabase', false);
  2373. };
  2374. }
  2375. ;
  2376. /*!
  2377. {
  2378. "name": "IndexedDB Blob",
  2379. "property": "indexeddbblob"
  2380. }
  2381. !*/
  2382. /* DOC
  2383. Detects if the browser can save File/Blob objects to IndexedDB
  2384. */
  2385. // Vendors had inconsistent prefixing with the experimental Indexed DB:
  2386. // - Webkit's implementation is accessible through webkitIndexedDB
  2387. // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
  2388. // For speed, we don't test the legacy (and beta-only) indexedDB
  2389. Modernizr.addAsyncTest(function() {
  2390. var indexeddb;
  2391. var dbname = 'detect-blob-support';
  2392. var supportsBlob = false;
  2393. var openRequest;
  2394. var db;
  2395. var putRequest;
  2396. try {
  2397. indexeddb = prefixed('indexedDB', window);
  2398. } catch (e) {
  2399. }
  2400. if (!(Modernizr.indexeddb && Modernizr.indexeddb.deletedatabase)) {
  2401. return false;
  2402. }
  2403. // Calling `deleteDatabase` in a try…catch because some contexts (e.g. data URIs)
  2404. // will throw a `SecurityError`
  2405. try {
  2406. indexeddb.deleteDatabase(dbname).onsuccess = function() {
  2407. openRequest = indexeddb.open(dbname, 1);
  2408. openRequest.onupgradeneeded = function() {
  2409. openRequest.result.createObjectStore('store');
  2410. };
  2411. openRequest.onsuccess = function() {
  2412. db = openRequest.result;
  2413. try {
  2414. putRequest = db.transaction('store', 'readwrite').objectStore('store').put(new Blob(), 'key');
  2415. putRequest.onsuccess = function() {
  2416. supportsBlob = true;
  2417. };
  2418. putRequest.onerror = function() {
  2419. supportsBlob = false;
  2420. };
  2421. }
  2422. catch (e) {
  2423. supportsBlob = false;
  2424. }
  2425. finally {
  2426. addTest('indexeddbblob', supportsBlob);
  2427. db.close();
  2428. indexeddb.deleteDatabase(dbname);
  2429. }
  2430. };
  2431. };
  2432. }
  2433. catch (e) {
  2434. addTest('indexeddbblob', false);
  2435. }
  2436. });
  2437. /**
  2438. * since we have a fairly large number of input tests that don't mutate the input
  2439. * we create a single element that can be shared with all of those tests for a
  2440. * minor perf boost
  2441. *
  2442. * @access private
  2443. * @returns {HTMLInputElement}
  2444. */
  2445. var inputElem = createElement('input');
  2446. /*!
  2447. {
  2448. "name": "Input attributes",
  2449. "property": "input",
  2450. "tags": ["forms"],
  2451. "authors": ["Mike Taylor"],
  2452. "notes": [{
  2453. "name": "WHATWG Spec",
  2454. "href": "https://html.spec.whatwg.org/multipage/input.html#input-type-attr-summary"
  2455. }],
  2456. "knownBugs": ["Some blackberry devices report false positive for input.multiple"]
  2457. }
  2458. !*/
  2459. /* DOC
  2460. Detects support for HTML5 `<input>` element attributes and exposes Boolean subproperties with the results:
  2461. ```javascript
  2462. Modernizr.input.autocomplete
  2463. Modernizr.input.autofocus
  2464. Modernizr.input.list
  2465. Modernizr.input.max
  2466. Modernizr.input.min
  2467. Modernizr.input.multiple
  2468. Modernizr.input.pattern
  2469. Modernizr.input.placeholder
  2470. Modernizr.input.required
  2471. Modernizr.input.step
  2472. ```
  2473. */
  2474. // Run through HTML5's new input attributes to see if the UA understands any.
  2475. // Mike Taylr has created a comprehensive resource for testing these attributes
  2476. // when applied to all input types:
  2477. // miketaylr.com/code/input-type-attr.html
  2478. // Only input placeholder is tested while textarea's placeholder is not.
  2479. // Currently Safari 4 and Opera 11 have support only for the input placeholder
  2480. // Both tests are available in feature-detects/forms-placeholder.js
  2481. var inputattrs = 'autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ');
  2482. var attrs = {};
  2483. Modernizr.input = (function(props) {
  2484. for (var i = 0, len = props.length; i < len; i++) {
  2485. attrs[ props[i] ] = !!(props[i] in inputElem);
  2486. }
  2487. if (attrs.list) {
  2488. // safari false positive's on datalist: webk.it/74252
  2489. // see also github.com/Modernizr/Modernizr/issues/146
  2490. attrs.list = !!(createElement('datalist') && window.HTMLDataListElement);
  2491. }
  2492. return attrs;
  2493. })(inputattrs);
  2494. /*!
  2495. {
  2496. "name": "input[search] search event",
  2497. "property": "inputsearchevent",
  2498. "tags": ["input","search"],
  2499. "authors": ["Calvin Webster"],
  2500. "notes": [{
  2501. "name": "Wufoo demo",
  2502. "href": "https://www.wufoo.com/html5/search-type/"
  2503. }, {
  2504. "name": "CSS Tricks",
  2505. "href": "https://css-tricks.com/webkit-html5-search-inputs/"
  2506. }]
  2507. }
  2508. !*/
  2509. /* DOC
  2510. There is a custom `search` event implemented in webkit browsers when using an `input[search]` element.
  2511. */
  2512. Modernizr.addTest('inputsearchevent', hasEvent('search'));
  2513. /*!
  2514. {
  2515. "name": "Form input types",
  2516. "property": "inputtypes",
  2517. "caniuse": "forms",
  2518. "tags": ["forms"],
  2519. "authors": ["Mike Taylor"],
  2520. "polyfills": [
  2521. "jquerytools",
  2522. "webshims",
  2523. "h5f",
  2524. "webforms2",
  2525. "nwxforms",
  2526. "fdslider",
  2527. "html5slider",
  2528. "galleryhtml5forms",
  2529. "jscolor",
  2530. "html5formshim",
  2531. "selectedoptionsjs",
  2532. "formvalidationjs"
  2533. ]
  2534. }
  2535. !*/
  2536. /* DOC
  2537. Detects support for HTML5 form input types and exposes Boolean subproperties with the results:
  2538. ```javascript
  2539. Modernizr.inputtypes.color
  2540. Modernizr.inputtypes.date
  2541. Modernizr.inputtypes.datetime
  2542. Modernizr.inputtypes['datetime-local']
  2543. Modernizr.inputtypes.email
  2544. Modernizr.inputtypes.month
  2545. Modernizr.inputtypes.number
  2546. Modernizr.inputtypes.range
  2547. Modernizr.inputtypes.search
  2548. Modernizr.inputtypes.tel
  2549. Modernizr.inputtypes.time
  2550. Modernizr.inputtypes.url
  2551. Modernizr.inputtypes.week
  2552. ```
  2553. */
  2554. // Run through HTML5's new input types to see if the UA understands any.
  2555. // This is put behind the tests runloop because it doesn't return a
  2556. // true/false like all the other tests; instead, it returns an object
  2557. // containing each input type with its corresponding true/false value
  2558. // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
  2559. var inputtypes = 'search tel url email datetime date month week time datetime-local number range color'.split(' ');
  2560. var inputs = {};
  2561. Modernizr.inputtypes = (function(props) {
  2562. var len = props.length;
  2563. var smile = '1)';
  2564. var inputElemType;
  2565. var defaultView;
  2566. var bool;
  2567. for (var i = 0; i < len; i++) {
  2568. inputElem.setAttribute('type', inputElemType = props[i]);
  2569. bool = inputElem.type !== 'text' && 'style' in inputElem;
  2570. // We first check to see if the type we give it sticks..
  2571. // If the type does, we feed it a textual value, which shouldn't be valid.
  2572. // If the value doesn't stick, we know there's input sanitization which infers a custom UI
  2573. if (bool) {
  2574. inputElem.value = smile;
  2575. inputElem.style.cssText = 'position:absolute;visibility:hidden;';
  2576. if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined) {
  2577. docElement.appendChild(inputElem);
  2578. defaultView = document.defaultView;
  2579. // Safari 2-4 allows the smiley as a value, despite making a slider
  2580. bool = defaultView.getComputedStyle &&
  2581. defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
  2582. // Mobile android web browser has false positive, so must
  2583. // check the height to see if the widget is actually there.
  2584. (inputElem.offsetHeight !== 0);
  2585. docElement.removeChild(inputElem);
  2586. } else if (/^(search|tel)$/.test(inputElemType)) {
  2587. // Spec doesn't define any special parsing or detectable UI
  2588. // behaviors so we pass these through as true
  2589. // Interestingly, opera fails the earlier test, so it doesn't
  2590. // even make it here.
  2591. } else if (/^(url|email)$/.test(inputElemType)) {
  2592. // Real url and email support comes with prebaked validation.
  2593. bool = inputElem.checkValidity && inputElem.checkValidity() === false;
  2594. } else {
  2595. // If the upgraded input component rejects the :) text, we got a winner
  2596. bool = inputElem.value !== smile;
  2597. }
  2598. }
  2599. inputs[ props[i] ] = !!bool;
  2600. }
  2601. return inputs;
  2602. })(inputtypes);
  2603. /*!
  2604. {
  2605. "name": "Internationalization API",
  2606. "property": "intl",
  2607. "notes": [{
  2608. "name": "MDN Docs",
  2609. "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl"
  2610. },{
  2611. "name": "ECMAScript spec",
  2612. "href": "https://www.ecma-international.org/ecma-402/1.0/"
  2613. }]
  2614. }
  2615. !*/
  2616. /* DOC
  2617. Detects support for the Internationalization API which allow easy formatting of number and dates and sorting string
  2618. based on a locale
  2619. */
  2620. Modernizr.addTest('intl', !!prefixed('Intl', window));
  2621. /*!
  2622. {
  2623. "name": "JSON",
  2624. "property": "json",
  2625. "caniuse": "json",
  2626. "notes": [{
  2627. "name": "MDN Docs",
  2628. "href": "https://developer.mozilla.org/en-US/docs/Glossary/JSON"
  2629. }],
  2630. "polyfills": ["json2"]
  2631. }
  2632. !*/
  2633. /* DOC
  2634. Detects native support for JSON handling functions.
  2635. */
  2636. // this will also succeed if you've loaded the JSON2.js polyfill ahead of time
  2637. // ... but that should be obvious. :)
  2638. Modernizr.addTest('json', 'JSON' in window && 'parse' in JSON && 'stringify' in JSON);
  2639. /**
  2640. * testAllProps determines whether a given CSS property is supported in the browser
  2641. *
  2642. * @memberOf Modernizr
  2643. * @name Modernizr.testAllProps
  2644. * @optionName Modernizr.testAllProps()
  2645. * @optionProp testAllProps
  2646. * @access public
  2647. * @function testAllProps
  2648. * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
  2649. * @param {string} [value] - String of the value to test
  2650. * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
  2651. * @returns {false|string} returns the string version of the property, or false if it is unsupported
  2652. * @example
  2653. *
  2654. * testAllProps determines whether a given CSS property, in some prefixed form,
  2655. * is supported by the browser.
  2656. *
  2657. * ```js
  2658. * testAllProps('boxSizing') // true
  2659. * ```
  2660. *
  2661. * It can optionally be given a CSS value in string form to test if a property
  2662. * value is valid
  2663. *
  2664. * ```js
  2665. * testAllProps('display', 'block') // true
  2666. * testAllProps('display', 'penguin') // false
  2667. * ```
  2668. *
  2669. * A boolean can be passed as a third parameter to skip the value check when
  2670. * native detection (@supports) isn't available.
  2671. *
  2672. * ```js
  2673. * testAllProps('shapeOutside', 'content-box', true);
  2674. * ```
  2675. */
  2676. function testAllProps(prop, value, skipValueTest) {
  2677. return testPropsAll(prop, undefined, undefined, value, skipValueTest);
  2678. }
  2679. ModernizrProto.testAllProps = testAllProps;
  2680. /*!
  2681. {
  2682. "name": "Font Ligatures",
  2683. "property": "ligatures",
  2684. "caniuse": "font-feature",
  2685. "notes": [{
  2686. "name": "Cross-browser Web Fonts",
  2687. "href": "https://www.sitepoint.com/cross-browser-web-fonts-part-3/"
  2688. }]
  2689. }
  2690. !*/
  2691. /* DOC
  2692. Detects support for OpenType ligatures
  2693. */
  2694. Modernizr.addTest('ligatures', testAllProps('fontFeatureSettings', '"liga" 1'));
  2695. /*!
  2696. {
  2697. "name": "Reverse Ordered Lists",
  2698. "property": "olreversed",
  2699. "notes": [{
  2700. "name": "Impressive Webs article",
  2701. "href": "https://www.impressivewebs.com/reverse-ordered-lists-html5/"
  2702. }],
  2703. "builderAliases": ["lists_reversed"]
  2704. }
  2705. !*/
  2706. /* DOC
  2707. Detects support for the `reversed` attribute on the `<ol>` element.
  2708. */
  2709. Modernizr.addTest('olreversed', 'reversed' in createElement('ol'));
  2710. /*!
  2711. {
  2712. "name": "MathML",
  2713. "property": "mathml",
  2714. "caniuse": "mathml",
  2715. "authors": ["Addy Osmani", "Davide P. Cervone", "David Carlisle"],
  2716. "knownBugs": ["Firefox < 4 will likely return a false, however it does support MathML inside XHTML documents"],
  2717. "notes": [{
  2718. "name": "W3C Spec",
  2719. "href": "https://www.w3.org/Math/"
  2720. }],
  2721. "polyfills": ["mathjax"]
  2722. }
  2723. !*/
  2724. /* DOC
  2725. Detects support for MathML, for mathematic equations in web pages.
  2726. */
  2727. // Based on work by Davide (@dpvc) and David (@davidcarlisle)
  2728. // in https://github.com/mathjax/MathJax/issues/182
  2729. Modernizr.addTest('mathml', function() {
  2730. var ret;
  2731. testStyles('#modernizr{position:absolute;display:inline-block}', function(node) {
  2732. node.innerHTML += '<math><mfrac><mi>xx</mi><mi>yy</mi></mfrac></math>';
  2733. ret = node.offsetHeight > node.offsetWidth;
  2734. });
  2735. return ret;
  2736. });
  2737. /*!
  2738. {
  2739. "name": "Media Source Extensions API",
  2740. "caniuse": "mediasource",
  2741. "property": "mediasource",
  2742. "notes": [{
  2743. "name": "MDN Docs",
  2744. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API"
  2745. }],
  2746. "builderAliases": ["media_source_extension_api"]
  2747. }
  2748. !*/
  2749. /* DOC
  2750. Detects support the Media Source Extensions API, which allows JavaScript to send byte streams to media codecs within web browsers that support HTML5 video.
  2751. */
  2752. Modernizr.addTest('mediasource', 'MediaSource' in window);
  2753. /*!
  2754. {
  2755. "name": "Message Channel",
  2756. "property": "messagechannel",
  2757. "authors": ["Raju Konga (@kongaraju)"],
  2758. "caniuse": "channel-messaging",
  2759. "tags": ["performance", "messagechannel"],
  2760. "notes": [{
  2761. "name": "W3C Spec",
  2762. "href": "https://www.w3.org/TR/2011/WD-webmessaging-20110317/#message-channels"
  2763. }, {
  2764. "name": "MDN Docs",
  2765. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API/Using_channel_messaging"
  2766. }]
  2767. }
  2768. !*/
  2769. /* DOC
  2770. Detects support for Message Channels, a way to communicate between different browsing contexts like iframes, workers, etc..
  2771. */
  2772. Modernizr.addTest('messagechannel', 'MessageChannel' in window);
  2773. /*!
  2774. {
  2775. "name": "Page Visibility API",
  2776. "property": "pagevisibility",
  2777. "caniuse": "pagevisibility",
  2778. "tags": ["performance"],
  2779. "notes": [{
  2780. "name": "MDN Docs",
  2781. "href": "https://developer.mozilla.org/en-US/docs/DOM/Using_the_Page_Visibility_API"
  2782. },{
  2783. "name": "W3C Spec",
  2784. "href": "https://www.w3.org/TR/2011/WD-page-visibility-20110602/"
  2785. },{
  2786. "name": "HTML5 Rocks Tutorial",
  2787. "href": "https://www.html5rocks.com/en/tutorials/pagevisibility/intro/"
  2788. }],
  2789. "polyfills": ["visibilityjs", "visiblyjs", "jquery-visibility"]
  2790. }
  2791. !*/
  2792. /* DOC
  2793. Detects support for the Page Visibility API, which can be used to disable unnecessary actions and otherwise improve user experience.
  2794. */
  2795. Modernizr.addTest('pagevisibility', !!prefixed('hidden', document, false));
  2796. /*!
  2797. {
  2798. "name": "Navigation Timing API",
  2799. "property": "performance",
  2800. "caniuse": "nav-timing",
  2801. "tags": ["performance"],
  2802. "authors": ["Scott Murphy (@uxder)"],
  2803. "notes": [{
  2804. "name": "W3C Spec",
  2805. "href": "https://www.w3.org/TR/navigation-timing/"
  2806. },{
  2807. "name": "HTML5 Rocks Tutorial",
  2808. "href": "https://www.html5rocks.com/en/tutorials/webperformance/basics/"
  2809. }],
  2810. "polyfills": ["perfnow"]
  2811. }
  2812. !*/
  2813. /* DOC
  2814. Detects support for the Navigation Timing API, for measuring browser and connection performance.
  2815. */
  2816. Modernizr.addTest('performance', !!prefixed('performance', window));
  2817. /*!
  2818. {
  2819. "name": "DOM Pointer Events API",
  2820. "property": "pointerevents",
  2821. "tags": ["input"],
  2822. "authors": ["Stu Cox"],
  2823. "notes": [{
  2824. "name": "W3C Spec (Pointer Events)",
  2825. "href": "https://www.w3.org/TR/pointerevents/"
  2826. },{
  2827. "name": "W3C Spec (Pointer Events Level 2)",
  2828. "href": "https://www.w3.org/TR/pointerevents2/"
  2829. },{
  2830. "name": "MDN Docs",
  2831. "href": "https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent"
  2832. }],
  2833. "warnings": ["This property name now refers to W3C DOM PointerEvents: https://github.com/Modernizr/Modernizr/issues/548#issuecomment-12812099"],
  2834. "polyfills": ["pep"]
  2835. }
  2836. !*/
  2837. /* DOC
  2838. Detects support for the DOM Pointer Events API, which provides a unified event interface for pointing input devices, as implemented in IE10+, Edge and Blink.
  2839. */
  2840. // **Test name hijacked!**
  2841. // Now refers to W3C DOM PointerEvents spec rather than the CSS pointer-events property.
  2842. Modernizr.addTest('pointerevents', function() {
  2843. // Cannot use `.prefixed()` for events, so test each prefix
  2844. var bool = false,
  2845. i = domPrefixes.length;
  2846. // Don't forget un-prefixed...
  2847. bool = Modernizr.hasEvent('pointerdown');
  2848. while (i-- && !bool) {
  2849. if (hasEvent(domPrefixes[i] + 'pointerdown')) {
  2850. bool = true;
  2851. }
  2852. }
  2853. return bool;
  2854. });
  2855. /*!
  2856. {
  2857. "name": "Pointer Lock API",
  2858. "property": "pointerlock",
  2859. "notes": [{
  2860. "name": "MDN Docs",
  2861. "href": "https://developer.mozilla.org/en-US/docs/API/Pointer_Lock_API"
  2862. }],
  2863. "builderAliases": ["pointerlock_api"]
  2864. }
  2865. !*/
  2866. /* DOC
  2867. Detects support the pointer lock API which allows you to lock the mouse cursor to the browser window.
  2868. */
  2869. // https://developer.mozilla.org/en-US/docs/API/Pointer_Lock_API
  2870. Modernizr.addTest('pointerlock', !!prefixed('exitPointerLock', document));
  2871. /*!
  2872. {
  2873. "name": "postMessage",
  2874. "property": "postmessage",
  2875. "caniuse": "x-doc-messaging",
  2876. "notes": [{
  2877. "name": "W3C Spec",
  2878. "href": "https://www.w3.org/TR/webmessaging/#crossDocumentMessages"
  2879. }],
  2880. "polyfills": ["easyxdm", "postmessage-jquery"],
  2881. "knownBugs": ["structuredclones - Android 2&3 can not send a structured clone of dates, filelists or regexps"],
  2882. "warnings": ["Some old WebKit versions have bugs. Stick with object, array, number and pixeldata to be safe."]
  2883. }
  2884. !*/
  2885. /* DOC
  2886. Detects support for the `window.postMessage` protocol for cross-document messaging.
  2887. `Modernizr.postmessage.structuredclones` reports if `postMessage` can send objects.
  2888. */
  2889. var support = new Boolean('postMessage' in window);
  2890. support.structuredclones = true;
  2891. try {
  2892. window.postMessage({ toString: function () { support.structuredclones = false; } }, '*');
  2893. } catch (e) {}
  2894. Modernizr.addTest('postmessage', support);
  2895. /*!
  2896. {
  2897. "name": "Proximity API",
  2898. "property": "proximity",
  2899. "authors": ["Cătălin Mariș"],
  2900. "tags": ["events", "proximity"],
  2901. "caniuse": "proximity",
  2902. "notes": [{
  2903. "name": "MDN Docs",
  2904. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Proximity_Events"
  2905. },{
  2906. "name": "W3C Spec",
  2907. "href": "https://www.w3.org/TR/proximity/"
  2908. }]
  2909. }
  2910. !*/
  2911. /* DOC
  2912. Detects support for an API that allows users to get proximity related information from the device's proximity sensor.
  2913. */
  2914. Modernizr.addAsyncTest(function() {
  2915. var timeout;
  2916. var timeoutTime = 300;
  2917. function advertiseSupport() {
  2918. // Clean up after ourselves
  2919. clearTimeout(timeout);
  2920. window.removeEventListener('deviceproximity', advertiseSupport);
  2921. // Advertise support as the browser supports
  2922. // the API and the device has a proximity sensor
  2923. addTest('proximity', true);
  2924. }
  2925. // Check if the browser has support for the API
  2926. if ('ondeviceproximity' in window && 'onuserproximity' in window) {
  2927. // Check if the device has a proximity sensor
  2928. // ( devices without such a sensor support the events but
  2929. // will never fire them resulting in a false positive )
  2930. window.addEventListener('deviceproximity', advertiseSupport);
  2931. // If the event doesn't fire in a reasonable amount of time,
  2932. // it means that the device doesn't have a proximity sensor,
  2933. // thus, we can advertise the "lack" of support
  2934. timeout = setTimeout(function() {
  2935. window.removeEventListener('deviceproximity', advertiseSupport);
  2936. addTest('proximity', false);
  2937. }, timeoutTime);
  2938. } else {
  2939. addTest('proximity', false);
  2940. }
  2941. });
  2942. /*!
  2943. {
  2944. "name": "QuerySelector",
  2945. "property": "queryselector",
  2946. "caniuse": "queryselector",
  2947. "tags": ["queryselector"],
  2948. "authors": ["Andrew Betts (@triblondon)"],
  2949. "notes": [{
  2950. "name": "W3C Spec",
  2951. "href": "https://www.w3.org/TR/selectors-api/#queryselectorall"
  2952. }],
  2953. "polyfills": ["css-selector-engine"]
  2954. }
  2955. !*/
  2956. /* DOC
  2957. Detects support for querySelector.
  2958. */
  2959. Modernizr.addTest('queryselector', 'querySelector' in document && 'querySelectorAll' in document);
  2960. /*!
  2961. {
  2962. "name": "Quota Storage Management API",
  2963. "property": "quotamanagement",
  2964. "tags": ["storage"],
  2965. "builderAliases": ["quota_management_api"],
  2966. "notes": [{
  2967. "name": "W3C Spec",
  2968. "href": "https://www.w3.org/TR/quota-api/"
  2969. }]
  2970. }
  2971. !*/
  2972. /* DOC
  2973. Detects the ability to request a specific amount of space for filesystem access
  2974. */
  2975. Modernizr.addTest('quotamanagement', function() {
  2976. var tempStorage = prefixed('temporaryStorage', navigator);
  2977. var persStorage = prefixed('persistentStorage', navigator);
  2978. return !!(tempStorage && persStorage);
  2979. });
  2980. /*!
  2981. {
  2982. "name": "requestAnimationFrame",
  2983. "property": "requestanimationframe",
  2984. "aliases": ["raf"],
  2985. "caniuse": "requestanimationframe",
  2986. "tags": ["animation"],
  2987. "authors": ["Addy Osmani"],
  2988. "notes": [{
  2989. "name": "W3C Spec",
  2990. "href": "https://www.w3.org/TR/animation-timing/"
  2991. }],
  2992. "polyfills": ["raf"]
  2993. }
  2994. !*/
  2995. /* DOC
  2996. Detects support for the `window.requestAnimationFrame` API, for offloading animation repainting to the browser for optimized performance.
  2997. */
  2998. Modernizr.addTest('requestanimationframe', !!prefixed('requestAnimationFrame', window), {aliases: ['raf']});
  2999. /*!
  3000. {
  3001. "name": "ServiceWorker API",
  3002. "property": "serviceworker",
  3003. "notes": [{
  3004. "name": "ServiceWorkers Explained",
  3005. "href": "https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md"
  3006. }]
  3007. }
  3008. !*/
  3009. /* DOC
  3010. ServiceWorkers (formerly Navigation Controllers) are a way to persistently cache resources to built apps that work better offline.
  3011. */
  3012. Modernizr.addTest('serviceworker', 'serviceWorker' in navigator);
  3013. /*!
  3014. {
  3015. "name": "SVG",
  3016. "property": "svg",
  3017. "caniuse": "svg",
  3018. "tags": ["svg"],
  3019. "authors": ["Erik Dahlstrom"],
  3020. "polyfills": [
  3021. "svgweb",
  3022. "raphael",
  3023. "amplesdk",
  3024. "canvg",
  3025. "svg-boilerplate",
  3026. "sie",
  3027. "dojogfx",
  3028. "fabricjs"
  3029. ]
  3030. }
  3031. !*/
  3032. /* DOC
  3033. Detects support for SVG in `<embed>` or `<object>` elements.
  3034. */
  3035. Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
  3036. /*!
  3037. {
  3038. "name": "Template strings",
  3039. "property": "templatestrings",
  3040. "notes": [{
  3041. "name": "MDN Docs",
  3042. "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Browser_compatibility"
  3043. }]
  3044. }
  3045. !*/
  3046. /* DOC
  3047. Template strings are string literals allowing embedded expressions.
  3048. */
  3049. Modernizr.addTest('templatestrings', function() {
  3050. var supports;
  3051. try {
  3052. // A number of tools, including uglifyjs and require, break on a raw "`", so
  3053. // use an eval to get around that.
  3054. // eslint-disable-next-line
  3055. eval('``');
  3056. supports = true;
  3057. } catch (e) {}
  3058. return !!supports;
  3059. });
  3060. /**
  3061. * List of property values to set for css tests. See ticket #21
  3062. * https://github.com/modernizr/modernizr/issues/21
  3063. *
  3064. * @memberOf Modernizr
  3065. * @name Modernizr._prefixes
  3066. * @optionName Modernizr._prefixes
  3067. * @optionProp prefixes
  3068. * @access public
  3069. * @example
  3070. *
  3071. * Modernizr._prefixes is the internal list of prefixes that we test against
  3072. * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
  3073. * an array of kebab-case vendor prefixes you can use within your code.
  3074. *
  3075. * Some common use cases include
  3076. *
  3077. * Generating all possible prefixed version of a CSS property
  3078. * ```js
  3079. * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
  3080. *
  3081. * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
  3082. * ```
  3083. *
  3084. * Generating all possible prefixed version of a CSS value
  3085. * ```js
  3086. * rule = 'display:' + Modernizr._prefixes.join('flex; display:') + 'flex';
  3087. *
  3088. * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
  3089. * ```
  3090. */
  3091. // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
  3092. // values in feature detects to continue to work
  3093. var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
  3094. // expose these for the plugin API. Look in the source for how to join() them against your input
  3095. ModernizrProto._prefixes = prefixes;
  3096. /**
  3097. * Modernizr.mq tests a given media query, live against the current state of the window
  3098. * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
  3099. * gist.github.com/786768
  3100. *
  3101. * @memberOf Modernizr
  3102. * @name Modernizr.mq
  3103. * @optionName Modernizr.mq()
  3104. * @optionProp mq
  3105. * @access public
  3106. * @function mq
  3107. * @param {string} mq - String of the media query we want to test
  3108. * @returns {boolean}
  3109. * @example
  3110. * Modernizr.mq allows for you to programmatically check if the current browser
  3111. * window state matches a media query.
  3112. *
  3113. * ```js
  3114. * var query = Modernizr.mq('(min-width: 900px)');
  3115. *
  3116. * if (query) {
  3117. * // the browser window is larger than 900px
  3118. * }
  3119. * ```
  3120. *
  3121. * Only valid media queries are supported, therefore you must always include values
  3122. * with your media query
  3123. *
  3124. * ```js
  3125. * // good
  3126. * Modernizr.mq('(min-width: 900px)');
  3127. *
  3128. * // bad
  3129. * Modernizr.mq('min-width');
  3130. * ```
  3131. *
  3132. * If you would just like to test that media queries are supported in general, use
  3133. *
  3134. * ```js
  3135. * Modernizr.mq('only all'); // true if MQ are supported, false if not
  3136. * ```
  3137. *
  3138. * Note that if the browser does not support media queries (e.g. old IE) mq will
  3139. * always return false.
  3140. */
  3141. var mq = (function() {
  3142. var matchMedia = window.matchMedia || window.msMatchMedia;
  3143. if (matchMedia) {
  3144. return function(mq) {
  3145. var mql = matchMedia(mq);
  3146. return mql && mql.matches || false;
  3147. };
  3148. }
  3149. return function(mq) {
  3150. var bool = false;
  3151. injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
  3152. bool = (window.getComputedStyle ?
  3153. window.getComputedStyle(node, null) :
  3154. node.currentStyle).position === 'absolute';
  3155. });
  3156. return bool;
  3157. };
  3158. })();
  3159. ModernizrProto.mq = mq;
  3160. /*!
  3161. {
  3162. "name": "Touch Events",
  3163. "property": "touchevents",
  3164. "caniuse": "touch",
  3165. "tags": ["media", "attribute"],
  3166. "notes": [{
  3167. "name": "Touch Events spec",
  3168. "href": "https://www.w3.org/TR/2013/WD-touch-events-20130124/"
  3169. }],
  3170. "warnings": [
  3171. "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
  3172. ],
  3173. "knownBugs": [
  3174. "False-positive on some configurations of Nokia N900",
  3175. "False-positive on some BlackBerry 6.0 builds – https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
  3176. ]
  3177. }
  3178. !*/
  3179. /* DOC
  3180. Indicates if the browser supports the W3C Touch Events API.
  3181. This *does not* necessarily reflect a touchscreen device:
  3182. * Older touchscreen devices only emulate mouse events
  3183. * Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that
  3184. * Some browsers & OS setups may enable touch APIs when no touchscreen is connected
  3185. * Future browsers may implement other event models for touch interactions
  3186. See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/).
  3187. It's recommended to bind both mouse and touch/pointer events simultaneously – see [this HTML5 Rocks tutorial](https://www.html5rocks.com/en/mobile/touchandmouse/).
  3188. This test will also return `true` for Firefox 4 Multitouch support.
  3189. */
  3190. // Chrome (desktop) used to lie about its support on this, but that has since been rectified: https://bugs.chromium.org/p/chromium/issues/detail?id=36415
  3191. Modernizr.addTest('touchevents', function() {
  3192. if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
  3193. return true;
  3194. }
  3195. // include the 'heartz' as a way to have a non matching MQ to help terminate the join
  3196. // https://github.com/Modernizr/Modernizr/issues/1814
  3197. var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
  3198. return mq(query);
  3199. });
  3200. /*!
  3201. {
  3202. "name": "Typed arrays",
  3203. "property": "typedarrays",
  3204. "caniuse": "typedarrays",
  3205. "tags": ["js"],
  3206. "authors": ["Stanley Stuart (@fivetanley)"],
  3207. "notes": [{
  3208. "name": "MDN Docs",
  3209. "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays"
  3210. },{
  3211. "name": "Kronos spec",
  3212. "href": "http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects"
  3213. }],
  3214. "polyfills": ["joshuabell-polyfill"]
  3215. }
  3216. !*/
  3217. /* DOC
  3218. Detects support for native binary data manipulation via Typed Arrays in JavaScript.
  3219. Does not check for DataView support; use `Modernizr.dataview` for that.
  3220. */
  3221. // Should fail in:
  3222. // Internet Explorer <= 9
  3223. // Firefox <= 3.6
  3224. // Chrome <= 6.0
  3225. // iOS Safari < 4.2
  3226. // Safari < 5.1
  3227. // Opera < 11.6
  3228. // Opera Mini, <= 7.0
  3229. // Android Browser < 4.0
  3230. // Blackberry Browser < 10.0
  3231. Modernizr.addTest('typedarrays', 'ArrayBuffer' in window);
  3232. /*!
  3233. {
  3234. "name": "Unicode Range",
  3235. "property": "unicoderange",
  3236. "notes": [{
  3237. "name": "W3C Spec",
  3238. "href": "https://www.w3.org/TR/2013/CR-css-fonts-3-20131003/#descdef-unicode-range"
  3239. }, {
  3240. "name": "24 Way article",
  3241. "href": "https://24ways.org/2011/creating-custom-font-stacks-with-unicode-range"
  3242. }]
  3243. }
  3244. !*/
  3245. Modernizr.addTest('unicoderange', function() {
  3246. return testStyles('@font-face{font-family:"unicodeRange";src:local("Arial");unicode-range:U+0020,U+002E}#modernizr span{font-size:20px;display:inline-block;font-family:"unicodeRange",monospace}#modernizr .mono{font-family:monospace}', function(elem) {
  3247. // we use specify a unicode-range of 002E (the `.` glyph,
  3248. // and a monospace font as the fallback. If the first of
  3249. // these test glyphs is a different width than the other
  3250. // the other three (which are all monospace), then we
  3251. // have a winner.
  3252. var testGlyphs = ['.', '.', 'm', 'm'];
  3253. for (var i = 0; i < testGlyphs.length; i++) {
  3254. var elm = createElement('span');
  3255. elm.innerHTML = testGlyphs[i];
  3256. elm.className = i % 2 ? 'mono' : '';
  3257. elem.appendChild(elm);
  3258. testGlyphs[i] = elm.clientWidth;
  3259. }
  3260. return (testGlyphs[0] !== testGlyphs[1] && testGlyphs[2] === testGlyphs[3]);
  3261. });
  3262. });
  3263. /*!
  3264. {
  3265. "name": "Unicode characters",
  3266. "property": "unicode",
  3267. "tags": ["encoding"],
  3268. "warnings": [
  3269. "positive Unicode support doesn't mean you can use it inside <title>, this seems more related to OS & Language packs"
  3270. ]
  3271. }
  3272. !*/
  3273. /* DOC
  3274. Detects if unicode characters are supported in the current document.
  3275. */
  3276. /**
  3277. * Unicode special character support
  3278. *
  3279. * Detection is made by testing missing glyph box rendering against star character
  3280. * If widths are the same, this "probably" means the browser didn't support the star character and rendered a glyph box instead
  3281. * Just need to ensure the font characters have different widths
  3282. */
  3283. Modernizr.addTest('unicode', function() {
  3284. var bool;
  3285. var missingGlyph = createElement('span');
  3286. var star = createElement('span');
  3287. testStyles('#modernizr{font-family:Arial,sans;font-size:300em;}', function(node) {
  3288. missingGlyph.innerHTML = isSVG ? '\u5987' : '&#5987;';
  3289. star.innerHTML = isSVG ? '\u2606' : '&#9734;';
  3290. node.appendChild(missingGlyph);
  3291. node.appendChild(star);
  3292. bool = 'offsetWidth' in missingGlyph && missingGlyph.offsetWidth !== star.offsetWidth;
  3293. });
  3294. return bool;
  3295. });
  3296. /*!
  3297. {
  3298. "name": "IE User Data API",
  3299. "property": "userdata",
  3300. "tags": ["storage"],
  3301. "authors": ["@stereobooster"],
  3302. "notes": [{
  3303. "name": "MSDN Documentation",
  3304. "href": "https://msdn.microsoft.com/en-us/library/ms531424.aspx"
  3305. }]
  3306. }
  3307. !*/
  3308. /* DOC
  3309. Detects support for IE userData for persisting data, an API similar to localStorage but supported since IE5.
  3310. */
  3311. Modernizr.addTest('userdata', !!createElement('div').addBehavior);
  3312. /*!
  3313. {
  3314. "name": "Vibration API",
  3315. "property": "vibrate",
  3316. "notes": [{
  3317. "name": "MDN Docs",
  3318. "href": "https://developer.mozilla.org/en/DOM/window.navigator.mozVibrate"
  3319. },{
  3320. "name": "W3C Spec",
  3321. "href": "https://www.w3.org/TR/vibration/"
  3322. }]
  3323. }
  3324. !*/
  3325. /* DOC
  3326. Detects support for the API that provides access to the vibration mechanism of the hosting device, to provide tactile feedback.
  3327. */
  3328. Modernizr.addTest('vibrate', !!prefixed('vibrate', navigator));
  3329. /*!
  3330. {
  3331. "name": "HTML5 Video",
  3332. "property": "video",
  3333. "caniuse": "video",
  3334. "tags": ["html5"],
  3335. "knownBugs": ["Without QuickTime, `Modernizr.video.h264` will be `undefined`; https://github.com/Modernizr/Modernizr/issues/546"],
  3336. "polyfills": [
  3337. "html5media",
  3338. "mediaelementjs",
  3339. "sublimevideo",
  3340. "videojs",
  3341. "leanbackplayer",
  3342. "videoforeverybody"
  3343. ]
  3344. }
  3345. !*/
  3346. /* DOC
  3347. Detects support for the video element, as well as testing what types of content it supports.
  3348. Subproperties are provided to describe support for `ogg`, `h264` and `webm` formats, e.g.:
  3349. ```javascript
  3350. Modernizr.video // true
  3351. Modernizr.video.ogg // 'probably'
  3352. ```
  3353. */
  3354. // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
  3355. // thx to NielsLeenheer and zcorpan
  3356. // Note: in some older browsers, "no" was a return value instead of empty string.
  3357. // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
  3358. // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
  3359. Modernizr.addTest('video', function() {
  3360. var elem = createElement('video');
  3361. var bool = false;
  3362. // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
  3363. try {
  3364. bool = !!elem.canPlayType;
  3365. if (bool) {
  3366. bool = new Boolean(bool);
  3367. bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, '');
  3368. // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
  3369. bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, '');
  3370. bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, '');
  3371. bool.vp9 = elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, '');
  3372. bool.hls = elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, '');
  3373. }
  3374. } catch (e) {}
  3375. return bool;
  3376. });
  3377. /*!
  3378. {
  3379. "name": "VML",
  3380. "property": "vml",
  3381. "tags": ["vml"],
  3382. "authors": ["Craig Andrews (@candrews)"],
  3383. "notes": [{
  3384. "name": "W3C Spec",
  3385. "href": "https://www.w3.org/TR/NOTE-VML"
  3386. },{
  3387. "name": "MSDN Documentation",
  3388. "href": "https://docs.microsoft.com/en-us/windows/desktop/VML/msdn-online-vml-introduction"
  3389. }]
  3390. }
  3391. !*/
  3392. /* DOC
  3393. Detects support for VML.
  3394. */
  3395. Modernizr.addTest('vml', function() {
  3396. var containerDiv = createElement('div');
  3397. var supports = false;
  3398. var shape;
  3399. if (!isSVG) {
  3400. containerDiv.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
  3401. shape = containerDiv.firstChild;
  3402. if ('style' in shape) {
  3403. shape.style.behavior = 'url(#default#VML)';
  3404. }
  3405. supports = shape ? typeof shape.adj === 'object' : true;
  3406. }
  3407. return supports;
  3408. });
  3409. /*!
  3410. {
  3411. "name": "Web Intents",
  3412. "property": "webintents",
  3413. "authors": ["Eric Bidelman"],
  3414. "notes": [{
  3415. "name": "Web Intents project site",
  3416. "href": "http://www.webintents.org/"
  3417. }],
  3418. "polyfills": ["webintents"],
  3419. "builderAliases": ["web_intents"]
  3420. }
  3421. !*/
  3422. /* DOC
  3423. Detects native support for the Web Intents APIs for service discovery and inter-application communication.
  3424. Chrome added support for this in v19, but [removed it again in v24](https://lists.w3.org/Archives/Public/public-web-intents/2012Nov/0000.html) because of "a number of areas for
  3425. development in both the API and specific user experience in Chrome". No other browsers currently support it, however a [JavaScript shim](http://www.webintents.org/#javascriptshim) is available.
  3426. */
  3427. Modernizr.addTest('webintents', !!prefixed('startActivity', navigator));
  3428. /*!
  3429. {
  3430. "name": "Web Animation API",
  3431. "property": "webanimations",
  3432. "caniuse": "web-animation",
  3433. "tags": ["webanimations"],
  3434. "polyfills": ["webanimationsjs"],
  3435. "notes": [{
  3436. "name": "Introducing Web Animations",
  3437. "href": "https://birtles.wordpress.com/2013/06/26/introducing-web-animations/"
  3438. }]
  3439. }
  3440. !*/
  3441. /* DOC
  3442. Detects support for the Web Animation API, a way to create css animations in js
  3443. */
  3444. Modernizr.addTest('webanimations', 'animate' in createElement('div'));
  3445. /*!
  3446. {
  3447. "name": "WebGL",
  3448. "property": "webgl",
  3449. "caniuse": "webgl",
  3450. "tags": ["webgl", "graphics"],
  3451. "polyfills": ["jebgl", "cwebgl", "iewebgl"]
  3452. }
  3453. !*/
  3454. Modernizr.addTest('webgl', function() {
  3455. return 'WebGLRenderingContext' in window;
  3456. });
  3457. /*!
  3458. {
  3459. "name": "WebSockets Support",
  3460. "property": "websockets",
  3461. "authors": ["Phread (@fearphage)", "Mike Sherov (@mikesherov)", "Burak Yigit Kaya (@BYK)"],
  3462. "caniuse": "websockets",
  3463. "tags": ["html5"],
  3464. "warnings": [
  3465. "This test will reject any old version of WebSockets even if it is not prefixed such as in Safari 5.1"
  3466. ],
  3467. "notes": [{
  3468. "name": "CLOSING State and Spec",
  3469. "href": "https://www.w3.org/TR/websockets/#the-websocket-interface"
  3470. }],
  3471. "polyfills": [
  3472. "sockjs",
  3473. "socketio",
  3474. "kaazing-websocket-gateway",
  3475. "websocketjs",
  3476. "atmosphere",
  3477. "graceful-websocket",
  3478. "portal",
  3479. "datachannel"
  3480. ]
  3481. }
  3482. !*/
  3483. var supports = false;
  3484. try {
  3485. supports = 'WebSocket' in window && window.WebSocket.CLOSING === 2;
  3486. } catch (e) {}
  3487. Modernizr.addTest('websockets', supports);
  3488. /*!
  3489. {
  3490. "name": "XDomainRequest",
  3491. "property": "xdomainrequest",
  3492. "tags": ["cors", "xdomainrequest", "ie9", "ie8"],
  3493. "authors": ["Ivan Pan (@hypotenuse)"],
  3494. "notes": [{
  3495. "name": "MDN Docs",
  3496. "href": "https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest"
  3497. }]
  3498. }
  3499. !*/
  3500. /* DOC
  3501. Detects support for XDomainRequest in IE9 & IE8
  3502. */
  3503. Modernizr.addTest('xdomainrequest', 'XDomainRequest' in window);
  3504. /*!
  3505. {
  3506. "name": "a[download] Attribute",
  3507. "property": "adownload",
  3508. "caniuse": "download",
  3509. "tags": ["media", "attribute"],
  3510. "builderAliases": ["a_download"],
  3511. "notes": [{
  3512. "name": "WHATWG Spec",
  3513. "href": "https://developers.whatwg.org/links.html#downloading-resources"
  3514. }]
  3515. }
  3516. !*/
  3517. /* DOC
  3518. When used on an `<a>`, this attribute signifies that the resource it points to should be downloaded by the browser rather than navigating to it.
  3519. */
  3520. Modernizr.addTest('adownload', !window.externalHost && 'download' in createElement('a'));
  3521. /*!
  3522. {
  3523. "name": "Audio Autoplay",
  3524. "property": "audioautoplay",
  3525. "authors": ["Jordy van Dortmont"],
  3526. "tags": ["audio"],
  3527. "async": true
  3528. }
  3529. !*/
  3530. /* DOC
  3531. Checks for support of the autoplay attribute of the audio element.
  3532. */
  3533. Modernizr.addAsyncTest(function() {
  3534. var timeout;
  3535. var waitTime = 200;
  3536. var retries = 5;
  3537. var currentTry = 0;
  3538. var elem = createElement('audio');
  3539. var elemStyle = elem.style;
  3540. function testAutoplay(arg) {
  3541. currentTry++;
  3542. clearTimeout(timeout);
  3543. var result = arg && arg.type === 'playing' || elem.currentTime !== 0;
  3544. if (!result && currentTry < retries) {
  3545. // Detection can be flaky if the browser is slow, so lets retry in a little bit
  3546. timeout = setTimeout(testAutoplay, waitTime);
  3547. return;
  3548. }
  3549. elem.removeEventListener('playing', testAutoplay, false);
  3550. addTest('audioautoplay', result);
  3551. // Cleanup, but don't assume elem is still in the page -
  3552. // an extension may already have removed it.
  3553. if (elem.parentNode) {
  3554. elem.parentNode.removeChild(elem);
  3555. }
  3556. }
  3557. // Skip the test if audio itself, or the autoplay element on it isn't supported
  3558. if (!Modernizr.audio || !('autoplay' in elem)) {
  3559. addTest('audioautoplay', false);
  3560. return;
  3561. }
  3562. elemStyle.position = 'absolute';
  3563. elemStyle.height = 0;
  3564. elemStyle.width = 0;
  3565. try {
  3566. if (Modernizr.audio.mp3) {
  3567. elem.src = 'data:audio/mpeg;base64,/+MYxAAAAANIAUAAAASEEB/jwOFM/0MM/90b/+RhST//w4NFwOjf///PZu////9lns5GFDv//l9GlUIEEIAAAgIg8Ir/JGq3/+MYxDsLIj5QMYcoAP0dv9HIjUcH//yYSg+CIbkGP//8w0bLVjUP///3Z0x5QCAv/yLjwtGKTEFNRTMuOTeqqqqqqqqqqqqq/+MYxEkNmdJkUYc4AKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
  3568. }
  3569. else if (Modernizr.audio.wav) {
  3570. elem.src = 'data:audio/wav;base64,UklGRjQAAABXQVZFZm10IBAAAAABAAEAEAAAABAAAAABAAgAZGF0YRAAAAB/f39/f39/f39/f39/f39/';
  3571. }
  3572. else {
  3573. addTest('audioautoplay', false);
  3574. return;
  3575. }
  3576. }
  3577. catch (e) {
  3578. addTest('audioautoplay', false);
  3579. return;
  3580. }
  3581. elem.setAttribute('autoplay', '');
  3582. elemStyle.cssText = 'display:none';
  3583. docElement.appendChild(elem);
  3584. // Wait for the next tick to add the listener, otherwise the element may
  3585. // not have time to play in high load situations (e.g. the test suite)
  3586. setTimeout(function() {
  3587. elem.addEventListener('playing', testAutoplay, false);
  3588. timeout = setTimeout(testAutoplay, waitTime);
  3589. }, 0);
  3590. });
  3591. /*!
  3592. {
  3593. "name": "Audio Loop Attribute",
  3594. "property": "audioloop",
  3595. "tags": ["audio", "media"]
  3596. }
  3597. !*/
  3598. /* DOC
  3599. Detects if an audio element can automatically restart, once it has finished
  3600. */
  3601. Modernizr.addTest('audioloop', 'loop' in createElement('audio'));
  3602. /*!
  3603. {
  3604. "name": "Audio Preload",
  3605. "property": "audiopreload",
  3606. "tags": ["audio", "media"],
  3607. "async": true,
  3608. "warnings": ["This test is very large – only include it if you absolutely need it"]
  3609. }
  3610. !*/
  3611. /* DOC
  3612. Detects if audio can be downloaded in the background before it starts playing in the `<audio>` element
  3613. */
  3614. Modernizr.addAsyncTest(function() {
  3615. var timeout;
  3616. var waitTime = 300;
  3617. var elem = createElement('audio');
  3618. var elemStyle = elem.style;
  3619. function testpreload(event) {
  3620. clearTimeout(timeout);
  3621. var result = event !== undefined && event.type === 'loadeddata' ? true : false; //need to check if event is not undefined here in case function is evoked from timeout (no parameters)
  3622. elem.removeEventListener('loadeddata', testpreload, false);
  3623. addTest('audiopreload', result);
  3624. // Cleanup, but don't assume elem is still in the page -
  3625. // an extension (eg Flashblock) may already have removed it.
  3626. if (elem.parentNode) {
  3627. elem.parentNode.removeChild(elem);
  3628. }
  3629. }
  3630. //skip the test if audio itself, or the preload
  3631. //element on it isn't supported
  3632. if (!Modernizr.audio || !('preload' in elem)) {
  3633. addTest('audiopreload', false);
  3634. return;
  3635. }
  3636. elemStyle.position = 'absolute';
  3637. elemStyle.height = 0;
  3638. elemStyle.width = 0;
  3639. try {
  3640. if (Modernizr.audio.mp3) {
  3641. //75ms of silence (minimum Mp3 duration loaded by Safari, not tested other formats thoroughly: may be possible to shrink base64 URI)
  3642. elem.src = 'data:audio/mpeg;base64,//MUxAAB6AXgAAAAAPP+c6nf//yi/6f3//MUxAMAAAIAAAjEcH//0fTX6C9Lf//0//MUxA4BeAIAAAAAAKX2/6zv//+IlR4f//MUxBMCMAH8AAAAABYWalVMQU1FMy45//MUxBUB0AH0AAAAADkuM1VVVVVVVVVV//MUxBgBUATowAAAAFVVVVVVVVVVVVVV';
  3643. }
  3644. else if (Modernizr.audio.m4a) {
  3645. elem.src = 'data:audio/x-m4a;base64,AAAAGGZ0eXBNNEEgAAACAGlzb21pc28yAAAACGZyZWUAAAAfbWRhdN4EAABsaWJmYWFjIDEuMjgAAAFoAQBHAAACiG1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAYAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAG0dHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAYAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAABUG1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAArEQAAAQAVcQAAAAAAC1oZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU291bmRIYW5kbGVyAAAAAPttaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAL9zdGJsAAAAW3N0c2QAAAAAAAAAAQAAAEttcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAACdlc2RzAAAAAAMZAAEABBFAFQAAAAABftAAAAAABQISCAYBAgAAABhzdHRzAAAAAAAAAAEAAAABAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAXAAAAAQAAABRzdGNvAAAAAAAAAAEAAAAoAAAAYHVkdGEAAABYbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAraWxzdAAAACOpdG9vAAAAG2RhdGEAAAABAAAAAExhdmY1Mi42NC4y';
  3646. }
  3647. else if (Modernizr.audio.ogg) {
  3648. elem.src = 'data:audio/ogg;base64,T2dnUwACAAAAAAAAAAD/QwAAAAAAAM2LVKsBHgF2b3JiaXMAAAAAAUSsAAAAAAAAgLsAAAAAAAC4AU9nZ1MAAAAAAAAAAAAA/0MAAAEAAADmvOe6Dy3/////////////////MgN2b3JiaXMdAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAwNzA2MjIAAAAAAQV2b3JiaXMfQkNWAQAAAQAYY1QpRplS0kqJGXOUMUaZYpJKiaWEFkJInXMUU6k515xrrLm1IIQQGlNQKQWZUo5SaRljkCkFmVIQS0kldBI6J51jEFtJwdaYa4tBthyEDZpSTCnElFKKQggZU4wpxZRSSkIHJXQOOuYcU45KKEG4nHOrtZaWY4updJJK5yRkTEJIKYWSSgelU05CSDWW1lIpHXNSUmpB6CCEEEK2IIQNgtCQVQAAAQDAQBAasgoAUAAAEIqhGIoChIasAgAyAAAEoCiO4iiOIzmSY0kWEBqyCgAAAgAQAADAcBRJkRTJsSRL0ixL00RRVX3VNlVV9nVd13Vd13UgNGQVAAABAEBIp5mlGiDCDGQYCA1ZBQAgAAAARijCEANCQ1YBAAABAABiKDmIJrTmfHOOg2Y5aCrF5nRwItXmSW4q5uacc845J5tzxjjnnHOKcmYxaCa05pxzEoNmKWgmtOacc57E5kFrqrTmnHPGOaeDcUYY55xzmrTmQWo21uaccxa0pjlqLsXmnHMi5eZJbS7V5pxzzjnnnHPOOeecc6oXp3NwTjjnnHOi9uZabkIX55xzPhmne3NCOOecc84555xzzjnnnHOC0JBVAAAQAABBGDaGcacgSJ+jgRhFiGnIpAfdo8MkaAxyCqlHo6ORUuoglFTGSSmdIDRkFQAACAAAIYQUUkghhRRSSCGFFFKIIYYYYsgpp5yCCiqppKKKMsoss8wyyyyzzDLrsLPOOuwwxBBDDK20EktNtdVYY62555xrDtJaaa211koppZRSSikIDVkFAIAAABAIGWSQQUYhhRRSiCGmnHLKKaigAkJDVgEAgAAAAgAAADzJc0RHdERHdERHdERHdETHczxHlERJlERJtEzL1ExPFVXVlV1b1mXd9m1hF3bd93Xf93Xj14VhWZZlWZZlWZZlWZZlWZZlWYLQkFUAAAgAAIAQQgghhRRSSCGlGGPMMeegk1BCIDRkFQAACAAgAAAAwFEcxXEkR3IkyZIsSZM0S7M8zdM8TfREURRN01RFV3RF3bRF2ZRN13RN2XRVWbVdWbZt2dZtX5Zt3/d93/d93/d93/d93/d1HQgNWQUASAAA6EiOpEiKpEiO4ziSJAGhIasAABkAAAEAKIqjOI7jSJIkSZakSZ7lWaJmaqZneqqoAqEhqwAAQAAAAQAAAAAAKJriKabiKaLiOaIjSqJlWqKmaq4om7Lruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7rui4QGrIKAJAAANCRHMmRHEmRFEmRHMkBQkNWAQAyAAACAHAMx5AUybEsS9M8zdM8TfRET/RMTxVd0QVCQ1YBAIAAAAIAAAAAADAkw1IsR3M0SZRUS7VUTbVUSxVVT1VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTVN0zRNIDRkJQAABADAYo3B5SAhJSXl3hDCEJOeMSYhtV4hBJGS3jEGFYOeMqIMct5C4xCDHggNWREARAEAAMYgxxBzyDlHqZMSOeeodJQa5xyljlJnKcWYYs0oldhSrI1zjlJHraOUYiwtdpRSjanGAgAAAhwAAAIshEJDVgQAUQAAhDFIKaQUYow5p5xDjCnnmHOGMeYcc44556B0UirnnHROSsQYc445p5xzUjonlXNOSiehAACAAAcAgAALodCQFQFAnACAQZI8T/I0UZQ0TxRFU3RdUTRd1/I81fRMU1U90VRVU1Vt2VRVWZY8zzQ901RVzzRV1VRVWTZVVZZFVdVt03V123RV3ZZt2/ddWxZ2UVVt3VRd2zdV1/Zd2fZ9WdZ1Y/I8VfVM03U903Rl1XVtW3VdXfdMU5ZN15Vl03Vt25VlXXdl2fc103Rd01Vl2XRd2XZlV7ddWfZ903WF35VlX1dlWRh2XfeFW9eV5XRd3VdlVzdWWfZ9W9eF4dZ1YZk8T1U903RdzzRdV3VdX1dd19Y105Rl03Vt2VRdWXZl2fddV9Z1zzRl2XRd2zZdV5ZdWfZ9V5Z13XRdX1dlWfhVV/Z1WdeV4dZt4Tdd1/dVWfaFV5Z14dZ1Ybl1XRg+VfV9U3aF4XRl39eF31luXTiW0XV9YZVt4VhlWTl+4ViW3feVZXRdX1ht2RhWWRaGX/id5fZ943h1XRlu3efMuu8Mx++k+8rT1W1jmX3dWWZfd47hGDq/8OOpqq+brisMpywLv+3rxrP7vrKMruv7qiwLvyrbwrHrvvP8vrAso+z6wmrLwrDatjHcvm4sv3Acy2vryjHrvlG2dXxfeArD83R1XXlmXcf2dXTjRzh+ygAAgAEHAIAAE8pAoSErAoA4AQCPJImiZFmiKFmWKIqm6LqiaLqupGmmqWmeaVqaZ5qmaaqyKZquLGmaaVqeZpqap5mmaJqua5qmrIqmKcumasqyaZqy7LqybbuubNuiacqyaZqybJqmLLuyq9uu7Oq6pFmmqXmeaWqeZ5qmasqyaZquq3meanqeaKqeKKqqaqqqraqqLFueZ5qa6KmmJ4qqaqqmrZqqKsumqtqyaaq2bKqqbbuq7Pqybeu6aaqybaqmLZuqatuu7OqyLNu6L2maaWqeZ5qa55mmaZqybJqqK1uep5qeKKqq5ommaqqqLJumqsqW55mqJ4qq6omea5qqKsumatqqaZq2bKqqLZumKsuubfu+68qybqqqbJuqauumasqybMu+78qq7oqmKcumqtqyaaqyLduy78uyrPuiacqyaaqybaqqLsuybRuzbPu6aJqybaqmLZuqKtuyLfu6LNu678qub6uqrOuyLfu67vqucOu6MLyybPuqrPq6K9u6b+sy2/Z9RNOUZVM1bdtUVVl2Zdn2Zdv2fdE0bVtVVVs2TdW2ZVn2fVm2bWE0Tdk2VVXWTdW0bVmWbWG2ZeF2Zdm3ZVv2ddeVdV/XfePXZd3murLty7Kt+6qr+rbu+8Jw667wCgAAGHAAAAgwoQwUGrISAIgCAACMYYwxCI1SzjkHoVHKOecgZM5BCCGVzDkIIZSSOQehlJQy5yCUklIIoZSUWgshlJRSawUAABQ4AAAE2KApsThAoSErAYBUAACD41iW55miatqyY0meJ4qqqaq27UiW54miaaqqbVueJ4qmqaqu6+ua54miaaqq6+q6aJqmqaqu67q6Lpqiqaqq67qyrpumqqquK7uy7Oumqqqq68quLPvCqrquK8uybevCsKqu68qybNu2b9y6ruu+7/vCka3rui78wjEMRwEA4AkOAEAFNqyOcFI0FlhoyEoAIAMAgDAGIYMQQgYhhJBSSiGllBIAADDgAAAQYEIZKDRkRQAQJwAAGEMppJRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkgppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkqppJRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoplVJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSCgCQinAAkHowoQwUGrISAEgFAACMUUopxpyDEDHmGGPQSSgpYsw5xhyUklLlHIQQUmktt8o5CCGk1FJtmXNSWosx5hgz56SkFFvNOYdSUoux5ppr7qS0VmuuNedaWqs115xzzbm0FmuuOdecc8sx15xzzjnnGHPOOeecc84FAOA0OACAHtiwOsJJ0VhgoSErAYBUAAACGaUYc8456BBSjDnnHIQQIoUYc845CCFUjDnnHHQQQqgYc8w5CCGEkDnnHIQQQgghcw466CCEEEIHHYQQQgihlM5BCCGEEEooIYQQQgghhBA6CCGEEEIIIYQQQgghhFJKCCGEEEIJoZRQAABggQMAQIANqyOcFI0FFhqyEgAAAgCAHJagUs6EQY5Bjw1BylEzDUJMOdGZYk5qMxVTkDkQnXQSGWpB2V4yCwAAgCAAIMAEEBggKPhCCIgxAABBiMwQCYVVsMCgDBoc5gHAA0SERACQmKBIu7iALgNc0MVdB0IIQhCCWBxAAQk4OOGGJ97whBucoFNU6iAAAAAAAAwA4AEA4KAAIiKaq7C4wMjQ2ODo8AgAAAAAABYA+AAAOD6AiIjmKiwuMDI0Njg6PAIAAAAAAAAAAICAgAAAAAAAQAAAAICAT2dnUwAE7AwAAAAAAAD/QwAAAgAAADuydfsFAQEBAQEACg4ODg==';
  3649. }
  3650. else if (Modernizr.audio.wav) {
  3651. elem.src = 'data:audio/wav;base64,UklGRvwZAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YdgZAAAAAAEA/v8CAP//AAABAP////8DAPz/BAD9/wEAAAAAAAAAAAABAP7/AgD//wAAAQD//wAAAQD//wAAAQD+/wIA//8AAAAAAAD//wIA/v8BAAAA//8BAAAA//8BAP//AQAAAP//AQD//wEAAAD//wEA//8BAP//AQD//wEA//8BAP//AQD+/wMA/f8DAP3/AgD+/wIA/////wMA/f8CAP7/AgD+/wMA/f8CAP7/AgD//wAAAAAAAAAAAQD+/wIA/v8CAP7/AwD9/wIA/v8BAAEA/v8CAP7/AQAAAAAAAAD//wEAAAD//wIA/f8DAP7/AQD//wEAAAD//wEA//8CAP7/AQD//wIA/v8CAP7/AQAAAAAAAAD//wEAAAAAAAAA//8BAP//AgD9/wQA+/8FAPz/AgAAAP//AgD+/wEAAAD//wIA/v8CAP3/BAD8/wQA/P8DAP7/AwD8/wQA/P8DAP7/AQAAAAAA//8BAP//AgD+/wEAAAD//wIA/v8BAP//AQD//wEAAAD//wEA//8BAAAAAAAAAP//AgD+/wEAAAAAAAAAAAD//wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AgD+/wIA/v8BAP//AQABAP7/AQD//wIA/v8CAP3/AwD/////AgD9/wMA/v8BAP//AQAAAP//AQD//wEA//8BAP//AAABAP//AAABAP//AQD//wAAAAACAP3/AwD9/wIA//8BAP//AQD//wEA//8BAP//AgD9/wMA/v8AAAIA/f8CAAAA/v8EAPv/BAD9/wIAAAD+/wQA+v8HAPr/BAD+/wEAAAD//wIA/f8EAPz/BAD7/wUA/P8EAPz/AwD+/wEAAAD//wEAAAAAAP//AgD8/wUA+/8FAPz/AwD9/wIA//8AAAEA/v8CAP//AQD//wAAAAABAP//AgD9/wMA/f8EAPz/AwD+/wAAAwD7/wUA/P8DAP7/AQAAAP//AgD+/wEAAQD+/wIA/v8BAAEA/v8CAP7/AQAAAP//AgD9/wMA/f8DAP7/AgD+/wEAAAAAAAEA//8AAAEA/v8DAP3/AgD//wEA//8BAP7/AwD9/wMA/v8BAP//AQAAAP//AgD9/wMA/v8BAP//AQAAAP//AgD+/wEAAQD+/wIA/////wIA//8AAAEA/f8DAP//AAABAP////8DAP3/AwD+/wEA//8BAP//AQAAAAAA//8BAP//AQD//wEA//8BAP//AAAAAAEA//8BAP7/AgD//wEA//8AAAAAAAAAAAAAAAD//wIA/v8BAAAA//8BAAEA/v8BAAAA//8DAPz/AwD+/wIA/v8CAP3/AwD+/wEAAAD//wEA//8BAAAA//8BAAAA/v8EAPv/BAD+/wAAAAABAP7/AgD//wAAAAABAP7/AgD//wAAAAAAAAAAAAABAP3/BAD8/wQA/f8BAAAAAAABAP7/AgD+/wIA/v8CAP7/AgD+/wIA/v8BAAAAAAD//wIA/f8DAP7/AAABAP//AAACAPz/BAD9/wIA//8AAP//AwD9/wMA/P8EAP3/AwD9/wIA//8BAP//AQD+/wMA/f8DAP7/AAABAP//AQAAAP//AQD//wIA/f8DAP7/AQAAAP//AQAAAAAA//8CAP7/AQABAP7/AgD+/wEAAQD+/wIA/v8CAP////8CAP7/AgD//wAAAAABAP7/AwD9/wIAAAD+/wMA/f8CAP//AQD+/wMA/f8CAP//AAACAPz/BQD6/wUA/v///wIA/v8CAP3/BAD7/wYA+v8FAPz/AwD/////AgD+/wEAAAD//wEAAAD//wIA/f8DAP7/AQAAAP//AgD//wAA//8BAAAAAAAAAP//AQD//wEA//8AAAIA/f8DAP3/AgAAAP//AQD//wEA//8AAAEA//8BAP////8CAP//AAABAP3/BAD9/wIA/v8BAAEA//8BAP7/AgD//wEA//8AAAEA//8BAP//AAAAAAEA//8BAP7/AgD//wEA//8AAAAAAQD+/wIA/v8BAAAAAAD//wIA/v8BAAAAAAAAAAAAAQD+/wMA/f8CAP//AQD//wIA/f8DAP7/AQD//wEA//8CAP7/AAABAP7/AwD9/wMA/v8AAAEA//8BAAAAAAD//wIA/v8BAAAA//8CAP7/AgD+/wEA//8CAP7/AgD//wAAAAAAAAAAAQD//wEA/v8DAPz/BQD8/wIA//8AAAEAAAD//wEA//8BAP//AQAAAAAA//8BAP//AgD+/wEAAAAAAP//AQD+/wMA/////wEA/v8CAP//AQD//wEA//8AAAEA//8BAAAA/v8EAPz/AwD+/wEAAAAAAAAA//8CAP7/AQD//wEA//8BAP//AAABAP7/AwD9/wIA//8BAP//AQD//wEA//8AAAEA/v8EAPv/BAD9/wIA//8BAP7/AwD9/wIA//8AAAEA//8BAP//AQD//wAAAQD//wEAAAD+/wMA/v8AAAIA/f8DAP7/AQD//wAAAQD+/wMA/f8CAP//AAABAP7/AgD+/wMA/f8CAP7/AQABAP7/AgD+/wIA/v8CAP7/AwD8/wMA//8AAAEA//8AAAAAAAABAP//AQD//wAAAQD//wIA/f8DAP3/AwD+/wAAAgD9/wIA//8AAAEAAAD+/wMA/P8FAPv/BAD9/wIA//8AAP//AgD+/wIA/v8BAAAAAAD//wEAAAAAAP//AQD//wEA//8BAP//AAABAP7/AwD9/wIA//8BAP//AAABAP//AQD//wAAAQD//wEA//8BAP//AAABAAAA//8BAP7/AwD9/wMA/f8DAP3/AgD//wEA//8BAP7/AgD//wAAAgD8/wQA/f8CAP//AQD+/wMA/f8CAP7/AgD//wAAAAAAAAAAAAABAP7/AwD9/wIA/v8DAP3/AwD9/wIA/v8DAPz/BQD7/wQA/f8CAP7/AwD9/wMA/f8CAP//AQAAAP7/AwD+/wEA//8AAAEAAAAAAP//AAABAP//AQAAAP7/AwD9/wMA/f8CAP//AQD//wEA//8AAAIA/f8CAAAA//8BAAAA//8BAAAA/v8EAPv/BAD9/wIA//8AAAEA/v8CAP//AAABAP//AAABAP//AAABAP7/AwD8/wQA/f8CAAAA/v8DAP3/AwD9/wMA/v8BAAAA//8BAAAA//8CAP7/AQAAAAAAAAAAAAAA//8CAP7/AgD+/wIA/v8CAP7/AgD//wAAAQD//wAAAQD//wAAAQD//wAAAQD+/wIA//8AAAAAAQD+/wMA/f8CAP//AQD//wEA//8AAAEA/v8DAP3/AgD//wAAAAABAP7/AwD9/wIA//8AAAEA/v8DAP3/AgD//wAAAAABAP7/AwD8/wMA/v8CAP//AAD//wIA/v8CAP7/AQABAP7/AQAAAP//AgD/////AQD//wEAAAD//wEA/v8EAPv/BAD9/wMA/v8BAAAA//8BAAEA/P8GAPr/BQD8/wMA/v8BAAAA//8CAP7/AQABAP3/BAD7/wYA+/8EAPz/AwD//wEA//8BAP7/BAD8/wMA/v8AAAIA/v8BAAAA//8BAAAA//8BAAAA//8CAP3/AwD+/wAAAgD8/wUA/P8DAP7/AAABAAAAAAD//wEAAAD//wIA/f8DAP7/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA/f8EAPz/AwD/////AgD+/wIA/f8DAP7/AgD+/wEA//8CAP7/AQD//wEAAAAAAP//AQAAAP//AgD9/wMA/v8BAAAA//8BAP//AQAAAP//AAACAP3/BAD7/wQA/v8BAAAA//8BAP//AQAAAP//AQAAAP7/BAD7/wUA+/8EAP3/AgD//wAAAQD+/wIA//8AAAEA/v8CAP//AQD+/wEAAAAAAAAAAAD//wEA//8CAP3/AwD9/wIA//8AAAAAAAAAAAAA//8BAP//AgD+/wEA//8CAP7/AQAAAP//AgD/////AgD/////AgD+/wIA//8AAP//AQABAP7/AgD9/wMA/v8CAP////8BAAAAAAAAAAAA//8CAP////8DAPz/AwD+/wEAAAAAAP//AQD//wEAAAD//wEAAAD+/wQA+/8FAPz/AgAAAP//AgD9/wMA/v8BAAAAAAD//wEAAAD//wIA/v8BAAAAAAD//wIA/v8BAAAA//8BAAAA//8CAP7/AQD//wEA//8BAAAA//8BAP//AAABAP//AQAAAP7/AgD//wEA//8AAAAAAQD+/wMA/P8EAP7///8DAPz/BQD8/wEAAQD+/wMA/v8AAAEA//8BAP//AQD//wEA/v8CAP//AQD//wAAAAABAAAA//8BAP//AQAAAAAA//8BAP//AgD+/wAAAQD//wIA/f8CAP//AQAAAP7/AwD9/wMA/v8BAP//AAABAP//AgD9/wIA//8BAAAA//8BAAAA//8CAP3/AwD+/wEAAAD+/wQA/P8DAP7/AAACAP7/AQAAAP//AQAAAP//AQAAAP//AgD9/wIAAAD//wIA/f8DAP7/AQD//wEA//8CAP7/AQD//wAAAQD//wEA//8AAAAAAQD//wEAAAD9/wUA+/8FAPz/AgD//wAAAQD//wAAAQD+/wMA/f8BAAEA/v8CAP7/AgD+/wIA/v8BAAAAAAAAAAAAAAD//wIA/v8CAP////8CAP7/AgD+/wIA/v8CAP7/AQAAAP//AQAAAP//AQD//wAAAQD//wAAAQD+/wMA/f8CAAAA/v8DAP3/AgAAAP//AQAAAP7/AwD9/wMA/v8BAP//AQD//wEAAAD+/wMA/f8CAAAA/v8CAP//AAAAAAEA//8AAAEA/v8DAP3/AwD9/wIA//8BAP//AgD8/wQA/v8BAAAA/v8CAP//AQD//wAAAAAAAAEA/f8EAPz/BAD9/wIA//8AAAAAAAABAP//AAAAAAAAAAABAP3/BAD9/wIA/v8BAAEA//8AAAAA//8CAP7/AgD9/wQA+/8FAPv/BQD8/wMA/f8DAP3/AwD+/wAAAgD9/wMA/f8CAAAA/v8EAPv/BQD7/wUA/P8DAP///v8DAP3/BAD8/wMA/f8DAP7/AQD//wEAAAD//wEA/v8CAAAA/v8CAP7/AgD//wAAAAAAAAAAAQD+/wIA//8AAAEA/v8DAPz/BAD9/wIA//8AAP//AgD//wEA/v8BAAAAAQD//wAAAAAAAAEA//8AAAEA//8BAP//AAABAP//AQD+/wIA/v8DAPz/BAD8/wQA/f8BAAAAAQD+/wMA/P8DAP//AAAAAAAAAAD//wMA+/8FAP3/AQABAP3/BAD8/wMA/v8BAAAA//8CAP3/AwD+/wEAAQD9/wMA/f8EAPz/BAD7/wQA/v8BAAEA/f8DAP7/AQAAAP//AgD+/wEAAAD//wIA/v8CAP7/AgD+/wEAAQD//wEA/v8CAP7/BAD7/wQA/f8CAAAA//8AAAAAAAABAP//AQD+/wEAAQD+/wMA/f8BAAEA/v8DAPz/AwD/////AwD8/wQA/P8DAP7/AgD//wAA//8BAAAAAAAAAP//AgD+/wEAAAD//wIA/v8BAAAA//8CAP3/AgD//wAAAQD+/wIA/v8BAAAA//8CAP7/AgD+/wEA//8CAP3/BAD7/wQA/v8BAAAA//8AAAEAAAD//wIA/f8DAP7/AgD+/wIA/v8CAP7/AgD+/wEAAAAAAP//AgD9/wMA/v8BAP//AgD9/wMA/v8AAAEA//8BAP//AQD//wEA//8AAAEA/v8EAPz/AgD//wAAAQAAAP//AAABAP//AQD//wEAAAD//wEA//8BAAEA/f8DAP7/AQABAP3/AwD+/wIA/////wEAAAAAAAAAAAD//wIA/v8CAP////8CAP7/AgD//wAA//8CAP3/BAD9/wAAAgD9/wMA/v8BAP//AQAAAP//AQAAAP//AgD9/wMA/f8EAPz/AwD+/wEAAAAAAAAAAAD//wIA/f8EAP3/AAABAAAA//8CAP7/AQAAAP//AQAAAAAA//8BAP//AQAAAP//AQAAAP//AQAAAP//AgD9/wMA/v8BAP//AQAAAP//AQD//wIA/v8CAP3/BAD9/wEAAAD//wEAAQD9/wMA/f8CAAAA/v8DAP3/AgD//wAAAQD+/wIA/v8CAP7/AQAAAP//AgD+/wEAAAAAAP//AwD7/wUA/f8BAAEA/v8BAAEA/v8DAP3/AgD//wEA//8BAP//AQD//wEA//8CAP3/BAD7/wQA/////wIA/v8AAAIA/v8CAP3/BAD7/wUA/P8DAP3/AwD9/wMA/v8AAAIA/v8CAP7/AgD+/wIA//8AAAEA/v8CAP7/AgD//wAAAAD//wEAAAAAAAAA//8BAP7/BAD7/wUA/P8CAAAA//8BAP//AQAAAP//AgD9/wMA/v8BAAAA//8BAAAA//8CAP3/AwD+/wEA//8CAP3/AwD+/wAAAwD8/wIAAAD//wIA/////wIA/v8CAP7/AgD+/wEAAAAAAAAAAAAAAP//AgD+/wIA//8AAAAA//8CAP7/AgD+/wEA//8CAP3/AwD9/wMA/v8BAP7/AwD9/wMA/f8CAP//AQD+/wIA//8BAP//AQD+/wMA/v8BAAAA//8BAAAA//8CAP7/AQAAAP//AgD+/wIA/v8CAP//AAAAAAEA//8BAP//AAABAAAA//8BAP//AQD//wEA//8BAP//AQAAAP//AQD//wEAAAD//wIA/f8CAAAA//8BAAAA//8BAP//AAABAP//AQD//wAAAAAAAAEA/v8CAP//AQD//wAAAAABAP7/AwD9/wIAAAD+/wIA//8BAP//AgD9/wMA/f8DAP7/AgD+/wEAAAAAAAEA/v8CAP7/AgD//wAAAAAAAAAAAAAAAP//AgD/////AgD9/wQA/f8BAAAAAAAAAAEA/f8DAP////8DAP3/AQABAP7/AgD//wAAAQD+/wMA/f8CAP7/AQABAP7/AwD7/wYA+v8FAP3/AQABAP7/AgD+/wMA/f8CAP7/AwD+/wEA//8BAP//AQAAAP7/BQD5/wcA+v8FAPz/AwD+/wIA/v8BAAAA//8DAPv/BQD8/wMA/////wEAAAAAAAAAAAD//wIA/f8DAP7/AQAAAP//AQAAAP//AgD+/wIA/v8BAAEA/f8EAPz/AwD+/wEA//8CAP7/AQD//wEA//8CAP7/AQAAAP//AgD+/wEAAAAAAAAAAAAAAAAAAAD//wIA/f8EAPz/AwD+/wEA//8CAP7/AgD+/wEAAQD+/wEAAQD+/wIA/////wIA//8AAAAAAAAAAAAAAAD//wEAAAAAAP//AgD9/wMA/v8BAP//AQAAAP//AQD//wEA//8BAP//AQD//wEA//8BAP//AQAAAP7/AwD9/wMA/v8BAP7/AwD9/wMA/v8BAP//AAABAP//AQD//wAAAAABAP//AAAAAAAAAQD//wEA/v8CAAAA/v8EAPv/BAD9/wIAAAD+/wMA/P8DAP//AAAAAP//AQD//wIA/f8DAP3/AwD9/wMA/v8BAAAA//8BAAAA//8CAP3/AwD9/wQA+/8FAPv/BQD8/wMA/v8BAAAA//8BAP//AgD+/wEAAAD//wIA/v8BAAEA/f8DAP3/AgAAAP//AQD//wAAAQD//wEA//8BAP//AQD//wEA/v8DAP3/AgAAAP7/AwD9/wIAAAD//wEAAAD//wIA/f8DAP7/AgD9/wQA+/8FAPz/AgAAAP//AgD9/wIA//8BAP//AQD//wEA//8BAP//AQD//wIA/f8DAP3/AgD//wAAAQD+/wIA/v8BAAEA/v8CAP7/AgD+/wMA/P8DAP//AAABAP7/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA/v8CAP3/BAD8/wMA/v8BAAAAAAD//wEAAAAAAAAAAAD//wEAAAAAAAAA//8BAP//AgD+/wEA//8CAP3/AwD9/wMA/f8EAPv/BAD+/wAAAQD//wEA//8BAP//AAABAP//AQD//wEAAAD//wEA//8BAP//AgD9/wMA/v8AAAIA/f8DAP7/AAACAP3/AwD+/wEA//8BAP//AQAAAP//AQAAAP7/AwD9/wMA/v8AAAEA//8BAP//AAAAAAEA//8AAAEA/v8CAP//AAAAAAEA/v8DAPz/BAD9/wEAAQD+/wEAAQD9/wQA/P8DAP7/AQAAAAAAAAAAAAAAAAAAAAAAAQD+/wIA/////wIA/v8BAAAA//8BAP//AQD//wEA//8BAAAA/v8EAPz/AwD///7/BAD8/wMA/////wIA/v8CAP////8CAP7/AgD+/wIA/v8CAP////8CAP7/AwD9/wIA/v8CAP//AAABAP7/AwD9/wEAAQD+/wMA/f8CAP//AAAAAAEA/v8DAPz/BAD9/wIA/v8CAP7/AgD//wAAAAD//wIA/v8CAP7/AQAAAAAA//8CAP7/AgD+/wIA/v8CAP7/AwD8/wUA+v8GAPv/AwD//wAAAAAAAAAA//8DAPv/BQD9/wAAAgD9/wMA/v8BAP//AQAAAP//AgD9/wMA/v8BAAAA//8BAAAAAAAAAP//AQAAAAAAAAD//wEA//8CAP3/AwD+/wAAAgD+/wEAAAD//wIA/v8CAP7/AgD/////AwD8/wUA/P8CAP//AQD//wIA/f8DAP3/AwD+/wAAAQD+/wMA/f8DAP3/AgD//wAAAQD//wEA//8BAP7/AwD+/wEA//8AAAEA//8CAPz/BAD9/wIA//8AAAEA/v8DAPz/BAD9/wIA//8AAAEA/v8CAP7/AgD//wEA/f8EAPz/BAD+////AgD//wAAAQD//wAAAQD//wEA//8BAP7/AwD+/wEA';
  3652. }
  3653. else {
  3654. addTest('audiopreload', false);
  3655. return;
  3656. }
  3657. }
  3658. catch (e) {
  3659. addTest('audiopreload', false);
  3660. return;
  3661. }
  3662. elem.setAttribute('preload', 'auto');
  3663. elem.style.cssText = 'display:none';
  3664. docElement.appendChild(elem);
  3665. // wait for the next tick to add the listener, otherwise the element may
  3666. // not have time to play in high load situations (e.g. the test suite)
  3667. setTimeout(function() {
  3668. elem.addEventListener('loadeddata', testpreload, false);
  3669. timeout = setTimeout(testpreload, waitTime);
  3670. }, 0);
  3671. });
  3672. /*!
  3673. {
  3674. "name": "Web Audio API",
  3675. "property": "webaudio",
  3676. "caniuse": "audio-api",
  3677. "polyfills": ["xaudiojs", "dynamicaudiojs", "audiolibjs"],
  3678. "tags": ["audio", "media"],
  3679. "builderAliases": ["audio_webaudio_api"],
  3680. "authors": ["Addy Osmani"],
  3681. "notes": [{
  3682. "name": "W3C Spec",
  3683. "href": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html"
  3684. }]
  3685. }
  3686. !*/
  3687. /* DOC
  3688. Detects the older non standard webaudio API, (as opposed to the standards based AudioContext API)
  3689. */
  3690. Modernizr.addTest('webaudio', function() {
  3691. var prefixed = 'webkitAudioContext' in window;
  3692. var unprefixed = 'AudioContext' in window;
  3693. if (Modernizr._config.usePrefixes) {
  3694. return prefixed || unprefixed;
  3695. }
  3696. return unprefixed;
  3697. });
  3698. /*!
  3699. {
  3700. "name": "Low Battery Level",
  3701. "property": "lowbattery",
  3702. "tags": ["hardware", "mobile"],
  3703. "builderAliases": ["battery_level"],
  3704. "authors": ["Paul Sayre"],
  3705. "notes": [{
  3706. "name": "MDN Docs",
  3707. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Navigator/battery"
  3708. }]
  3709. }
  3710. !*/
  3711. /* DOC
  3712. Enable a developer to remove CPU intensive CSS/JS when battery is low
  3713. */
  3714. Modernizr.addTest('lowbattery', function() {
  3715. var minLevel = 0.20;
  3716. var battery = prefixed('battery', navigator);
  3717. return !!(battery && !battery.charging && battery.level <= minLevel);
  3718. });
  3719. /*!
  3720. {
  3721. "name": "canvas blending support",
  3722. "property": "canvasblending",
  3723. "caniuse": "canvas-blending",
  3724. "tags": ["canvas"],
  3725. "notes": [{
  3726. "name": "W3C Spec",
  3727. "href": "https://drafts.fxtf.org/compositing-1/"
  3728. },{
  3729. "name": "Article",
  3730. "href": "https://web.archive.org/web/20171003232921/http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/"
  3731. }]
  3732. }
  3733. !*/
  3734. /* DOC
  3735. Detects if Photoshop style blending modes are available in canvas.
  3736. */
  3737. Modernizr.addTest('canvasblending', function() {
  3738. if (Modernizr.canvas === false) {
  3739. return false;
  3740. }
  3741. var ctx = createElement('canvas').getContext('2d');
  3742. // firefox 3 throws an error when setting an invalid `globalCompositeOperation`
  3743. try {
  3744. ctx.globalCompositeOperation = 'screen';
  3745. } catch (e) {}
  3746. return ctx.globalCompositeOperation === 'screen';
  3747. });
  3748. /*!
  3749. {
  3750. "name": "canvas.toDataURL type support",
  3751. "property": ["todataurljpeg", "todataurlpng", "todataurlwebp"],
  3752. "tags": ["canvas"],
  3753. "builderAliases": ["canvas_todataurl_type"],
  3754. "notes": [{
  3755. "name": "MDN Docs",
  3756. "href": "https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement.toDataURL"
  3757. }]
  3758. }
  3759. !*/
  3760. var canvas = createElement('canvas');
  3761. Modernizr.addTest('todataurljpeg', function() {
  3762. return !!Modernizr.canvas && canvas.toDataURL('image/jpeg').indexOf('data:image/jpeg') === 0;
  3763. });
  3764. Modernizr.addTest('todataurlpng', function() {
  3765. return !!Modernizr.canvas && canvas.toDataURL('image/png').indexOf('data:image/png') === 0;
  3766. });
  3767. Modernizr.addTest('todataurlwebp', function() {
  3768. var supports = false;
  3769. // firefox 3 throws an error when you use an "invalid" toDataUrl
  3770. try {
  3771. supports = !!Modernizr.canvas && canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
  3772. } catch (e) {}
  3773. return supports;
  3774. });
  3775. /*!
  3776. {
  3777. "name": "canvas winding support",
  3778. "property": "canvaswinding",
  3779. "tags": ["canvas"],
  3780. "notes": [{
  3781. "name": "Article",
  3782. "href": "https://web.archive.org/web/20170825024655/http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/"
  3783. }]
  3784. }
  3785. !*/
  3786. /* DOC
  3787. Determines if winding rules, which controls if a path can go clockwise or counterclockwise
  3788. */
  3789. Modernizr.addTest('canvaswinding', function() {
  3790. if (Modernizr.canvas === false) {
  3791. return false;
  3792. }
  3793. var ctx = createElement('canvas').getContext('2d');
  3794. ctx.rect(0, 0, 10, 10);
  3795. ctx.rect(2, 2, 6, 6);
  3796. return ctx.isPointInPath(5, 5, 'evenodd') === false;
  3797. });
  3798. /*!
  3799. {
  3800. "name": "getRandomValues",
  3801. "property": "getrandomvalues",
  3802. "caniuse": "getrandomvalues",
  3803. "tags": ["crypto"],
  3804. "authors": ["komachi"],
  3805. "notes": [{
  3806. "name": "W3C Editor’s Draft Spec",
  3807. "href": "https://w3c.github.io/webcrypto/#Crypto-interface-methods"
  3808. }],
  3809. "polyfills": ["polycrypt"]
  3810. }
  3811. !*/
  3812. /* DOC
  3813. Detects support for the window.crypto.getRandomValues method for generating cryptographically secure random numbers
  3814. */
  3815. // In Safari <=5.0 `window.crypto` exists (for some reason) but is `undefined`, so we have to check
  3816. // it’s truthy before checking for existence of `getRandomValues`
  3817. var crypto = prefixed('crypto', window);
  3818. var supportsGetRandomValues;
  3819. // Safari 6.0 supports crypto.getRandomValues, but does not return the array,
  3820. // which is required by the spec, so we need to actually check.
  3821. if (crypto && 'getRandomValues' in crypto && 'Uint32Array' in window) {
  3822. var array = new Uint32Array(10);
  3823. var values = crypto.getRandomValues(array);
  3824. supportsGetRandomValues = values && is(values[0], 'number');
  3825. }
  3826. Modernizr.addTest('getrandomvalues', !!supportsGetRandomValues);
  3827. /*!
  3828. {
  3829. "name": "cssall",
  3830. "property": "cssall",
  3831. "notes": [{
  3832. "name": "Spec",
  3833. "href": "https://drafts.csswg.org/css-cascade/#all-shorthand"
  3834. }]
  3835. }
  3836. !*/
  3837. /* DOC
  3838. Detects support for the `all` css property, which is a shorthand to reset all css properties (except direction and unicode-bidi) to their original value
  3839. */
  3840. Modernizr.addTest('cssall', 'all' in docElement.style);
  3841. /*!
  3842. {
  3843. "name": "CSS Animations",
  3844. "property": "cssanimations",
  3845. "caniuse": "css-animation",
  3846. "polyfills": ["transformie", "csssandpaper"],
  3847. "tags": ["css"],
  3848. "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
  3849. "notes": [{
  3850. "name": "Article: 'Dispelling the Android CSS animation myths'",
  3851. "href": "https://web.archive.org/web/20180602074607/https://daneden.me/2011/12/14/putting-up-with-androids-bullshit/"
  3852. }]
  3853. }
  3854. !*/
  3855. /* DOC
  3856. Detects whether or not elements can be animated using CSS
  3857. */
  3858. Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
  3859. /*!
  3860. {
  3861. "name": "Appearance",
  3862. "property": "appearance",
  3863. "caniuse": "css-appearance",
  3864. "tags": ["css"],
  3865. "notes": [{
  3866. "name": "MDN Docs",
  3867. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance"
  3868. },{
  3869. "name": "CSS-Tricks CSS Almanac: appearance",
  3870. "href": "https://css-tricks.com/almanac/properties/a/appearance/"
  3871. }]
  3872. }
  3873. !*/
  3874. /* DOC
  3875. Detects support for the `appearance` css property, which is used to make an
  3876. element inherit the style of a standard user interface element. It can also be
  3877. used to remove the default styles of an element, such as input and buttons.
  3878. */
  3879. Modernizr.addTest('appearance', testAllProps('appearance'));
  3880. /*!
  3881. {
  3882. "name": "Backdrop Filter",
  3883. "property": "backdropfilter",
  3884. "authors": ["Brian Seward"],
  3885. "tags": ["css"],
  3886. "caniuse": "css-backdrop-filter",
  3887. "notes": [{
  3888. "name": "W3C Editor’s Draft Spec",
  3889. "href": "https://drafts.fxtf.org/filters-2/#BackdropFilterProperty"
  3890. },{
  3891. "name": "WebKit Blog introduction + Demo",
  3892. "href": "https://www.webkit.org/blog/3632/introducing-backdrop-filters/"
  3893. }]
  3894. }
  3895. !*/
  3896. /* DOC
  3897. Detects support for CSS Backdrop Filters, allowing for background blur effects like those introduced in iOS 7. Support for this was added to iOS Safari/WebKit in iOS 9.
  3898. */
  3899. Modernizr.addTest('backdropfilter', testAllProps('backdropFilter'));
  3900. /*!
  3901. {
  3902. "name": "CSS Background Blend Mode",
  3903. "property": "backgroundblendmode",
  3904. "caniuse": "css-backgroundblendmode",
  3905. "tags": ["css"],
  3906. "notes": [{
  3907. "name": "CSS Blend Modes could be the next big thing in Web Design",
  3908. "href": "https://medium.com/@bennettfeely/css-blend-modes-could-be-the-next-big-thing-in-web-design-6b51bf53743a"
  3909. },{
  3910. "name": "Demo",
  3911. "href": "https://bennettfeely.com/gradients/"
  3912. }]
  3913. }
  3914. !*/
  3915. /* DOC
  3916. Detects the ability for the browser to composite backgrounds using blending modes similar to ones found in Photoshop or Illustrator.
  3917. */
  3918. Modernizr.addTest('backgroundblendmode', prefixed('backgroundBlendMode', 'text'));
  3919. /*!
  3920. {
  3921. "name": "CSS Background Clip Text",
  3922. "property": "backgroundcliptext",
  3923. "authors": ["ausi"],
  3924. "tags": ["css"],
  3925. "notes": [{
  3926. "name": "CSS Tricks Article",
  3927. "href": "https://css-tricks.com/image-under-text/"
  3928. },{
  3929. "name": "MDN Docs",
  3930. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip"
  3931. },{
  3932. "name": "Related Github Issue",
  3933. "href": "https://github.com/Modernizr/Modernizr/issues/199"
  3934. }]
  3935. }
  3936. !*/
  3937. /* DOC
  3938. Detects the ability to control specifies whether or not an element's background
  3939. extends beyond its border in CSS
  3940. */
  3941. Modernizr.addTest('backgroundcliptext', function() {
  3942. return testAllProps('backgroundClip', 'text');
  3943. });
  3944. /*!
  3945. {
  3946. "name": "Background Position Shorthand",
  3947. "property": "bgpositionshorthand",
  3948. "tags": ["css"],
  3949. "builderAliases": ["css_backgroundposition_shorthand"],
  3950. "notes": [{
  3951. "name": "MDN Docs",
  3952. "href": "https://developer.mozilla.org/en/CSS/background-position"
  3953. }, {
  3954. "name": "W3C Spec",
  3955. "href": "https://www.w3.org/TR/css3-background/#background-position"
  3956. }, {
  3957. "name": "Demo",
  3958. "href": "https://jsfiddle.net/Blink/bBXvt/"
  3959. }]
  3960. }
  3961. !*/
  3962. /* DOC
  3963. Detects if you can use the shorthand method to define multiple parts of an
  3964. element's background-position simultaneously.
  3965. eg `background-position: right 10px bottom 10px`
  3966. */
  3967. Modernizr.addTest('bgpositionshorthand', function() {
  3968. var elem = createElement('a');
  3969. var eStyle = elem.style;
  3970. var val = 'right 10px bottom 10px';
  3971. eStyle.cssText = 'background-position: ' + val + ';';
  3972. return (eStyle.backgroundPosition === val);
  3973. });
  3974. /*!
  3975. {
  3976. "name": "Background Position XY",
  3977. "property": "bgpositionxy",
  3978. "tags": ["css"],
  3979. "builderAliases": ["css_backgroundposition_xy"],
  3980. "authors": ["Allan Lei", "Brandom Aaron"],
  3981. "notes": [{
  3982. "name": "Demo",
  3983. "href": "https://jsfiddle.net/allanlei/R8AYS/"
  3984. }, {
  3985. "name": "Adapted From",
  3986. "href": "https://github.com/brandonaaron/jquery-cssHooks/blob/master/bgpos.js"
  3987. }]
  3988. }
  3989. !*/
  3990. /* DOC
  3991. Detects the ability to control an element's background position using css
  3992. */
  3993. Modernizr.addTest('bgpositionxy', function() {
  3994. return testAllProps('backgroundPositionX', '3px', true) && testAllProps('backgroundPositionY', '5px', true);
  3995. });
  3996. /*!
  3997. {
  3998. "name": "Background Repeat",
  3999. "property": ["bgrepeatspace", "bgrepeatround"],
  4000. "tags": ["css"],
  4001. "builderAliases": ["css_backgroundrepeat"],
  4002. "authors": ["Ryan Seddon"],
  4003. "notes": [{
  4004. "name": "MDN Docs",
  4005. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat"
  4006. }, {
  4007. "name": "Test Page",
  4008. "href": "https://jsbin.com/uzesun/"
  4009. }, {
  4010. "name": "Demo",
  4011. "href": "https://jsfiddle.net/ryanseddon/yMLTQ/6/"
  4012. }]
  4013. }
  4014. !*/
  4015. /* DOC
  4016. Detects the ability to use round and space as properties for background-repeat
  4017. */
  4018. // Must value-test these
  4019. Modernizr.addTest('bgrepeatround', testAllProps('backgroundRepeat', 'round'));
  4020. Modernizr.addTest('bgrepeatspace', testAllProps('backgroundRepeat', 'space'));
  4021. /*!
  4022. {
  4023. "name": "Background Size",
  4024. "property": "backgroundsize",
  4025. "tags": ["css"],
  4026. "knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"],
  4027. "notes": [{
  4028. "name": "Related Issue",
  4029. "href": "https://github.com/Modernizr/Modernizr/issues/396"
  4030. }]
  4031. }
  4032. !*/
  4033. Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true));
  4034. /*!
  4035. {
  4036. "name": "Background Size Cover",
  4037. "property": "bgsizecover",
  4038. "tags": ["css"],
  4039. "builderAliases": ["css_backgroundsizecover"],
  4040. "notes": [{
  4041. "name": "MDN Docs",
  4042. "href": "https://developer.mozilla.org/en/CSS/background-size"
  4043. }]
  4044. }
  4045. !*/
  4046. // Must test value, as this specifically tests the `cover` value
  4047. Modernizr.addTest('bgsizecover', testAllProps('backgroundSize', 'cover'));
  4048. /*!
  4049. {
  4050. "name": "Border Image",
  4051. "property": "borderimage",
  4052. "caniuse": "border-image",
  4053. "polyfills": ["css3pie"],
  4054. "knownBugs": ["Android < 2.0 is true, but has a broken implementation"],
  4055. "tags": ["css"]
  4056. }
  4057. !*/
  4058. Modernizr.addTest('borderimage', testAllProps('borderImage', 'url() 1', true));
  4059. /*!
  4060. {
  4061. "name": "Border Radius",
  4062. "property": "borderradius",
  4063. "caniuse": "border-radius",
  4064. "polyfills": ["css3pie"],
  4065. "tags": ["css"],
  4066. "notes": [{
  4067. "name": "Comprehensive Compat Chart",
  4068. "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance"
  4069. }]
  4070. }
  4071. !*/
  4072. Modernizr.addTest('borderradius', testAllProps('borderRadius', '0px', true));
  4073. /*!
  4074. {
  4075. "name": "Box Decoration Break",
  4076. "property": "boxdecorationbreak",
  4077. "caniuse": "css-boxdecorationbreak",
  4078. "tags": ["css"],
  4079. "notes": [{
  4080. "name": "MDN Docs",
  4081. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/box-decoration-break"
  4082. }, {
  4083. "name": "Demo",
  4084. "href": "https://jsbin.com/xojoro/edit?css,output"
  4085. }]
  4086. }
  4087. !*/
  4088. /* DOC
  4089. Specifies how an element's fragments should be rendered when broken across multiple lines, columns, or pages.
  4090. */
  4091. Modernizr.addTest('boxdecorationbreak', testAllProps('boxDecorationBreak', 'slice'));
  4092. /*!
  4093. {
  4094. "name": "Box Shadow",
  4095. "property": "boxshadow",
  4096. "caniuse": "css-boxshadow",
  4097. "tags": ["css"],
  4098. "knownBugs": [
  4099. "WebOS false positives on this test.",
  4100. "The Kindle Silk browser false positives"
  4101. ]
  4102. }
  4103. !*/
  4104. Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true));
  4105. /*!
  4106. {
  4107. "name": "Box Sizing",
  4108. "property": "boxsizing",
  4109. "caniuse": "css3-boxsizing",
  4110. "polyfills": ["borderboxmodel", "boxsizingpolyfill", "borderbox"],
  4111. "tags": ["css"],
  4112. "builderAliases": ["css_boxsizing"],
  4113. "notes": [{
  4114. "name": "MDN Docs",
  4115. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing"
  4116. },{
  4117. "name": "Related Github Issue",
  4118. "href": "https://github.com/Modernizr/Modernizr/issues/248"
  4119. }]
  4120. }
  4121. !*/
  4122. Modernizr.addTest('boxsizing', testAllProps('boxSizing', 'border-box', true) && (document.documentMode === undefined || document.documentMode > 7));
  4123. /*!
  4124. {
  4125. "name": "CSS Calc",
  4126. "property": "csscalc",
  4127. "caniuse": "calc",
  4128. "tags": ["css"],
  4129. "builderAliases": ["css_calc"],
  4130. "authors": ["@calvein"]
  4131. }
  4132. !*/
  4133. /* DOC
  4134. Method of allowing calculated values for length units. For example:
  4135. ```css
  4136. //lem {
  4137. width: calc(100% - 3em);
  4138. }
  4139. ```
  4140. */
  4141. Modernizr.addTest('csscalc', function() {
  4142. var prop = 'width:';
  4143. var value = 'calc(10px);';
  4144. var el = createElement('a');
  4145. el.style.cssText = prop + prefixes.join(value + prop);
  4146. return !!el.style.length;
  4147. });
  4148. /*!
  4149. {
  4150. "name": "CSS :checked pseudo-selector",
  4151. "caniuse": "css-sel3",
  4152. "property": "checked",
  4153. "tags": ["css"],
  4154. "notes": [{
  4155. "name": "Related Github Issue",
  4156. "href": "https://github.com/Modernizr/Modernizr/pull/879"
  4157. }]
  4158. }
  4159. !*/
  4160. Modernizr.addTest('checked', function() {
  4161. return testStyles('#modernizr {position:absolute} #modernizr input {margin-left:10px} #modernizr :checked {margin-left:20px;display:block}', function(elem) {
  4162. var cb = createElement('input');
  4163. cb.setAttribute('type', 'checkbox');
  4164. cb.setAttribute('checked', 'checked');
  4165. elem.appendChild(cb);
  4166. return cb.offsetLeft === 20;
  4167. });
  4168. });
  4169. /*!
  4170. {
  4171. "name": "CSS Font ch Units",
  4172. "authors": ["Ron Waldon (@jokeyrhyme)"],
  4173. "property": "csschunit",
  4174. "tags": ["css"],
  4175. "notes": [{
  4176. "name": "W3C Spec",
  4177. "href": "https://www.w3.org/TR/css3-values/#font-relative-lengths"
  4178. }]
  4179. }
  4180. !*/
  4181. Modernizr.addTest('csschunit', function() {
  4182. var elemStyle = modElem.elem.style;
  4183. var supports;
  4184. try {
  4185. elemStyle.fontSize = '3ch';
  4186. supports = elemStyle.fontSize.indexOf('ch') !== -1;
  4187. } catch (e) {
  4188. supports = false;
  4189. }
  4190. return supports;
  4191. });
  4192. /*!
  4193. {
  4194. "name": "CSS Columns",
  4195. "property": "csscolumns",
  4196. "caniuse": "multicolumn",
  4197. "polyfills": ["css3multicolumnjs"],
  4198. "tags": ["css"]
  4199. }
  4200. !*/
  4201. (function() {
  4202. Modernizr.addTest('csscolumns', function() {
  4203. var bool = false;
  4204. var test = testAllProps('columnCount');
  4205. try {
  4206. bool = !!test;
  4207. if (bool) {
  4208. bool = new Boolean(bool);
  4209. }
  4210. } catch (e) {}
  4211. return bool;
  4212. });
  4213. var props = ['Width', 'Span', 'Fill', 'Gap', 'Rule', 'RuleColor', 'RuleStyle', 'RuleWidth', 'BreakBefore', 'BreakAfter', 'BreakInside'];
  4214. var name, test;
  4215. for (var i = 0; i < props.length; i++) {
  4216. name = props[i].toLowerCase();
  4217. test = testAllProps('column' + props[i]);
  4218. // break-before, break-after & break-inside are not "column"-prefixed in spec
  4219. if (name === 'breakbefore' || name === 'breakafter' || name === 'breakinside') {
  4220. test = test || testAllProps(props[i]);
  4221. }
  4222. Modernizr.addTest('csscolumns.' + name, test);
  4223. }
  4224. })();
  4225. /*!
  4226. {
  4227. "name": "CSS Grid (old & new)",
  4228. "property": ["cssgrid", "cssgridlegacy"],
  4229. "authors": ["Faruk Ates"],
  4230. "tags": ["css"],
  4231. "notes": [{
  4232. "name": "The new, standardized CSS Grid",
  4233. "href": "https://www.w3.org/TR/css3-grid-layout/"
  4234. }, {
  4235. "name": "The _old_ CSS Grid (legacy)",
  4236. "href": "https://www.w3.org/TR/2011/WD-css3-grid-layout-20110407/"
  4237. }]
  4238. }
  4239. !*/
  4240. // `grid-columns` is only in the old syntax, `grid-column` exists in both and so `grid-template-rows` is used for the new syntax.
  4241. Modernizr.addTest('cssgridlegacy', testAllProps('grid-columns', '10px', true));
  4242. Modernizr.addTest('cssgrid', testAllProps('grid-template-rows', 'none', true));
  4243. /*!
  4244. {
  4245. "name": "CSS Cubic Bezier Range",
  4246. "property": "cubicbezierrange",
  4247. "tags": ["css"],
  4248. "builderAliases": ["css_cubicbezierrange"],
  4249. "authors": ["@calvein"],
  4250. "warnings": ["cubic-bezier values can't be > 1 for Webkit until [bug #45761](https://bugs.webkit.org/show_bug.cgi?id=45761) is fixed"],
  4251. "notes": [{
  4252. "name": "Comprehensive Compat Chart",
  4253. "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance/"
  4254. }]
  4255. }
  4256. !*/
  4257. Modernizr.addTest('cubicbezierrange', function() {
  4258. var el = createElement('a');
  4259. el.style.cssText = prefixes.join('transition-timing-function:cubic-bezier(1,0,0,1.1); ');
  4260. return !!el.style.length;
  4261. });
  4262. /*!
  4263. {
  4264. "name": "CSS Custom Properties",
  4265. "property": "customproperties",
  4266. "caniuse": "css-variables",
  4267. "tags": ["css"],
  4268. "builderAliases": ["css_customproperties"],
  4269. "notes": [{
  4270. "name": "MDN Docs",
  4271. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/--*"
  4272. },{
  4273. "name": "W3C Spec",
  4274. "href": "https://drafts.csswg.org/css-variables/"
  4275. }]
  4276. }
  4277. !*/
  4278. var supportsFn = (window.CSS && window.CSS.supports.bind(window.CSS)) || (window.supportsCSS);
  4279. Modernizr.addTest('customproperties', !!supportsFn && (supportsFn('--f:0') || supportsFn('--f', 0)));
  4280. /*!
  4281. {
  4282. "name": "CSS Display run-in",
  4283. "property": "display-runin",
  4284. "authors": ["alanhogan"],
  4285. "tags": ["css"],
  4286. "builderAliases": ["css_displayrunin"],
  4287. "notes": [{
  4288. "name": "CSS Tricks Article",
  4289. "href": "https://web.archive.org/web/20111204150927/http://css-tricks.com:80/596-run-in/"
  4290. },{
  4291. "name": "Related Github Issue",
  4292. "href": "https://github.com/Modernizr/Modernizr/issues/198"
  4293. }]
  4294. }
  4295. !*/
  4296. Modernizr.addTest('displayrunin', testAllProps('display', 'run-in'),
  4297. {aliases: ['display-runin']});
  4298. /*!
  4299. {
  4300. "name": "CSS Display table",
  4301. "property": "displaytable",
  4302. "caniuse": "css-table",
  4303. "authors": ["scottjehl"],
  4304. "tags": ["css"],
  4305. "builderAliases": ["css_displaytable"],
  4306. "notes": [{
  4307. "name": "Detects for all additional table display values",
  4308. "href": "https://pastebin.com/Gk9PeVaQ"
  4309. }]
  4310. }
  4311. !*/
  4312. /* DOC
  4313. `display: table` and `table-cell` test. (both are tested under one name `table-cell` )
  4314. */
  4315. // If a document is in rtl mode this test will fail so we force ltr mode on the injected
  4316. // element https://github.com/Modernizr/Modernizr/issues/716
  4317. testStyles('#modernizr{display: table; direction: ltr}#modernizr div{display: table-cell; padding: 10px}', function(elem) {
  4318. var ret;
  4319. var child = elem.childNodes;
  4320. ret = child[0].offsetLeft < child[1].offsetLeft;
  4321. Modernizr.addTest('displaytable', ret, {aliases: ['display-table']});
  4322. }, 2);
  4323. /*!
  4324. {
  4325. "name": "CSS text-overflow ellipsis",
  4326. "property": "ellipsis",
  4327. "caniuse": "text-overflow",
  4328. "polyfills": ["text-overflow"],
  4329. "tags": ["css"]
  4330. }
  4331. !*/
  4332. Modernizr.addTest('ellipsis', testAllProps('textOverflow', 'ellipsis'));
  4333. /*!
  4334. {
  4335. "name": "CSS.escape()",
  4336. "property": "cssescape",
  4337. "polyfills": ["css-escape"],
  4338. "tags": ["css", "cssom"]
  4339. }
  4340. !*/
  4341. /* DOC
  4342. Tests for `CSS.escape()` support.
  4343. */
  4344. var CSS = window.CSS;
  4345. Modernizr.addTest('cssescape', CSS ? typeof CSS.escape === 'function' : false);
  4346. /*!
  4347. {
  4348. "name": "CSS Font ex Units",
  4349. "authors": ["Ron Waldon (@jokeyrhyme)"],
  4350. "property": "cssexunit",
  4351. "tags": ["css"],
  4352. "notes": [{
  4353. "name": "W3C Spec",
  4354. "href": "https://www.w3.org/TR/css3-values/#font-relative-lengths"
  4355. }]
  4356. }
  4357. !*/
  4358. Modernizr.addTest('cssexunit', function() {
  4359. var elemStyle = modElem.elem.style;
  4360. var supports;
  4361. try {
  4362. elemStyle.fontSize = '3ex';
  4363. supports = elemStyle.fontSize.indexOf('ex') !== -1;
  4364. } catch (e) {
  4365. supports = false;
  4366. }
  4367. return supports;
  4368. });
  4369. /*!
  4370. {
  4371. "name": "CSS Supports",
  4372. "property": "supports",
  4373. "caniuse": "css-featurequeries",
  4374. "tags": ["css"],
  4375. "builderAliases": ["css_supports"],
  4376. "notes": [{
  4377. "name": "W3C Spec",
  4378. "href": "https://dev.w3.org/csswg/css3-conditional/#at-supports"
  4379. },{
  4380. "name": "Related Github Issue",
  4381. "href": "https://github.com/Modernizr/Modernizr/issues/648"
  4382. },{
  4383. "name": "W3C Spec",
  4384. "href": "https://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
  4385. }]
  4386. }
  4387. !*/
  4388. var newSyntax = 'CSS' in window && 'supports' in window.CSS;
  4389. var oldSyntax = 'supportsCSS' in window;
  4390. Modernizr.addTest('supports', newSyntax || oldSyntax);
  4391. /*!
  4392. {
  4393. "name": "CSS Filters",
  4394. "property": "cssfilters",
  4395. "caniuse": "css-filters",
  4396. "polyfills": ["polyfilter"],
  4397. "tags": ["css"],
  4398. "builderAliases": ["css_filters"],
  4399. "notes": [{
  4400. "name": "MDN Docs",
  4401. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/filter"
  4402. }]
  4403. }
  4404. !*/
  4405. Modernizr.addTest('cssfilters', function() {
  4406. if (Modernizr.supports) {
  4407. return testAllProps('filter', 'blur(2px)');
  4408. } else {
  4409. var el = createElement('a');
  4410. el.style.cssText = prefixes.join('filter:blur(2px); ');
  4411. // https://github.com/Modernizr/Modernizr/issues/615
  4412. // documentMode is needed for false positives in oldIE, please see issue above
  4413. return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9));
  4414. }
  4415. });
  4416. /*!
  4417. {
  4418. "name": "Flexbox",
  4419. "property": "flexbox",
  4420. "caniuse": "flexbox",
  4421. "tags": ["css"],
  4422. "notes": [{
  4423. "name": "The _new_ flexbox",
  4424. "href": "https://www.w3.org/TR/css-flexbox-1/"
  4425. }],
  4426. "warnings": [
  4427. "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
  4428. ]
  4429. }
  4430. !*/
  4431. /* DOC
  4432. Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
  4433. */
  4434. Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
  4435. /*!
  4436. {
  4437. "name": "Flexbox (legacy)",
  4438. "property": "flexboxlegacy",
  4439. "tags": ["css"],
  4440. "polyfills": ["flexie"],
  4441. "notes": [{
  4442. "name": "The _old_ flexbox",
  4443. "href": "https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/"
  4444. }]
  4445. }
  4446. !*/
  4447. Modernizr.addTest('flexboxlegacy', testAllProps('boxDirection', 'reverse', true));
  4448. /*!
  4449. {
  4450. "name": "Flexbox (tweener)",
  4451. "property": "flexboxtweener",
  4452. "tags": ["css"],
  4453. "polyfills": ["flexie"],
  4454. "notes": [{
  4455. "name": "The _inbetween_ flexbox",
  4456. "href": "https://www.w3.org/TR/2011/WD-css3-flexbox-20111129/"
  4457. }],
  4458. "warnings": ["This represents an old syntax, not the latest standard syntax."]
  4459. }
  4460. !*/
  4461. Modernizr.addTest('flexboxtweener', testAllProps('flexAlign', 'end', true));
  4462. /*!
  4463. {
  4464. "name": "Flex Line Wrapping",
  4465. "property": "flexwrap",
  4466. "tags": ["css", "flexbox"],
  4467. "notes": [{
  4468. "name": "W3C Spec",
  4469. "href": "https://www.w3.org/TR/css-flexbox-1/"
  4470. }],
  4471. "warnings": [
  4472. "Does not imply a modern implementation – see documentation."
  4473. ]
  4474. }
  4475. !*/
  4476. /* DOC
  4477. Detects support for the `flex-wrap` CSS property, part of Flexbox, which isn’t present in all Flexbox implementations (notably Firefox).
  4478. This featured in both the 'tweener' syntax (implemented by IE10) and the 'modern' syntax (implemented by others). This detect will return `true` for either of these implementations, as long as the `flex-wrap` property is supported. So to ensure the modern syntax is supported, use together with `Modernizr.flexbox`:
  4479. ```javascript
  4480. if (Modernizr.flexbox && Modernizr.flexwrap) {
  4481. // Modern Flexbox with `flex-wrap` supported
  4482. }
  4483. else {
  4484. // Either old Flexbox syntax, or `flex-wrap` not supported
  4485. }
  4486. ```
  4487. */
  4488. Modernizr.addTest('flexwrap', testAllProps('flexWrap', 'wrap', true));
  4489. /*!
  4490. {
  4491. "name": "CSS :focus-within pseudo-selector",
  4492. "caniuse": "css-focus-visible",
  4493. "property": "focuswithin",
  4494. "tags": ["css"]
  4495. }
  4496. !*/
  4497. Modernizr.addTest('focuswithin', function() {
  4498. try {
  4499. document.querySelector(':focus-within');
  4500. } catch (error) {
  4501. return false;
  4502. }
  4503. return true;
  4504. });
  4505. /*!
  4506. {
  4507. "name": "Font Display",
  4508. "property": "fontdisplay",
  4509. "authors": ["Patrick Kettner"],
  4510. "caniuse": "css-font-rendering-controls",
  4511. "notes": [{
  4512. "name": "W3C Spec",
  4513. "href": "https://drafts.csswg.org/css-fonts-4/#font-display-desc"
  4514. },{
  4515. "name": "`font-display` for the masses",
  4516. "href": "https://css-tricks.com/font-display-masses/"
  4517. }]
  4518. }
  4519. !*/
  4520. /* DOC
  4521. Detects support for the `font-display` descriptor, which defines how font files are loaded and displayed by the browser.
  4522. */
  4523. Modernizr.addTest('fontDisplay', testProp('font-display'));
  4524. /*!
  4525. {
  4526. "name": "@font-face",
  4527. "property": "fontface",
  4528. "authors": ["Diego Perini", "Mat Marquis"],
  4529. "tags": ["css"],
  4530. "knownBugs": [
  4531. "False Positive: WebOS https://github.com/Modernizr/Modernizr/issues/342",
  4532. "False Positive: WP7 https://github.com/Modernizr/Modernizr/issues/538"
  4533. ],
  4534. "notes": [{
  4535. "name": "@font-face detection routine by Diego Perini",
  4536. "href": "http://javascript.nwbox.com/CSSSupport/"
  4537. },{
  4538. "name": "Filament Group @font-face compatibility research",
  4539. "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p"
  4540. },{
  4541. "name": "Filament Grunticon/@font-face device testing results",
  4542. "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0"
  4543. },{
  4544. "name": "CSS fonts on Android",
  4545. "href": "https://stackoverflow.com/questions/3200069/css-fonts-on-android"
  4546. },{
  4547. "name": "@font-face and Android",
  4548. "href": "http://archivist.incutio.com/viewlist/css-discuss/115960"
  4549. }]
  4550. }
  4551. !*/
  4552. var blacklist = (function() {
  4553. var ua = navigator.userAgent;
  4554. var webos = ua.match(/w(eb)?osbrowser/gi);
  4555. var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9;
  4556. return webos || wppre8;
  4557. }());
  4558. if (blacklist) {
  4559. Modernizr.addTest('fontface', false);
  4560. } else {
  4561. testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) {
  4562. var style = document.getElementById('smodernizr');
  4563. var sheet = style.sheet || style.styleSheet;
  4564. var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
  4565. var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
  4566. Modernizr.addTest('fontface', bool);
  4567. });
  4568. }
  4569. ;
  4570. /*!
  4571. {
  4572. "name": "CSS Generated Content",
  4573. "property": "generatedcontent",
  4574. "tags": ["css"],
  4575. "warnings": ["Android won't return correct height for anything below 7px #738"],
  4576. "notes": [{
  4577. "name": "W3C Spec",
  4578. "href": "https://www.w3.org/TR/css3-selectors/#gen-content"
  4579. },{
  4580. "name": "MDN Docs on :before",
  4581. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before"
  4582. },{
  4583. "name": "MDN Docs on :after",
  4584. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::after"
  4585. }]
  4586. }
  4587. !*/
  4588. testStyles('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}', function(node) {
  4589. // See bug report on why this value is 6 crbug.com/608142
  4590. Modernizr.addTest('generatedcontent', node.offsetHeight >= 6);
  4591. });
  4592. /*!
  4593. {
  4594. "name": "CSS Gradients",
  4595. "caniuse": "css-gradients",
  4596. "property": "cssgradients",
  4597. "tags": ["css"],
  4598. "knownBugs": ["False-positives on webOS (https://github.com/Modernizr/Modernizr/issues/202)"],
  4599. "notes": [{
  4600. "name": "Webkit Gradient Syntax",
  4601. "href": "https://webkit.org/blog/175/introducing-css-gradients/"
  4602. },{
  4603. "name": "Linear Gradient Syntax",
  4604. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient"
  4605. },{
  4606. "name": "W3C Spec",
  4607. "href": "https://drafts.csswg.org/css-images-3/#gradients"
  4608. }]
  4609. }
  4610. !*/
  4611. Modernizr.addTest('cssgradients', function() {
  4612. var str1 = 'background-image:';
  4613. var str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));';
  4614. var css = '';
  4615. var angle;
  4616. for (var i = 0, len = prefixes.length - 1; i < len; i++) {
  4617. angle = (i === 0 ? 'to ' : '');
  4618. css += str1 + prefixes[i] + 'linear-gradient(' + angle + 'left top, #9f9, white);';
  4619. }
  4620. if (Modernizr._config.usePrefixes) {
  4621. // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
  4622. css += str1 + '-webkit-' + str2;
  4623. }
  4624. var elem = createElement('a');
  4625. var style = elem.style;
  4626. style.cssText = css;
  4627. // IE6 returns undefined so cast to string
  4628. return ('' + style.backgroundImage).indexOf('gradient') > -1;
  4629. });
  4630. /*! {
  4631. "name": "CSS Hairline",
  4632. "property": "hairline",
  4633. "tags": ["css"],
  4634. "authors": ["strarsis"],
  4635. "notes": [{
  4636. "name": "Blog post about CSS retina hairlines",
  4637. "href": "http://dieulot.net/css-retina-hairline"
  4638. },{
  4639. "name": "Derived from",
  4640. "href": "https://gist.github.com/dieulot/520a49463f6058fbc8d1"
  4641. }]
  4642. }
  4643. !*/
  4644. /* DOC
  4645. Detects support for hidpi/retina hairlines, which are CSS borders with less than 1px in width, for being physically 1px on hidpi screens.
  4646. */
  4647. Modernizr.addTest('hairline', function() {
  4648. return testStyles('#modernizr {border:.5px solid transparent}', function(elem) {
  4649. return elem.offsetHeight === 1;
  4650. });
  4651. });
  4652. /*!
  4653. {
  4654. "name": "CSS HSLA Colors",
  4655. "caniuse": "css3-colors",
  4656. "property": "hsla",
  4657. "tags": ["css"]
  4658. }
  4659. !*/
  4660. Modernizr.addTest('hsla', function() {
  4661. var style = createElement('a').style;
  4662. style.cssText = 'background-color:hsla(120,40%,100%,.5)';
  4663. return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
  4664. });
  4665. /*!
  4666. {
  4667. "name": "CSS Hyphens",
  4668. "caniuse": "css-hyphens",
  4669. "property": ["csshyphens", "softhyphens", "softhyphensfind"],
  4670. "tags": ["css"],
  4671. "builderAliases": ["css_hyphens"],
  4672. "async": true,
  4673. "authors": ["David Newton"],
  4674. "warnings": [
  4675. "These tests currently require document.body to be present",
  4676. "If loading Hyphenator.js via yepnope, be cautious of issue 158: https://github.com/mnater/hyphenator/issues/158",
  4677. "This is very large – only include it if you absolutely need it"
  4678. ],
  4679. "notes": [{
  4680. "name": "The Current State of Hyphenation on the Web.",
  4681. "href": "https://davidnewton.ca/the-current-state-of-hyphenation-on-the-web"
  4682. },{
  4683. "name": "Hyphenation Test Page",
  4684. "href": "https://web.archive.org/web/20150319125549/http://davidnewton.ca/demos/hyphenation/test.html"
  4685. },{
  4686. "name": "Hyphenation is Language Specific",
  4687. "href": "https://code.google.com/p/hyphenator/source/diff?spec=svn975&r=975&format=side&path=/trunk/Hyphenator.js#sc_svn975_313"
  4688. },{
  4689. "name": "Related Modernizr Issue",
  4690. "href": "https://github.com/Modernizr/Modernizr/issues/312"
  4691. }]
  4692. }
  4693. !*/
  4694. Modernizr.addAsyncTest(function() {
  4695. var waitTime = 300;
  4696. setTimeout(runHyphenTest, waitTime);
  4697. // Wait 1000ms so we can hope for document.body
  4698. function runHyphenTest() {
  4699. if (!document.body && !document.getElementsByTagName('body')[0]) {
  4700. setTimeout(runHyphenTest, waitTime);
  4701. return;
  4702. }
  4703. // functional test of adding hyphens:auto
  4704. function test_hyphens_css() {
  4705. try {
  4706. /* create a div container and a span within that
  4707. * these have to be appended to document.body, otherwise some browsers can give false negative */
  4708. var div = createElement('div');
  4709. var span = createElement('span');
  4710. var divStyle = div.style;
  4711. var spanHeight = 0;
  4712. var spanWidth = 0;
  4713. var result = false;
  4714. var firstChild = document.body.firstElementChild || document.body.firstChild;
  4715. /* Hyphenation is only applied when language is explicitly set and when respective dictionary
  4716. * is available. See https://developer.mozilla.org/en-US/docs/Web/CSS/hyphens for details. */
  4717. div.lang = 'en';
  4718. div.appendChild(span);
  4719. span.innerHTML = 'Bacon ipsum dolor sit amet jerky velit in culpa hamburger et. Laborum dolor proident, enim dolore duis commodo et strip steak. Salami anim et, veniam consectetur dolore qui tenderloin jowl velit sirloin. Et ad culpa, fatback cillum jowl ball tip ham hock nulla short ribs pariatur aute. Pig pancetta ham bresaola, ut boudin nostrud commodo flank esse cow tongue culpa. Pork belly bresaola enim pig, ea consectetur nisi. Fugiat officia turkey, ea cow jowl pariatur ullamco proident do laborum velit sausage. Magna biltong sint tri-tip commodo sed bacon, esse proident aliquip. Ullamco ham sint fugiat, velit in enim sed mollit nulla cow ut adipisicing nostrud consectetur. Proident dolore beef ribs, laborum nostrud meatball ea laboris rump cupidatat labore culpa. Shankle minim beef, velit sint cupidatat fugiat tenderloin pig et ball tip. Ut cow fatback salami, bacon ball tip et in shank strip steak bresaola. In ut pork belly sed mollit tri-tip magna culpa veniam, short ribs qui in andouille ham consequat. Dolore bacon t-bone, velit short ribs enim strip steak nulla. Voluptate labore ut, biltong swine irure jerky. Cupidatat excepteur aliquip salami dolore. Ball tip strip steak in pork dolor. Ad in esse biltong. Dolore tenderloin exercitation ad pork loin t-bone, dolore in chicken ball tip qui pig. Ut culpa tongue, sint ribeye dolore ex shank voluptate hamburger. Jowl et tempor, boudin pork chop labore ham hock drumstick consectetur tri-tip elit swine meatball chicken ground round. Proident shankle mollit dolore. Shoulder ut duis t-bone quis reprehenderit. Meatloaf dolore minim strip steak, laboris ea aute bacon beef ribs elit shank in veniam drumstick qui. Ex laboris meatball cow tongue pork belly. Ea ball tip reprehenderit pig, sed fatback boudin dolore flank aliquip laboris eu quis. Beef ribs duis beef, cow corned beef adipisicing commodo nisi deserunt exercitation. Cillum dolor t-bone spare ribs, ham hock est sirloin. Brisket irure meatloaf in, boudin pork belly sirloin ball tip. Sirloin sint irure nisi nostrud aliqua. Nostrud nulla aute, enim officia culpa ham hock. Aliqua reprehenderit dolore sunt nostrud sausage, ea boudin pork loin ut t-bone ham tempor. Tri-tip et pancetta drumstick laborum. Ham hock magna do nostrud in proident. Ex ground round fatback, venison non ribeye in.';
  4720. document.body.insertBefore(div, firstChild);
  4721. /* get size of unhyphenated text */
  4722. divStyle.cssText = 'position:absolute;top:0;left:0;width:5em;text-align:justify;text-justify:newspaper;';
  4723. spanHeight = span.offsetHeight;
  4724. spanWidth = span.offsetWidth;
  4725. /* compare size with hyphenated text */
  4726. divStyle.cssText = 'position:absolute;top:0;left:0;width:5em;text-align:justify;text-justify:newspaper;' +
  4727. prefixes.join('hyphens:auto; ');
  4728. /* results */
  4729. result = (span.offsetHeight !== spanHeight || span.offsetWidth !== spanWidth);
  4730. /* cleanup */
  4731. document.body.removeChild(div);
  4732. div.removeChild(span);
  4733. return result;
  4734. } catch (e) {
  4735. return false;
  4736. }
  4737. }
  4738. // for the softhyphens test
  4739. function test_hyphens(delimiter, testWidth) {
  4740. try {
  4741. /* create a div container and a span within that
  4742. * these have to be appended to document.body, otherwise some browsers can give false negative */
  4743. var div = createElement('div');
  4744. var span = createElement('span');
  4745. var divStyle = div.style;
  4746. var spanSize = 0;
  4747. var result = false;
  4748. var result1 = false;
  4749. var result2 = false;
  4750. var firstChild = document.body.firstElementChild || document.body.firstChild;
  4751. divStyle.cssText = 'position:absolute;top:0;left:0;overflow:visible;width:1.25em;';
  4752. div.appendChild(span);
  4753. document.body.insertBefore(div, firstChild);
  4754. /* get height of unwrapped text */
  4755. span.innerHTML = 'mm';
  4756. spanSize = span.offsetHeight;
  4757. /* compare height w/ delimiter, to see if it wraps to new line */
  4758. span.innerHTML = 'm' + delimiter + 'm';
  4759. result1 = (span.offsetHeight > spanSize);
  4760. /* if we're testing the width too (i.e. for soft-hyphen, not zws),
  4761. * this is because tested Blackberry devices will wrap the text but not display the hyphen */
  4762. if (testWidth) {
  4763. /* get width of wrapped, non-hyphenated text */
  4764. span.innerHTML = 'm<br />m';
  4765. spanSize = span.offsetWidth;
  4766. /* compare width w/ wrapped w/ delimiter to see if hyphen is present */
  4767. span.innerHTML = 'm' + delimiter + 'm';
  4768. result2 = (span.offsetWidth > spanSize);
  4769. } else {
  4770. result2 = true;
  4771. }
  4772. /* results and cleanup */
  4773. if (result1 === true && result2 === true) { result = true; }
  4774. document.body.removeChild(div);
  4775. div.removeChild(span);
  4776. return result;
  4777. } catch (e) {
  4778. return false;
  4779. }
  4780. }
  4781. // testing if in-browser Find functionality will work on hyphenated text
  4782. function test_hyphens_find(delimiter) {
  4783. try {
  4784. /* create a dummy input for resetting selection location, and a div container
  4785. * these have to be appended to document.body, otherwise some browsers can give false negative
  4786. * div container gets the doubled testword, separated by the delimiter
  4787. * Note: giving a width to div gives false positive in iOS Safari */
  4788. var dummy = createElement('input');
  4789. var div = createElement('div');
  4790. var testword = 'lebowski';
  4791. var result = false;
  4792. var textrange;
  4793. var firstChild = document.body.firstElementChild || document.body.firstChild;
  4794. div.innerHTML = testword + delimiter + testword;
  4795. document.body.insertBefore(div, firstChild);
  4796. document.body.insertBefore(dummy, div);
  4797. /* reset the selection to the dummy input element, i.e. BEFORE the div container
  4798. * stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area */
  4799. if (dummy.setSelectionRange) {
  4800. dummy.focus();
  4801. dummy.setSelectionRange(0, 0);
  4802. } else if (dummy.createTextRange) {
  4803. textrange = dummy.createTextRange();
  4804. textrange.collapse(true);
  4805. textrange.moveEnd('character', 0);
  4806. textrange.moveStart('character', 0);
  4807. textrange.select();
  4808. }
  4809. /* try to find the doubled testword, without the delimiter */
  4810. try {
  4811. if (window.find) {
  4812. result = window.find(testword + testword);
  4813. } else {
  4814. textrange = window.self.document.body.createTextRange();
  4815. result = textrange.findText(testword + testword);
  4816. }
  4817. } catch (e) {
  4818. result = false;
  4819. }
  4820. document.body.removeChild(div);
  4821. document.body.removeChild(dummy);
  4822. return result;
  4823. } catch (e) {
  4824. return false;
  4825. }
  4826. }
  4827. addTest('csshyphens', function() {
  4828. if (!testAllProps('hyphens', 'auto', true)) {
  4829. return false;
  4830. }
  4831. /* Chrome lies about its hyphens support so we need a more robust test
  4832. crbug.com/107111
  4833. */
  4834. try {
  4835. return test_hyphens_css();
  4836. } catch (e) {
  4837. return false;
  4838. }
  4839. });
  4840. addTest('softhyphens', function() {
  4841. try {
  4842. // use numeric entity instead of &shy; in case it's XHTML
  4843. return test_hyphens('&#173;', true) && test_hyphens('&#8203;', false);
  4844. } catch (e) {
  4845. return false;
  4846. }
  4847. });
  4848. addTest('softhyphensfind', function() {
  4849. try {
  4850. return test_hyphens_find('&#173;') && test_hyphens_find('&#8203;');
  4851. } catch (e) {
  4852. return false;
  4853. }
  4854. });
  4855. }
  4856. });
  4857. /*!
  4858. {
  4859. "name": "CSS :invalid pseudo-class",
  4860. "property": "cssinvalid",
  4861. "notes": [{
  4862. "name": "MDN Docs",
  4863. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid"
  4864. }]
  4865. }
  4866. !*/
  4867. /* DOC
  4868. Detects support for the ':invalid' CSS pseudo-class.
  4869. */
  4870. Modernizr.addTest('cssinvalid', function() {
  4871. return testStyles('#modernizr input{height:0;border:0;padding:0;margin:0;width:10px} #modernizr input:invalid{width:50px}', function(elem) {
  4872. var input = createElement('input');
  4873. input.required = true;
  4874. elem.appendChild(input);
  4875. return input.clientWidth > 10;
  4876. });
  4877. });
  4878. /*!
  4879. {
  4880. "name": "CSS :last-child pseudo-selector",
  4881. "caniuse": "css-sel3",
  4882. "property": "lastchild",
  4883. "tags": ["css"],
  4884. "builderAliases": ["css_lastchild"],
  4885. "notes": [{
  4886. "name": "Related Github Issue",
  4887. "href": "https://github.com/Modernizr/Modernizr/pull/304"
  4888. }]
  4889. }
  4890. !*/
  4891. testStyles('#modernizr div {width:100px} #modernizr :last-child{width:200px;display:block}', function(elem) {
  4892. Modernizr.addTest('lastchild', elem.lastChild.offsetWidth > elem.firstChild.offsetWidth);
  4893. }, 2);
  4894. /*!
  4895. {
  4896. "name": "CSS Mask",
  4897. "caniuse": "css-masks",
  4898. "property": "cssmask",
  4899. "tags": ["css"],
  4900. "builderAliases": ["css_mask"],
  4901. "notes": [{
  4902. "name": "Webkit blog on CSS Masks",
  4903. "href": "https://webkit.org/blog/181/css-masks/"
  4904. },{
  4905. "name": "Safari Docs",
  4906. "href": "https://developer.apple.com/library/archive/documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Masks/Masks.html"
  4907. },{
  4908. "name": "CSS SVG mask",
  4909. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/mask"
  4910. },{
  4911. "name": "Combine with clippaths for awesomeness",
  4912. "href": "https://web.archive.org/web/20150508193041/http://generic.cx:80/for/webkit/test.html"
  4913. }]
  4914. }
  4915. !*/
  4916. Modernizr.addTest('cssmask', testAllProps('maskRepeat', 'repeat-x', true));
  4917. /*!
  4918. {
  4919. "name": "CSS Media Queries",
  4920. "caniuse": "css-mediaqueries",
  4921. "property": "mediaqueries",
  4922. "tags": ["css"],
  4923. "builderAliases": ["css_mediaqueries"]
  4924. }
  4925. !*/
  4926. Modernizr.addTest('mediaqueries', mq('only all'));
  4927. /*!
  4928. {
  4929. "name": "CSS Multiple Backgrounds",
  4930. "caniuse": "multibackgrounds",
  4931. "property": "multiplebgs",
  4932. "tags": ["css"]
  4933. }
  4934. !*/
  4935. // Setting multiple images AND a color on the background shorthand property
  4936. // and then querying the style.background property value for the number of
  4937. // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
  4938. Modernizr.addTest('multiplebgs', function() {
  4939. var style = createElement('a').style;
  4940. style.cssText = 'background:url(https://),url(https://),red url(https://)';
  4941. // If the UA supports multiple backgrounds, there should be three occurrences
  4942. // of the string "url(" in the return value for elemStyle.background
  4943. return (/(url\s*\(.*?){3}/).test(style.background);
  4944. });
  4945. /*!
  4946. {
  4947. "name": "CSS :nth-child pseudo-selector",
  4948. "caniuse": "css-sel3",
  4949. "property": "nthchild",
  4950. "tags": ["css"],
  4951. "notes": [{
  4952. "name": "Related Github Issue",
  4953. "href": "https://github.com/Modernizr/Modernizr/pull/685"
  4954. },{
  4955. "name": "Sitepoint :nth-child documentation",
  4956. "href": "https://www.sitepoint.com/atoz-css-screencast-nth-child/"
  4957. }],
  4958. "authors": ["@emilchristensen"],
  4959. "warnings": ["Known false negative in Safari 3.1 and Safari 3.2.2"]
  4960. }
  4961. !*/
  4962. /* DOC
  4963. Detects support for the ':nth-child()' CSS pseudo-selector.
  4964. */
  4965. // 5 `<div>` elements with `1px` width are created.
  4966. // Then every other element has its `width` set to `2px`.
  4967. // A JavaScript loop then tests if the `<div>`s have the expected width
  4968. // using the modulus operator.
  4969. testStyles('#modernizr div {width:1px} #modernizr div:nth-child(2n) {width:2px;}', function(elem) {
  4970. var elems = elem.getElementsByTagName('div');
  4971. var correctWidths = true;
  4972. for (var i = 0; i < 5; i++) {
  4973. correctWidths = correctWidths && elems[i].offsetWidth === i % 2 + 1;
  4974. }
  4975. Modernizr.addTest('nthchild', correctWidths);
  4976. }, 5);
  4977. /*!
  4978. {
  4979. "name": "CSS Object Fit",
  4980. "caniuse": "object-fit",
  4981. "property": "objectfit",
  4982. "tags": ["css"],
  4983. "builderAliases": ["css_objectfit"],
  4984. "notes": [{
  4985. "name": "Opera Article on Object Fit",
  4986. "href": "https://dev.opera.com/articles/css3-object-fit-object-position/"
  4987. }]
  4988. }
  4989. !*/
  4990. Modernizr.addTest('objectfit', !!prefixed('objectFit'), {aliases: ['object-fit']});
  4991. /*!
  4992. {
  4993. "name": "CSS Opacity",
  4994. "caniuse": "css-opacity",
  4995. "property": "opacity",
  4996. "tags": ["css"]
  4997. }
  4998. !*/
  4999. // Browsers that actually have CSS Opacity implemented have done so
  5000. // according to spec, which means their return values are within the
  5001. // range of [0.0,1.0] - including the leading zero.
  5002. Modernizr.addTest('opacity', function() {
  5003. var style = createElement('a').style;
  5004. style.cssText = prefixes.join('opacity:.55;');
  5005. // The non-literal . in this regex is intentional:
  5006. // German Chrome returns this value as 0,55
  5007. // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
  5008. return (/^0.55$/).test(style.opacity);
  5009. });
  5010. /*!
  5011. {
  5012. "name": "CSS Overflow Scrolling",
  5013. "property": "overflowscrolling",
  5014. "tags": ["css"],
  5015. "builderAliases": ["css_overflow_scrolling"],
  5016. "warnings": ["Introduced in iOS5b2. API is subject to change."],
  5017. "notes": [{
  5018. "name": "Article on iOS overflow scrolling",
  5019. "href": "https://css-tricks.com/snippets/css/momentum-scrolling-on-ios-overflow-elements/"
  5020. }]
  5021. }
  5022. !*/
  5023. Modernizr.addTest('overflowscrolling', testAllProps('overflowScrolling', 'touch', true));
  5024. /*!
  5025. {
  5026. "name": "CSS Pointer Events",
  5027. "caniuse": "pointer-events",
  5028. "property": "csspointerevents",
  5029. "authors": ["ausi"],
  5030. "tags": ["css"],
  5031. "builderAliases": ["css_pointerevents"],
  5032. "notes": [{
  5033. "name": "MDN Docs",
  5034. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events"
  5035. },{
  5036. "name": "Test Project Page",
  5037. "href": "https://ausi.github.com/Feature-detection-technique-for-pointer-events/"
  5038. },{
  5039. "name": "Test Project Wiki",
  5040. "href": "https://github.com/ausi/Feature-detection-technique-for-pointer-events/wiki"
  5041. },{
  5042. "name": "Related Github Issue",
  5043. "href": "https://github.com/Modernizr/Modernizr/issues/80"
  5044. }]
  5045. }
  5046. !*/
  5047. Modernizr.addTest('csspointerevents', function() {
  5048. var style = createElement('a').style;
  5049. style.cssText = 'pointer-events:auto';
  5050. return style.pointerEvents === 'auto';
  5051. });
  5052. /*!
  5053. {
  5054. "name": "CSS position: sticky",
  5055. "property": "csspositionsticky",
  5056. "tags": ["css"],
  5057. "builderAliases": ["css_positionsticky"],
  5058. "notes": [{
  5059. "name": "Chrome bug report",
  5060. "href":"https://bugs.chromium.org/p/chromium/issues/detail?id=322972"
  5061. }],
  5062. "warnings": ["using position:sticky on anything but top aligned elements is buggy in Chrome < 37 and iOS <=7+"]
  5063. }
  5064. !*/
  5065. // Sticky positioning - constrains an element to be positioned inside the
  5066. // intersection of its container box, and the viewport.
  5067. Modernizr.addTest('csspositionsticky', function() {
  5068. var prop = 'position:';
  5069. var value = 'sticky';
  5070. var el = createElement('a');
  5071. var mStyle = el.style;
  5072. mStyle.cssText = prop + prefixes.join(value + ';' + prop).slice(0, -prop.length);
  5073. return mStyle.position.indexOf(value) !== -1;
  5074. });
  5075. /*!
  5076. {
  5077. "name": "CSS Generated Content Animations",
  5078. "property": "csspseudoanimations",
  5079. "tags": ["css"]
  5080. }
  5081. !*/
  5082. Modernizr.addTest('csspseudoanimations', function() {
  5083. var result = false;
  5084. if (!Modernizr.cssanimations || !window.getComputedStyle) {
  5085. return result;
  5086. }
  5087. var styles = [
  5088. '@', prefixes.join('keyframes csspseudoanimations { from { font-size: 10px; } }@').replace(/\@$/, ''),
  5089. '#modernizr:before { content:" "; font-size:5px;',
  5090. prefixes.join('animation:csspseudoanimations 1ms infinite;'),
  5091. '}'
  5092. ].join('');
  5093. testStyles(styles, function(elem) {
  5094. result = window.getComputedStyle(elem, ':before').getPropertyValue('font-size') === '10px';
  5095. });
  5096. return result;
  5097. });
  5098. /*!
  5099. {
  5100. "name": "CSS Transitions",
  5101. "property": "csstransitions",
  5102. "caniuse": "css-transitions",
  5103. "tags": ["css"]
  5104. }
  5105. !*/
  5106. Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
  5107. /*!
  5108. {
  5109. "name": "CSS Generated Content Transitions",
  5110. "property": "csspseudotransitions",
  5111. "tags": ["css"]
  5112. }
  5113. !*/
  5114. Modernizr.addTest('csspseudotransitions', function() {
  5115. var result = false;
  5116. if (!Modernizr.csstransitions || !window.getComputedStyle) {
  5117. return result;
  5118. }
  5119. var styles =
  5120. '#modernizr:before { content:" "; font-size:5px;' + prefixes.join('transition:0s 100s;') + '}' +
  5121. '#modernizr.trigger:before { font-size:10px; }';
  5122. testStyles(styles, function(elem) {
  5123. // Force rendering of the element's styles so that the transition will trigger
  5124. window.getComputedStyle(elem, ':before').getPropertyValue('font-size');
  5125. elem.className += 'trigger';
  5126. result = window.getComputedStyle(elem, ':before').getPropertyValue('font-size') === '5px';
  5127. });
  5128. return result;
  5129. });
  5130. /*!
  5131. {
  5132. "name": "CSS Reflections",
  5133. "caniuse": "css-reflections",
  5134. "property": "cssreflections",
  5135. "tags": ["css"]
  5136. }
  5137. !*/
  5138. Modernizr.addTest('cssreflections', testAllProps('boxReflect', 'above', true));
  5139. /*!
  5140. {
  5141. "name": "CSS Regions",
  5142. "caniuse": "css-regions",
  5143. "authors": ["Mihai Balan"],
  5144. "property": "regions",
  5145. "tags": ["css"],
  5146. "builderAliases": ["css_regions"],
  5147. "notes": [{
  5148. "name": "W3C Spec",
  5149. "href": "https://www.w3.org/TR/css3-regions/"
  5150. }]
  5151. }
  5152. !*/
  5153. // We start with a CSS parser test then we check page geometry to see if it's affected by regions
  5154. // Later we might be able to retire the second part, as WebKit builds with the false positives die out
  5155. Modernizr.addTest('regions', function() {
  5156. if (isSVG) {
  5157. // css regions don't work inside of SVG elements. Rather than update the
  5158. // below test to work in an SVG context, just exit early to save bytes
  5159. return false;
  5160. }
  5161. /* Get the 'flowFrom' property name available in the browser. Either default or vendor prefixed.
  5162. If the property name can't be found we'll get Boolean 'false' and fail quickly */
  5163. var flowFromProperty = prefixed('flowFrom');
  5164. var flowIntoProperty = prefixed('flowInto');
  5165. var result = false;
  5166. if (!flowFromProperty || !flowIntoProperty) {
  5167. return result;
  5168. }
  5169. /* If CSS parsing is there, try to determine if regions actually work. */
  5170. var iframeContainer = createElement('iframe');
  5171. var container = createElement('div');
  5172. var content = createElement('div');
  5173. var region = createElement('div');
  5174. /* we create a random, unlikely to be generated flow number to make sure we don't
  5175. clash with anything more vanilla, like 'flow', or 'article', or 'f1' */
  5176. var flowName = 'modernizr_flow_for_regions_check';
  5177. /* First create a div with two adjacent divs inside it. The first will be the
  5178. content, the second will be the region. To be able to distinguish between the two,
  5179. we'll give the region a particular padding */
  5180. content.innerText = 'M';
  5181. container.style.cssText = 'top: 150px; left: 150px; padding: 0px;';
  5182. region.style.cssText = 'width: 50px; height: 50px; padding: 42px;';
  5183. region.style[flowFromProperty] = flowName;
  5184. container.appendChild(content);
  5185. container.appendChild(region);
  5186. docElement.appendChild(container);
  5187. /* Now compute the bounding client rect, before and after attempting to flow the
  5188. content div in the region div. If regions are enabled, the after bounding rect
  5189. should reflect the padding of the region div.*/
  5190. var flowedRect, delta;
  5191. var plainRect = content.getBoundingClientRect();
  5192. content.style[flowIntoProperty] = flowName;
  5193. flowedRect = content.getBoundingClientRect();
  5194. delta = parseInt(flowedRect.left - plainRect.left, 10);
  5195. docElement.removeChild(container);
  5196. if (delta === 42) {
  5197. result = true;
  5198. } else {
  5199. /* IE only allows for the content to come from iframes. This has the
  5200. * side effect of automatic collapsing of iframes once they get the flow-into
  5201. * property set. checking for a change on the height allows us to detect this
  5202. * in a sync way, without having to wait for a frame to load */
  5203. docElement.appendChild(iframeContainer);
  5204. plainRect = iframeContainer.getBoundingClientRect();
  5205. iframeContainer.style[flowIntoProperty] = flowName;
  5206. flowedRect = iframeContainer.getBoundingClientRect();
  5207. if (plainRect.height > 0 && plainRect.height !== flowedRect.height && flowedRect.height === 0) {
  5208. result = true;
  5209. }
  5210. }
  5211. content = region = container = iframeContainer = undefined;
  5212. return result;
  5213. });
  5214. /*!
  5215. {
  5216. "name": "CSS Font rem Units",
  5217. "caniuse": "rem",
  5218. "authors": ["nsfmc"],
  5219. "property": "cssremunit",
  5220. "tags": ["css"],
  5221. "builderAliases": ["css_remunit"],
  5222. "notes": [{
  5223. "name": "W3C Spec",
  5224. "href": "https://www.w3.org/TR/css3-values/#relative0"
  5225. },{
  5226. "name": "Font Size with rem by Jonathan Snook",
  5227. "href": "https://snook.ca/archives/html_and_css/font-size-with-rem"
  5228. }]
  5229. }
  5230. !*/
  5231. // "The 'rem' unit ('root em') is relative to the computed
  5232. // value of the 'font-size' value of the root element."
  5233. // you can test by checking if the prop was ditched
  5234. Modernizr.addTest('cssremunit', function() {
  5235. var style = createElement('a').style;
  5236. try {
  5237. style.fontSize = '3rem';
  5238. }
  5239. catch (e) {}
  5240. return (/rem/).test(style.fontSize);
  5241. });
  5242. /*!
  5243. {
  5244. "name": "CSS UI Resize",
  5245. "property": "cssresize",
  5246. "caniuse": "css-resize",
  5247. "tags": ["css"],
  5248. "builderAliases": ["css_resize"],
  5249. "notes": [{
  5250. "name": "W3C Spec",
  5251. "href": "https://www.w3.org/TR/css3-ui/#resize"
  5252. },{
  5253. "name": "MDN Docs",
  5254. "href": "https://developer.mozilla.org/en/CSS/resize"
  5255. }]
  5256. }
  5257. !*/
  5258. /* DOC
  5259. Test for CSS 3 UI "resize" property
  5260. */
  5261. Modernizr.addTest('cssresize', testAllProps('resize', 'both', true));
  5262. /*!
  5263. {
  5264. "name": "CSS rgba",
  5265. "caniuse": "css3-colors",
  5266. "property": "rgba",
  5267. "tags": ["css"],
  5268. "notes": [{
  5269. "name": "CSSTricks Tutorial",
  5270. "href": "https://css-tricks.com/rgba-browser-support/"
  5271. }]
  5272. }
  5273. !*/
  5274. Modernizr.addTest('rgba', function() {
  5275. var style = createElement('a').style;
  5276. style.cssText = 'background-color:rgba(150,255,150,.5)';
  5277. return ('' + style.backgroundColor).indexOf('rgba') > -1;
  5278. });
  5279. /*!
  5280. {
  5281. "name": "CSS Stylable Scrollbars",
  5282. "property": "cssscrollbar",
  5283. "tags": ["css"],
  5284. "builderAliases": ["css_scrollbars"]
  5285. }
  5286. !*/
  5287. testStyles('#modernizr{overflow: scroll; width: 40px; height: 40px; }#' + prefixes
  5288. .join('scrollbar{width:10px}' + ' #modernizr::')
  5289. .split('#')
  5290. .slice(1)
  5291. .join('#') + 'scrollbar{width:10px}',
  5292. function(node) {
  5293. Modernizr.addTest('cssscrollbar', 'scrollWidth' in node && node.scrollWidth === 30);
  5294. });
  5295. /*!
  5296. {
  5297. "name": "Scroll Snap Points",
  5298. "property": "scrollsnappoints",
  5299. "notes": [{
  5300. "name": "Setting native-like scrolling offsets in CSS with Scrolling Snap Points",
  5301. "href": "http://generatedcontent.org/post/66817675443/setting-native-like-scrolling-offsets-in-css-with"
  5302. },{
  5303. "name": "MDN Docs",
  5304. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points"
  5305. }],
  5306. "polyfills": ["scrollsnap"]
  5307. }
  5308. !*/
  5309. /* DOC
  5310. Detects support for CSS Snap Points
  5311. */
  5312. Modernizr.addTest('scrollsnappoints', testAllProps('scrollSnapType'));
  5313. /*!
  5314. {
  5315. "name": "CSS Shapes",
  5316. "property": "shapes",
  5317. "tags": ["css"],
  5318. "notes": [{
  5319. "name": "W3C Spec",
  5320. "href": "https://www.w3.org/TR/css-shapes"
  5321. },{
  5322. "name": "Examples from Adobe",
  5323. "href": "https://web.archive.org/web/20171230010236/http://webplatform.adobe.com:80/shapes"
  5324. }, {
  5325. "name": "Examples from CSS-Tricks",
  5326. "href": "https://css-tricks.com/examples/ShapesOfCSS/"
  5327. }]
  5328. }
  5329. !*/
  5330. Modernizr.addTest('shapes', testAllProps('shapeOutside', 'content-box', true));
  5331. /*!
  5332. {
  5333. "name": "CSS general sibling selector",
  5334. "caniuse": "css-sel3",
  5335. "property": "siblinggeneral",
  5336. "tags": ["css"],
  5337. "notes": [{
  5338. "name": "Related Github Issue",
  5339. "href": "https://github.com/Modernizr/Modernizr/pull/889"
  5340. }]
  5341. }
  5342. !*/
  5343. Modernizr.addTest('siblinggeneral', function() {
  5344. return testStyles('#modernizr div {width:100px} #modernizr div ~ div {width:200px;display:block}', function(elem) {
  5345. return elem.lastChild.offsetWidth === 200;
  5346. }, 2);
  5347. });
  5348. /*!
  5349. {
  5350. "name": "CSS Subpixel Fonts",
  5351. "property": "subpixelfont",
  5352. "tags": ["css"],
  5353. "builderAliases": ["css_subpixelfont"],
  5354. "authors": ["@derSchepp", "@gerritvanaaken", "@rodneyrehm", "@yatil", "@ryanseddon"],
  5355. "notes": [{
  5356. "name": "Origin Test",
  5357. "href": "https://github.com/gerritvanaaken/subpixeldetect"
  5358. }]
  5359. }
  5360. !*/
  5361. /*
  5362. * (to infer if GDI or DirectWrite is used on Windows)
  5363. */
  5364. testStyles(
  5365. '#modernizr{position: absolute; top: -10em; visibility:hidden; font: normal 10px arial;}#subpixel{float: left; font-size: 33.3333%;}',
  5366. function(elem) {
  5367. var subpixel = elem.firstChild;
  5368. subpixel.innerHTML = 'This is a text written in Arial';
  5369. Modernizr.addTest('subpixelfont', window.getComputedStyle ?
  5370. window.getComputedStyle(subpixel, null).getPropertyValue('width') !== '44px'
  5371. : false);
  5372. }, 1, ['subpixel']);
  5373. /*!
  5374. {
  5375. "name": "CSS :target pseudo-class",
  5376. "caniuse": "css-sel3",
  5377. "property": "target",
  5378. "tags": ["css"],
  5379. "notes": [{
  5380. "name": "MDN Docs",
  5381. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:target"
  5382. }],
  5383. "authors": ["@zachleat"],
  5384. "warnings": ["Opera Mini supports :target but doesn't update the hash for anchor links."]
  5385. }
  5386. !*/
  5387. /* DOC
  5388. Detects support for the ':target' CSS pseudo-class.
  5389. */
  5390. // querySelector
  5391. Modernizr.addTest('target', function() {
  5392. var doc = window.document;
  5393. if (!('querySelectorAll' in doc)) {
  5394. return false;
  5395. }
  5396. try {
  5397. doc.querySelectorAll(':target');
  5398. return true;
  5399. } catch (e) {
  5400. return false;
  5401. }
  5402. });
  5403. /*!
  5404. {
  5405. "name": "CSS text-align-last",
  5406. "property": "textalignlast",
  5407. "tags": ["css"],
  5408. "knownBugs": ["IE does not support the 'start' or 'end' values."],
  5409. "notes": [{
  5410. "name": "Quirksmode",
  5411. "href": "https://www.quirksmode.org/css/text/textalignlast.html"
  5412. },{
  5413. "name": "MDN Docs",
  5414. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/text-align-last"
  5415. }]
  5416. }
  5417. !*/
  5418. Modernizr.addTest('textalignlast', testAllProps('textAlignLast'));
  5419. /*!
  5420. {
  5421. "name": "CSS textDecoration",
  5422. "property": "textdecoration",
  5423. "caniuse": "text-decoration",
  5424. "tags": ["css"],
  5425. "notes": [{
  5426. "name": "W3C Spec",
  5427. "href": "https://www.w3.org/TR/css-text-decor-3/#line-decoration"
  5428. }]
  5429. }
  5430. !*/
  5431. (function() {
  5432. Modernizr.addTest('textdecoration', function() {
  5433. var bool = false;
  5434. var test = testAllProps('textDecoration');
  5435. try {
  5436. bool = !!test;
  5437. if (bool) {
  5438. bool = new Boolean(bool);
  5439. }
  5440. } catch (e) {}
  5441. return bool;
  5442. });
  5443. var props = ['Line', 'Style', 'Color', 'Skip', 'SkipInk'];
  5444. var name, test;
  5445. for (var i = 0; i < props.length; i++) {
  5446. name = props[i].toLowerCase();
  5447. test = testAllProps('textDecoration' + props[i]);
  5448. Modernizr.addTest('textdecoration.' + name, test);
  5449. }
  5450. })();
  5451. /*!
  5452. {
  5453. "name": "CSS textshadow",
  5454. "property": "textshadow",
  5455. "caniuse": "css-textshadow",
  5456. "tags": ["css"],
  5457. "knownBugs": ["FF3.0 will false positive on this test"]
  5458. }
  5459. !*/
  5460. Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px'));
  5461. /*!
  5462. {
  5463. "name": "CSS Transforms",
  5464. "property": "csstransforms",
  5465. "caniuse": "transforms2d",
  5466. "tags": ["css"]
  5467. }
  5468. !*/
  5469. Modernizr.addTest('csstransforms', function() {
  5470. // Android < 3.0 is buggy, so we sniff and blacklist
  5471. // https://github.com/Modernizr/Modernizr/issues/903
  5472. return navigator.userAgent.indexOf('Android 2.') === -1 &&
  5473. testAllProps('transform', 'scale(1)', true);
  5474. });
  5475. /*!
  5476. {
  5477. "name": "CSS Transforms 3D",
  5478. "property": "csstransforms3d",
  5479. "caniuse": "transforms3d",
  5480. "tags": ["css"],
  5481. "warnings": [
  5482. "Chrome may occasionally fail this test on some systems; more info: https://bugs.chromium.org/p/chromium/issues/detail?id=129004"
  5483. ]
  5484. }
  5485. !*/
  5486. Modernizr.addTest('csstransforms3d', function() {
  5487. return !!testAllProps('perspective', '1px', true);
  5488. });
  5489. /*!
  5490. {
  5491. "name": "CSS Transforms Level 2",
  5492. "property": "csstransformslevel2",
  5493. "authors": ["rupl"],
  5494. "tags": ["css"],
  5495. "notes": [{
  5496. "name": "CSSWG Draft Spec",
  5497. "href": "https://drafts.csswg.org/css-transforms-2/"
  5498. }]
  5499. }
  5500. !*/
  5501. Modernizr.addTest('csstransformslevel2', function() {
  5502. return testAllProps('translate', '45px', true);
  5503. });
  5504. /*!
  5505. {
  5506. "name": "CSS Transform Style preserve-3d",
  5507. "property": "preserve3d",
  5508. "authors": ["denyskoch", "aFarkas"],
  5509. "tags": ["css"],
  5510. "notes": [{
  5511. "name": "MDN Docs",
  5512. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style"
  5513. },{
  5514. "name": "Related Github Issue",
  5515. "href": "https://github.com/Modernizr/Modernizr/issues/1748"
  5516. }]
  5517. }
  5518. !*/
  5519. /* DOC
  5520. Detects support for `transform-style: preserve-3d`, for getting a proper 3D perspective on elements.
  5521. */
  5522. Modernizr.addTest('preserve3d', function() {
  5523. var outerAnchor, innerAnchor;
  5524. var CSS = window.CSS;
  5525. var result = false;
  5526. if (CSS && CSS.supports && CSS.supports('(transform-style: preserve-3d)')) {
  5527. return true;
  5528. }
  5529. outerAnchor = createElement('a');
  5530. innerAnchor = createElement('a');
  5531. outerAnchor.style.cssText = 'display: block; transform-style: preserve-3d; transform-origin: right; transform: rotateY(40deg);';
  5532. innerAnchor.style.cssText = 'display: block; width: 9px; height: 1px; background: #000; transform-origin: right; transform: rotateY(40deg);';
  5533. outerAnchor.appendChild(innerAnchor);
  5534. docElement.appendChild(outerAnchor);
  5535. result = innerAnchor.getBoundingClientRect();
  5536. docElement.removeChild(outerAnchor);
  5537. result = result.width && result.width < 4;
  5538. return result;
  5539. });
  5540. /*!
  5541. {
  5542. "name": "CSS user-select",
  5543. "property": "userselect",
  5544. "caniuse": "user-select-none",
  5545. "authors": ["ryan seddon"],
  5546. "tags": ["css"],
  5547. "builderAliases": ["css_userselect"],
  5548. "notes": [{
  5549. "name": "Related Modernizr Issue",
  5550. "href": "https://github.com/Modernizr/Modernizr/issues/250"
  5551. }]
  5552. }
  5553. !*/
  5554. //https://github.com/Modernizr/Modernizr/issues/250
  5555. Modernizr.addTest('userselect', testAllProps('userSelect', 'none', true));
  5556. /*!
  5557. {
  5558. "name": "CSS :valid pseudo-class",
  5559. "property": "cssvalid",
  5560. "notes": [{
  5561. "name": "MDN Docs",
  5562. "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:valid"
  5563. }]
  5564. }
  5565. !*/
  5566. /* DOC
  5567. Detects support for the ':valid' CSS pseudo-class.
  5568. */
  5569. Modernizr.addTest('cssvalid', function() {
  5570. return testStyles('#modernizr input{height:0;border:0;padding:0;margin:0;width:10px} #modernizr input:valid{width:50px}', function(elem) {
  5571. var input = createElement('input');
  5572. elem.appendChild(input);
  5573. return input.clientWidth > 10;
  5574. });
  5575. });
  5576. /*!
  5577. {
  5578. "name": "Variable Open Type Fonts",
  5579. "property": "variablefonts",
  5580. "authors": ["Patrick Kettner"],
  5581. "tags": ["css"],
  5582. "notes": [{
  5583. "name": "Variable fonts on the web",
  5584. "href": "https://webkit.org/blog/7051/variable-fonts-on-the-web/"
  5585. }, {
  5586. "name": "Variable fonts for responsive design",
  5587. "href": "https://alistapart.com/blog/post/variable-fonts-for-responsive-design"
  5588. }]
  5589. }
  5590. !*/
  5591. Modernizr.addTest('variablefonts', testAllProps('fontVariationSettings'));
  5592. /**
  5593. * roundedEquals takes two integers and checks if the first is within 1 of the second
  5594. *
  5595. * @access private
  5596. * @function roundedEquals
  5597. * @param {number} a - first integer
  5598. * @param {number} b - second integer
  5599. * @returns {boolean} true if the first integer is within 1 of the second, false otherwise
  5600. */
  5601. function roundedEquals(a, b) {
  5602. return a - 1 === b || a === b || a + 1 === b;
  5603. }
  5604. ;
  5605. /*!
  5606. {
  5607. "name": "CSS vh unit",
  5608. "property": "cssvhunit",
  5609. "caniuse": "viewport-units",
  5610. "tags": ["css"],
  5611. "builderAliases": ["css_vhunit"],
  5612. "notes": [{
  5613. "name": "Related Modernizr Issue",
  5614. "href": "https://github.com/Modernizr/Modernizr/issues/572"
  5615. },{
  5616. "name": "Similar JSFiddle",
  5617. "href": "https://jsfiddle.net/FWeinb/etnYC/"
  5618. }]
  5619. }
  5620. !*/
  5621. testStyles('#modernizr { height: 50vh; }', function(elem) {
  5622. var height = parseInt(window.innerHeight / 2, 10);
  5623. var compStyle = parseInt(computedStyle(elem, null, 'height'), 10);
  5624. Modernizr.addTest('cssvhunit', roundedEquals(compStyle, height));
  5625. });
  5626. /*!
  5627. {
  5628. "name": "CSS vmax unit",
  5629. "property": "cssvmaxunit",
  5630. "caniuse": "viewport-units",
  5631. "tags": ["css"],
  5632. "builderAliases": ["css_vmaxunit"],
  5633. "notes": [{
  5634. "name": "Related Modernizr Issue",
  5635. "href": "https://github.com/Modernizr/Modernizr/issues/572"
  5636. },{
  5637. "name": "JSFiddle Example",
  5638. "href": "https://jsfiddle.net/glsee/JDsWQ/4/"
  5639. }]
  5640. }
  5641. !*/
  5642. testStyles('#modernizr1{width: 50vmax}#modernizr2{width:50px;height:50px;overflow:scroll}#modernizr3{position:fixed;top:0;left:0;bottom:0;right:0}', function(node) {
  5643. var elem = node.childNodes[2];
  5644. var scroller = node.childNodes[1];
  5645. var fullSizeElem = node.childNodes[0];
  5646. var scrollbarWidth = parseInt((scroller.offsetWidth - scroller.clientWidth) / 2, 10);
  5647. var one_vw = fullSizeElem.clientWidth / 100;
  5648. var one_vh = fullSizeElem.clientHeight / 100;
  5649. var expectedWidth = parseInt(Math.max(one_vw, one_vh) * 50, 10);
  5650. var compWidth = parseInt(computedStyle(elem, null, 'width'), 10);
  5651. Modernizr.addTest('cssvmaxunit', roundedEquals(expectedWidth, compWidth) || roundedEquals(expectedWidth, compWidth - scrollbarWidth));
  5652. }, 3);
  5653. /*!
  5654. {
  5655. "name": "CSS vmin unit",
  5656. "property": "cssvminunit",
  5657. "caniuse": "viewport-units",
  5658. "tags": ["css"],
  5659. "builderAliases": ["css_vminunit"],
  5660. "notes": [{
  5661. "name": "Related Modernizr Issue",
  5662. "href": "https://github.com/Modernizr/Modernizr/issues/572"
  5663. },{
  5664. "name": "JSFiddle Example",
  5665. "href": "https://jsfiddle.net/glsee/JRmdq/8/"
  5666. }]
  5667. }
  5668. !*/
  5669. testStyles('#modernizr1{width: 50vm;width:50vmin}#modernizr2{width:50px;height:50px;overflow:scroll}#modernizr3{position:fixed;top:0;left:0;bottom:0;right:0}', function(node) {
  5670. var elem = node.childNodes[2];
  5671. var scroller = node.childNodes[1];
  5672. var fullSizeElem = node.childNodes[0];
  5673. var scrollbarWidth = parseInt((scroller.offsetWidth - scroller.clientWidth) / 2, 10);
  5674. var one_vw = fullSizeElem.clientWidth / 100;
  5675. var one_vh = fullSizeElem.clientHeight / 100;
  5676. var expectedWidth = parseInt(Math.min(one_vw, one_vh) * 50, 10);
  5677. var compWidth = parseInt(computedStyle(elem, null, 'width'), 10);
  5678. Modernizr.addTest('cssvminunit', roundedEquals(expectedWidth, compWidth) || roundedEquals(expectedWidth, compWidth - scrollbarWidth));
  5679. }, 3);
  5680. /*!
  5681. {
  5682. "name": "CSS vw unit",
  5683. "property": "cssvwunit",
  5684. "caniuse": "viewport-units",
  5685. "tags": ["css"],
  5686. "builderAliases": ["css_vwunit"],
  5687. "notes": [{
  5688. "name": "Related Modernizr Issue",
  5689. "href": "https://github.com/Modernizr/Modernizr/issues/572"
  5690. },{
  5691. "name": "JSFiddle Example",
  5692. "href": "https://jsfiddle.net/FWeinb/etnYC/"
  5693. }]
  5694. }
  5695. !*/
  5696. testStyles('#modernizr { width: 50vw; }', function(elem) {
  5697. var width = parseInt(window.innerWidth / 2, 10);
  5698. var compStyle = parseInt(computedStyle(elem, null, 'width'), 10);
  5699. Modernizr.addTest('cssvwunit', roundedEquals(compStyle, width));
  5700. });
  5701. /*!
  5702. {
  5703. "name": "will-change",
  5704. "property": "willchange",
  5705. "notes": [{
  5706. "name": "W3C Spec",
  5707. "href": "https://drafts.csswg.org/css-will-change/"
  5708. }]
  5709. }
  5710. !*/
  5711. /* DOC
  5712. Detects support for the `will-change` css property, which formally signals to the
  5713. browser that an element will be animating.
  5714. */
  5715. Modernizr.addTest('willchange', 'willChange' in docElement.style);
  5716. /*!
  5717. {
  5718. "name": "CSS wrap-flow",
  5719. "property": "wrapflow",
  5720. "tags": ["css"],
  5721. "notes": [{
  5722. "name": "W3C Spec",
  5723. "href": "https://www.w3.org/TR/css3-exclusions"
  5724. },{
  5725. "name": "Example by Louie Rootfield",
  5726. "href": "https://webdesign.tutsplus.com/tutorials/css-exclusions--cms-28087"
  5727. }]
  5728. }
  5729. !*/
  5730. Modernizr.addTest('wrapflow', function() {
  5731. var prefixedProperty = prefixed('wrapFlow');
  5732. if (!prefixedProperty || isSVG) {
  5733. return false;
  5734. }
  5735. var wrapFlowProperty = prefixedProperty.replace(/([A-Z])/g, function(str, m1) { return '-' + m1.toLowerCase(); }).replace(/^ms-/, '-ms-');
  5736. /* If the CSS parsing is there we need to determine if wrap-flow actually works to avoid false positive cases, e.g. the browser parses
  5737. the property, but it hasn't got the implementation for the functionality yet. */
  5738. var container = createElement('div');
  5739. var exclusion = createElement('div');
  5740. var content = createElement('span');
  5741. /* First we create a div with two adjacent divs inside it. The first div will be the content, the second div will be the exclusion area.
  5742. We use the "wrap-flow: end" property to test the actual behavior. (https://drafts.csswg.org/css-exclusions-1/#wrap-flow-property)
  5743. The wrap-flow property is applied to the exclusion area what has a 50px left offset and a 100px width.
  5744. If the wrap-flow property is working correctly then the content should start after the exclusion area, so the content's left offset should be 150px. */
  5745. exclusion.style.cssText = 'position: absolute; left: 50px; width: 100px; height: 20px;' + wrapFlowProperty + ':end;';
  5746. content.innerText = 'X';
  5747. container.appendChild(exclusion);
  5748. container.appendChild(content);
  5749. docElement.appendChild(container);
  5750. var leftOffset = content.offsetLeft;
  5751. docElement.removeChild(container);
  5752. exclusion = content = container = undefined;
  5753. return (leftOffset === 150);
  5754. });
  5755. /*!
  5756. {
  5757. "name": "classList",
  5758. "caniuse": "classlist",
  5759. "property": "classlist",
  5760. "tags": ["dom"],
  5761. "builderAliases": ["dataview_api"],
  5762. "notes": [{
  5763. "name": "MDN Docs",
  5764. "href": "https://developer.mozilla.org/en/DOM/element.classList"
  5765. }]
  5766. }
  5767. !*/
  5768. Modernizr.addTest('classlist', 'classList' in docElement);
  5769. /*!
  5770. {
  5771. "name": "createElement with Attributes",
  5772. "property": ["createelementattrs", "createelement-attrs"],
  5773. "tags": ["dom"],
  5774. "builderAliases": ["dom_createElement_attrs"],
  5775. "authors": ["James A. Rosen"],
  5776. "notes": [{
  5777. "name": "Related Github Issue",
  5778. "href": "https://github.com/Modernizr/Modernizr/issues/258"
  5779. }]
  5780. }
  5781. !*/
  5782. Modernizr.addTest('createelementattrs', function() {
  5783. try {
  5784. return createElement('<input name="test" />').getAttribute('name') === 'test';
  5785. } catch (e) {
  5786. return false;
  5787. }
  5788. }, {
  5789. aliases: ['createelement-attrs']
  5790. });
  5791. /*!
  5792. {
  5793. "name": "dataset API",
  5794. "caniuse": "dataset",
  5795. "property": "dataset",
  5796. "tags": ["dom"],
  5797. "builderAliases": ["dom_dataset"],
  5798. "authors": ["@phiggins42"]
  5799. }
  5800. !*/
  5801. // dataset API for data-* attributes
  5802. Modernizr.addTest('dataset', function() {
  5803. var n = createElement('div');
  5804. n.setAttribute('data-a-b', 'c');
  5805. return !!(n.dataset && n.dataset.aB === 'c');
  5806. });
  5807. /*!
  5808. {
  5809. "name": "Document Fragment",
  5810. "property": "documentfragment",
  5811. "notes": [{
  5812. "name": "W3C Spec",
  5813. "href": "https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-B63ED1A3"
  5814. }, {
  5815. "name": "MDN Docs",
  5816. "href": "https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment"
  5817. }, {
  5818. "name": "QuirksMode Compatibility Tables",
  5819. "href": "https://www.quirksmode.org/m/w3c_core.html#t112"
  5820. }],
  5821. "authors": ["Ron Waldon (@jokeyrhyme)"],
  5822. "knownBugs": ["false-positive on Blackberry 9500, see QuirksMode note"],
  5823. "tags": ["dom"]
  5824. }
  5825. !*/
  5826. /* DOC
  5827. Append multiple elements to the DOM within a single insertion.
  5828. */
  5829. Modernizr.addTest('documentfragment', function() {
  5830. return 'createDocumentFragment' in document &&
  5831. 'appendChild' in docElement;
  5832. });
  5833. /*!
  5834. {
  5835. "name": "[hidden] Attribute",
  5836. "property": "hidden",
  5837. "tags": ["dom"],
  5838. "notes": [{
  5839. "name": "WHATWG Spec",
  5840. "href": "https://html.spec.whatwg.org/dev/interaction.html#the-hidden-attribute"
  5841. }, {
  5842. "name": "original implementation of detect code",
  5843. "href": "https://github.com/aFarkas/html5shiv/blob/bf4fcc4/src/html5shiv.js#L38"
  5844. }],
  5845. "polyfills": ["html5shiv"],
  5846. "authors": ["Ron Waldon (@jokeyrhyme)"]
  5847. }
  5848. !*/
  5849. /* DOC
  5850. Does the browser support the HTML5 [hidden] attribute?
  5851. */
  5852. Modernizr.addTest('hidden', 'hidden' in createElement('a'));
  5853. /*!
  5854. {
  5855. "name": "Intersection Observer",
  5856. "property": "intersectionobserver",
  5857. "caniuse": "intersectionobserver",
  5858. "tags": ["dom"],
  5859. "notes": [{
  5860. "name": "W3C Spec",
  5861. "href": "https://w3c.github.io/IntersectionObserver/"
  5862. }, {
  5863. "name": "IntersectionObserver polyfill",
  5864. "href": "https://github.com/w3c/IntersectionObserver/tree/master/polyfill"
  5865. }, {
  5866. "name": "MDN Docs",
  5867. "href": "https://developer.mozilla.org/en/docs/Web/API/Intersection_Observer_API"
  5868. }]
  5869. }
  5870. !*/
  5871. /* DOC
  5872. Determines if Intersection Observer API is available.
  5873. */
  5874. Modernizr.addTest('intersectionobserver', 'IntersectionObserver' in window);
  5875. /*!
  5876. {
  5877. "name": "microdata",
  5878. "property": "microdata",
  5879. "tags": ["dom"],
  5880. "builderAliases": ["dom_microdata"],
  5881. "notes": [{
  5882. "name": "W3C Spec",
  5883. "href": "https://www.w3.org/TR/microdata/"
  5884. }]
  5885. }
  5886. !*/
  5887. Modernizr.addTest('microdata', 'getItems' in document);
  5888. /*!
  5889. {
  5890. "name": "DOM4 MutationObserver",
  5891. "property": "mutationobserver",
  5892. "caniuse": "mutationobserver",
  5893. "tags": ["dom"],
  5894. "authors": ["Karel Sedláček (@ksdlck)"],
  5895. "polyfills": ["mutationobservers"],
  5896. "notes": [{
  5897. "name": "MDN Docs",
  5898. "href": "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"
  5899. }]
  5900. }
  5901. !*/
  5902. /* DOC
  5903. Determines if DOM4 MutationObserver support is available.
  5904. */
  5905. Modernizr.addTest('mutationobserver',
  5906. !!window.MutationObserver || !!window.WebKitMutationObserver);
  5907. /*!
  5908. {
  5909. "property": "passiveeventlisteners",
  5910. "tags": ["dom"],
  5911. "authors": ["Rick Byers"],
  5912. "name": "Passive event listeners",
  5913. "notes": [{
  5914. "name": "WHATWG Spec",
  5915. "href": "https://dom.spec.whatwg.org/#dom-addeventlisteneroptions-passive"
  5916. },{
  5917. "name": "WICG explainer",
  5918. "href": "https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md"
  5919. }]
  5920. }
  5921. !*/
  5922. /* DOC
  5923. Detects support for the passive option to addEventListener.
  5924. */
  5925. Modernizr.addTest('passiveeventlisteners', function() {
  5926. var supportsPassiveOption = false;
  5927. try {
  5928. var opts = Object.defineProperty({}, 'passive', {
  5929. get: function() {
  5930. supportsPassiveOption = true;
  5931. }
  5932. });
  5933. var noop = function () {};
  5934. window.addEventListener('testPassiveEventSupport', noop, opts);
  5935. window.removeEventListener('testPassiveEventSupport', noop, opts);
  5936. } catch (e) {}
  5937. return supportsPassiveOption;
  5938. });
  5939. /*!
  5940. {
  5941. "name": "bdi Element",
  5942. "property": "bdi",
  5943. "notes": [{
  5944. "name": "MDN Docs",
  5945. "href": "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi"
  5946. }]
  5947. }
  5948. !*/
  5949. /* DOC
  5950. Detect support for the bdi element, a way to have text that is isolated from its possibly bidirectional surroundings
  5951. */
  5952. Modernizr.addTest('bdi', function() {
  5953. var div = createElement('div');
  5954. var bdi = createElement('bdi');
  5955. bdi.innerHTML = '&#1573;';
  5956. div.appendChild(bdi);
  5957. docElement.appendChild(div);
  5958. var supports = computedStyle(bdi, null, 'direction') === 'rtl';
  5959. docElement.removeChild(div);
  5960. return supports;
  5961. });
  5962. /*!
  5963. {
  5964. "name": "datalist Element",
  5965. "caniuse": "datalist",
  5966. "property": "datalistelem",
  5967. "tags": ["elem"],
  5968. "builderAliases": ["elem_datalist"],
  5969. "warnings": ["This test is a dupe of Modernizr.input.list. Only around for legacy reasons."],
  5970. "notes": [{
  5971. "name": "CSS Tricks Article",
  5972. "href": "https://css-tricks.com/relevant-dropdowns-polyfill-for-datalist/"
  5973. },{
  5974. "name": "Mike Taylor Code",
  5975. "href": "https://miketaylr.com/code/datalist.html"
  5976. }]
  5977. }
  5978. !*/
  5979. // lol. we already have a test for datalist built in! silly you.
  5980. // Leaving it around in case anyone's using it
  5981. Modernizr.addTest('datalistelem', Modernizr.input.list);
  5982. /*!
  5983. {
  5984. "name": "details Element",
  5985. "caniuse": "details",
  5986. "property": "details",
  5987. "tags": ["elem"],
  5988. "builderAliases": ["elem_details"],
  5989. "authors": ["@mathias"],
  5990. "notes": [{
  5991. "name": "Mathias' Original",
  5992. "href": "https://mathiasbynens.be/notes/html5-details-jquery#comment-35"
  5993. }]
  5994. }
  5995. !*/
  5996. Modernizr.addTest('details', function() {
  5997. var el = createElement('details');
  5998. var diff;
  5999. // return early if possible; thanks @aFarkas!
  6000. if (!('open' in el)) {
  6001. return false;
  6002. }
  6003. testStyles('#modernizr details{display:block}', function(node) {
  6004. node.appendChild(el);
  6005. el.innerHTML = '<summary>a</summary>b';
  6006. diff = el.offsetHeight;
  6007. el.open = true;
  6008. diff = diff !== el.offsetHeight;
  6009. });
  6010. return diff;
  6011. });
  6012. /*!
  6013. {
  6014. "name": "output Element",
  6015. "property": "outputelem",
  6016. "tags": ["elem"],
  6017. "builderAliases": ["elem_output"],
  6018. "notes": [{
  6019. "name": "WhatWG Spec",
  6020. "href": "https://html.spec.whatwg.org/multipage/form-elements.html#the-output-element"
  6021. }]
  6022. }
  6023. !*/
  6024. Modernizr.addTest('outputelem', 'value' in createElement('output'));
  6025. /*!
  6026. {
  6027. "name": "picture Element",
  6028. "property": "picture",
  6029. "tags": ["elem"],
  6030. "authors": ["Scott Jehl", "Mat Marquis"],
  6031. "notes": [{
  6032. "name": "WHATWG Spec",
  6033. "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#embedded-content"
  6034. },{
  6035. "name": "Relevant spec issue",
  6036. "href": "https://github.com/ResponsiveImagesCG/picture-element/issues/87"
  6037. }]
  6038. }
  6039. !*/
  6040. Modernizr.addTest('picture', 'HTMLPictureElement' in window);
  6041. /*!
  6042. {
  6043. "name": "progress Element",
  6044. "caniuse": "progress",
  6045. "property": ["progressbar", "meter"],
  6046. "tags": ["elem"],
  6047. "builderAliases": ["elem_progress_meter"],
  6048. "authors": ["Stefan Wallin"]
  6049. }
  6050. !*/
  6051. // Tests for progressbar-support. All browsers that don't support progressbar returns undefined =)
  6052. Modernizr.addTest('progressbar', createElement('progress').max !== undefined);
  6053. // Tests for meter-support. All browsers that don't support meters returns undefined =)
  6054. Modernizr.addTest('meter', createElement('meter').max !== undefined);
  6055. /*!
  6056. {
  6057. "name": "ruby, rp, rt Elements",
  6058. "caniuse": "ruby",
  6059. "property": "ruby",
  6060. "tags": ["elem"],
  6061. "builderAliases": ["elem_ruby"],
  6062. "authors": ["Cătălin Mariș"],
  6063. "notes": [{
  6064. "name": "WHATWG Spec",
  6065. "href": "https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-ruby-element"
  6066. }]
  6067. }
  6068. !*/
  6069. Modernizr.addTest('ruby', function() {
  6070. var ruby = createElement('ruby');
  6071. var rt = createElement('rt');
  6072. var rp = createElement('rp');
  6073. var displayStyleProperty = 'display';
  6074. // 'fontSize' - because it`s only used for IE6 and IE7
  6075. var fontSizeStyleProperty = 'fontSize';
  6076. ruby.appendChild(rp);
  6077. ruby.appendChild(rt);
  6078. docElement.appendChild(ruby);
  6079. // browsers that support <ruby> hide the <rp> via "display:none"
  6080. if (getStyle(rp, displayStyleProperty) === 'none' || // for non-IE browsers
  6081. // but in IE browsers <rp> has "display:inline" so, the test needs other conditions:
  6082. getStyle(ruby, displayStyleProperty) === 'ruby' && getStyle(rt, displayStyleProperty) === 'ruby-text' || // for IE8+
  6083. getStyle(rp, fontSizeStyleProperty) === '6pt' && getStyle(rt, fontSizeStyleProperty) === '6pt') { // for IE6 & IE7
  6084. cleanUp();
  6085. return true;
  6086. } else {
  6087. cleanUp();
  6088. return false;
  6089. }
  6090. function getStyle(element, styleProperty) {
  6091. var result;
  6092. if (window.getComputedStyle) { // for non-IE browsers
  6093. result = document.defaultView.getComputedStyle(element, null).getPropertyValue(styleProperty);
  6094. } else if (element.currentStyle) { // for IE
  6095. result = element.currentStyle[styleProperty];
  6096. }
  6097. return result;
  6098. }
  6099. function cleanUp() {
  6100. docElement.removeChild(ruby);
  6101. // the removed child node still exists in memory, so ...
  6102. ruby = null;
  6103. rt = null;
  6104. rp = null;
  6105. }
  6106. });
  6107. /*!
  6108. {
  6109. "name": "Template Tag",
  6110. "property": "template",
  6111. "tags": ["elem"],
  6112. "notes": [{
  6113. "name": "HTML5Rocks Article",
  6114. "href": "https://www.html5rocks.com/en/tutorials/webcomponents/template/"
  6115. },{
  6116. "name": "W3C Spec",
  6117. "href": "https://web.archive.org/web/20171130222649/http://www.w3.org/TR/html5/scripting-1.html"
  6118. }]
  6119. }
  6120. !*/
  6121. Modernizr.addTest('template', 'content' in createElement('template'));
  6122. /*!
  6123. {
  6124. "name": "time Element",
  6125. "property": "time",
  6126. "tags": ["elem"],
  6127. "builderAliases": ["elem_time"],
  6128. "notes": [{
  6129. "name": "WHATWG Spec",
  6130. "href": "https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-time-element"
  6131. }]
  6132. }
  6133. !*/
  6134. Modernizr.addTest('time', 'valueAsDate' in createElement('time'));
  6135. /*!
  6136. {
  6137. "name": "Track element and Timed Text Track",
  6138. "property": ["texttrackapi", "track"],
  6139. "tags": ["elem"],
  6140. "builderAliases": ["elem_track"],
  6141. "authors": ["Addy Osmani"],
  6142. "notes": [{
  6143. "name": "W3C Spec (Track Element)",
  6144. "href": "https://web.archive.org/web/20121119095019/http://www.w3.org/TR/html5/the-track-element.html#the-track-element"
  6145. },{
  6146. "name": "W3C Spec (Track API)",
  6147. "href": "https://web.archive.org/web/20121119094620/http://www.w3.org/TR/html5/media-elements.html#text-track-api"
  6148. }],
  6149. "warnings": ["While IE10 has implemented the track element, IE10 does not expose the underlying APIs to create timed text tracks by JS (really sad)"]
  6150. }
  6151. !*/
  6152. Modernizr.addTest('texttrackapi', typeof (createElement('video').addTextTrack) === 'function');
  6153. // a more strict test for track including UI support: document.createElement('track').kind === 'subtitles'
  6154. Modernizr.addTest('track', 'kind' in createElement('track'));
  6155. /*!
  6156. {
  6157. "name": "Unknown Elements",
  6158. "property": "unknownelements",
  6159. "tags": ["elem"],
  6160. "notes": [{
  6161. "name": "The Story of the HTML5 Shiv",
  6162. "href": "https://www.paulirish.com/2011/the-history-of-the-html5-shiv/"
  6163. }, {
  6164. "name": "original implementation of detect code",
  6165. "href": "https://github.com/aFarkas/html5shiv/blob/bf4fcc4/src/html5shiv.js#L36"
  6166. }],
  6167. "polyfills": ["html5shiv"],
  6168. "authors": ["Ron Waldon (@jokeyrhyme)"]
  6169. }
  6170. !*/
  6171. /* DOC
  6172. Does the browser support HTML with non-standard / new elements?
  6173. */
  6174. Modernizr.addTest('unknownelements', function() {
  6175. var a = createElement('a');
  6176. a.innerHTML = '<xyz></xyz>';
  6177. return a.childNodes.length === 1;
  6178. });
  6179. /*!
  6180. {
  6181. "name": "ES5 Array",
  6182. "property": "es5array",
  6183. "notes": [{
  6184. "name": "ECMAScript 5.1 Language Specification",
  6185. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6186. }],
  6187. "polyfills": ["es5shim"],
  6188. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6189. "tags": ["es5"]
  6190. }
  6191. !*/
  6192. /* DOC
  6193. Check if browser implements ECMAScript 5 Array per specification.
  6194. */
  6195. Modernizr.addTest('es5array', function() {
  6196. return !!(Array.prototype &&
  6197. Array.prototype.every &&
  6198. Array.prototype.filter &&
  6199. Array.prototype.forEach &&
  6200. Array.prototype.indexOf &&
  6201. Array.prototype.lastIndexOf &&
  6202. Array.prototype.map &&
  6203. Array.prototype.some &&
  6204. Array.prototype.reduce &&
  6205. Array.prototype.reduceRight &&
  6206. Array.isArray);
  6207. });
  6208. /*!
  6209. {
  6210. "name": "ES5 Date",
  6211. "property": "es5date",
  6212. "notes": [{
  6213. "name": "ECMAScript 5.1 Language Specification",
  6214. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6215. }],
  6216. "polyfills": ["es5shim"],
  6217. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6218. "tags": ["es5"]
  6219. }
  6220. !*/
  6221. /* DOC
  6222. Check if browser implements ECMAScript 5 Date per specification.
  6223. */
  6224. Modernizr.addTest('es5date', function() {
  6225. var isoDate = '2013-04-12T06:06:37.307Z',
  6226. canParseISODate = false;
  6227. try {
  6228. canParseISODate = !!Date.parse(isoDate);
  6229. } catch (e) {
  6230. // no ISO date parsing yet
  6231. }
  6232. return !!(Date.now &&
  6233. Date.prototype &&
  6234. Date.prototype.toISOString &&
  6235. Date.prototype.toJSON &&
  6236. canParseISODate);
  6237. });
  6238. /*!
  6239. {
  6240. "name": "ES5 Function",
  6241. "property": "es5function",
  6242. "notes": [{
  6243. "name": "ECMAScript 5.1 Language Specification",
  6244. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6245. }],
  6246. "polyfills": ["es5shim"],
  6247. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6248. "tags": ["es5"]
  6249. }
  6250. !*/
  6251. /* DOC
  6252. Check if browser implements ECMAScript 5 Function per specification.
  6253. */
  6254. Modernizr.addTest('es5function', function() {
  6255. return !!(Function.prototype && Function.prototype.bind);
  6256. });
  6257. /*!
  6258. {
  6259. "name": "ES5 Object",
  6260. "property": "es5object",
  6261. "notes": [{
  6262. "name": "ECMAScript 5.1 Language Specification",
  6263. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6264. }],
  6265. "polyfills": ["es5shim", "es5sham"],
  6266. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6267. "tags": ["es5"]
  6268. }
  6269. !*/
  6270. /* DOC
  6271. Check if browser implements ECMAScript 5 Object per specification.
  6272. */
  6273. Modernizr.addTest('es5object', function() {
  6274. return !!(Object.keys &&
  6275. Object.create &&
  6276. Object.getPrototypeOf &&
  6277. Object.getOwnPropertyNames &&
  6278. Object.isSealed &&
  6279. Object.isFrozen &&
  6280. Object.isExtensible &&
  6281. Object.getOwnPropertyDescriptor &&
  6282. Object.defineProperty &&
  6283. Object.defineProperties &&
  6284. Object.seal &&
  6285. Object.freeze &&
  6286. Object.preventExtensions);
  6287. });
  6288. /*!
  6289. {
  6290. "name": "ES5 Strict Mode",
  6291. "property": "strictmode",
  6292. "caniuse": "use-strict",
  6293. "notes": [{
  6294. "name": "ECMAScript 5.1 Language Specification",
  6295. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6296. }],
  6297. "authors": ["@kangax"],
  6298. "tags": ["es5"],
  6299. "builderAliases": ["es5_strictmode"]
  6300. }
  6301. !*/
  6302. /* DOC
  6303. Check if browser implements ECMAScript 5 Object strict mode.
  6304. */
  6305. Modernizr.addTest('strictmode', (function() {'use strict'; return !this; })());
  6306. /*!
  6307. {
  6308. "name": "ES5 String",
  6309. "property": "es5string",
  6310. "notes": [{
  6311. "name": "ECMAScript 5.1 Language Specification",
  6312. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6313. }],
  6314. "polyfills": ["es5shim"],
  6315. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6316. "tags": ["es5"]
  6317. }
  6318. !*/
  6319. /* DOC
  6320. Check if browser implements ECMAScript 5 String per specification.
  6321. */
  6322. Modernizr.addTest('es5string', function() {
  6323. return !!(String.prototype && String.prototype.trim);
  6324. });
  6325. /*!
  6326. {
  6327. "name": "ES5 Syntax",
  6328. "property": "es5syntax",
  6329. "notes": [{
  6330. "name": "ECMAScript 5.1 Language Specification",
  6331. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6332. }, {
  6333. "name": "original implementation of detect code",
  6334. "href": "https://kangax.github.io/compat-table/es5/"
  6335. }],
  6336. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6337. "warnings": ["This detect uses `eval()`, so CSP may be a problem."],
  6338. "tags": ["es5"]
  6339. }
  6340. !*/
  6341. /* DOC
  6342. Check if browser accepts ECMAScript 5 syntax.
  6343. */
  6344. Modernizr.addTest('es5syntax', function() {
  6345. var value, obj, stringAccess, getter, setter, reservedWords, zeroWidthChars;
  6346. try {
  6347. /* eslint no-eval: "off" */
  6348. // Property access on strings
  6349. stringAccess = eval('"foobar"[3] === "b"');
  6350. // Getter in property initializer
  6351. getter = eval('({ get x(){ return 1 } }).x === 1');
  6352. eval('({ set x(v){ value = v; } }).x = 1');
  6353. // Setter in property initializer
  6354. setter = value === 1;
  6355. // Reserved words as property names
  6356. eval('obj = ({ if: 1 })');
  6357. reservedWords = obj['if'] === 1;
  6358. // Zero-width characters in identifiers
  6359. zeroWidthChars = eval('_\u200c\u200d = true');
  6360. return stringAccess && getter && setter && reservedWords && zeroWidthChars;
  6361. } catch (ignore) {
  6362. return false;
  6363. }
  6364. });
  6365. /*!
  6366. {
  6367. "name": "ES5 Immutable Undefined",
  6368. "property": "es5undefined",
  6369. "notes": [{
  6370. "name": "ECMAScript 5.1 Language Specification",
  6371. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6372. }, {
  6373. "name": "original implementation of detect code",
  6374. "href": "https://kangax.github.io/compat-table/es5/"
  6375. }],
  6376. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6377. "tags": ["es5"]
  6378. }
  6379. !*/
  6380. /* DOC
  6381. Check if browser prevents assignment to global `undefined` per ECMAScript 5.
  6382. */
  6383. Modernizr.addTest('es5undefined', function() {
  6384. var result, originalUndefined;
  6385. try {
  6386. originalUndefined = window.undefined;
  6387. window.undefined = 12345;
  6388. result = typeof window.undefined === 'undefined';
  6389. window.undefined = originalUndefined;
  6390. } catch (e) {
  6391. return false;
  6392. }
  6393. return result;
  6394. });
  6395. /*!
  6396. {
  6397. "name": "ES5",
  6398. "property": "es5",
  6399. "caniuse": "es5",
  6400. "notes": [{
  6401. "name": "ECMAScript 5.1 Language Specification",
  6402. "href": "https://www.ecma-international.org/ecma-262/5.1/"
  6403. }],
  6404. "polyfills": ["es5shim", "es5sham"],
  6405. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6406. "tags": ["es5"]
  6407. }
  6408. !*/
  6409. /* DOC
  6410. Check if browser implements everything as specified in ECMAScript 5.
  6411. */
  6412. Modernizr.addTest('es5', function() {
  6413. return !!(
  6414. Modernizr.es5array &&
  6415. Modernizr.es5date &&
  6416. Modernizr.es5function &&
  6417. Modernizr.es5object &&
  6418. Modernizr.strictmode &&
  6419. Modernizr.es5string &&
  6420. Modernizr.json &&
  6421. Modernizr.es5syntax &&
  6422. Modernizr.es5undefined
  6423. );
  6424. });
  6425. /*!
  6426. {
  6427. "name": "ES6 Array",
  6428. "property": "es6array",
  6429. "notes": [{
  6430. "name": "unofficial ECMAScript 6 draft specification",
  6431. "href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
  6432. }],
  6433. "polyfills": ["es6shim"],
  6434. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6435. "warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
  6436. "tags": ["es6"]
  6437. }
  6438. !*/
  6439. /* DOC
  6440. Check if browser implements ECMAScript 6 Array per specification.
  6441. */
  6442. Modernizr.addTest('es6array', !!(Array.prototype &&
  6443. Array.prototype.copyWithin &&
  6444. Array.prototype.fill &&
  6445. Array.prototype.find &&
  6446. Array.prototype.findIndex &&
  6447. Array.prototype.keys &&
  6448. Array.prototype.entries &&
  6449. Array.prototype.values &&
  6450. Array.from &&
  6451. Array.of));
  6452. /*!
  6453. {
  6454. "name": "ES6 Arrow Functions",
  6455. "property": "arrow",
  6456. "authors": ["Vincent Riemer"],
  6457. "tags": ["es6"]
  6458. }
  6459. !*/
  6460. /* DOC
  6461. Check if browser implements ECMAScript 6 Arrow Functions per specification.
  6462. */
  6463. Modernizr.addTest('arrow', function() {
  6464. try {
  6465. // eslint-disable-next-line
  6466. eval('()=>{}');
  6467. } catch (e) {
  6468. return false;
  6469. }
  6470. return true;
  6471. });
  6472. /*!
  6473. {
  6474. "name": "ES6 Collections",
  6475. "property": "es6collections",
  6476. "notes": [{
  6477. "name": "unofficial ECMAScript 6 draft specification",
  6478. "href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
  6479. }],
  6480. "polyfills": ["es6shim", "weakmap"],
  6481. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6482. "warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
  6483. "tags": ["es6"]
  6484. }
  6485. !*/
  6486. /* DOC
  6487. Check if browser implements ECMAScript 6 Map, Set, WeakMap and WeakSet
  6488. */
  6489. Modernizr.addTest('es6collections', !!(
  6490. window.Map && window.Set && window.WeakMap && window.WeakSet
  6491. ));
  6492. /*!
  6493. {
  6494. "name": "ES5 String.prototype.contains",
  6495. "property": "contains",
  6496. "authors": ["Robert Kowalski"],
  6497. "tags": ["es6"]
  6498. }
  6499. !*/
  6500. /* DOC
  6501. Check if browser implements ECMAScript 6 `String.prototype.contains` per specification.
  6502. */
  6503. Modernizr.addTest('contains', is(String.prototype.contains, 'function'));
  6504. /*!
  6505. {
  6506. "name": "ES6 Generators",
  6507. "property": "generators",
  6508. "authors": ["Michael Kachanovskyi"],
  6509. "tags": ["es6"]
  6510. }
  6511. !*/
  6512. /* DOC
  6513. Check if browser implements ECMAScript 6 Generators per specification.
  6514. */
  6515. Modernizr.addTest('generators', function() {
  6516. try {
  6517. new Function('function* test() {}')();
  6518. } catch (e) {
  6519. return false;
  6520. }
  6521. return true;
  6522. });
  6523. /*!
  6524. {
  6525. "name": "ES6 Math",
  6526. "property": "es6math",
  6527. "notes": [{
  6528. "name": "unofficial ECMAScript 6 draft specification",
  6529. "href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
  6530. }],
  6531. "polyfills": ["es6shim"],
  6532. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6533. "warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
  6534. "tags": ["es6"]
  6535. }
  6536. !*/
  6537. /* DOC
  6538. Check if browser implements ECMAScript 6 Math per specification.
  6539. */
  6540. Modernizr.addTest('es6math', !!(Math &&
  6541. Math.clz32 &&
  6542. Math.cbrt &&
  6543. Math.imul &&
  6544. Math.sign &&
  6545. Math.log10 &&
  6546. Math.log2 &&
  6547. Math.log1p &&
  6548. Math.expm1 &&
  6549. Math.cosh &&
  6550. Math.sinh &&
  6551. Math.tanh &&
  6552. Math.acosh &&
  6553. Math.asinh &&
  6554. Math.atanh &&
  6555. Math.hypot &&
  6556. Math.trunc &&
  6557. Math.fround));
  6558. /*!
  6559. {
  6560. "name": "ES6 Number",
  6561. "property": "es6number",
  6562. "notes": [{
  6563. "name": "unofficial ECMAScript 6 draft specification",
  6564. "href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
  6565. }],
  6566. "polyfills": ["es6shim"],
  6567. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6568. "warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
  6569. "tags": ["es6"]
  6570. }
  6571. !*/
  6572. /* DOC
  6573. Check if browser implements ECMAScript 6 Number per specification.
  6574. */
  6575. Modernizr.addTest('es6number', !!(Number.isFinite &&
  6576. Number.isInteger &&
  6577. Number.isSafeInteger &&
  6578. Number.isNaN &&
  6579. Number.parseInt &&
  6580. Number.parseFloat &&
  6581. Number.isInteger(Number.MAX_SAFE_INTEGER) &&
  6582. Number.isInteger(Number.MIN_SAFE_INTEGER) &&
  6583. Number.isFinite(Number.EPSILON)));
  6584. /*!
  6585. {
  6586. "name": "ES6 Object",
  6587. "property": "es6object",
  6588. "notes": [{
  6589. "name": "unofficial ECMAScript 6 draft specification",
  6590. "href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
  6591. }],
  6592. "polyfills": ["es6shim"],
  6593. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6594. "warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
  6595. "tags": ["es6"]
  6596. }
  6597. !*/
  6598. /* DOC
  6599. Check if browser implements ECMAScript 6 Object per specification.
  6600. */
  6601. Modernizr.addTest('es6object', !!(Object.assign &&
  6602. Object.is &&
  6603. Object.setPrototypeOf));
  6604. /*!
  6605. {
  6606. "name": "ES6 Promises",
  6607. "property": "promises",
  6608. "caniuse": "promises",
  6609. "polyfills": ["es6promises"],
  6610. "authors": ["Krister Kari", "Jake Archibald"],
  6611. "tags": ["es6"],
  6612. "notes": [{
  6613. "name": "The ES6 promises spec",
  6614. "href": "https://github.com/domenic/promises-unwrapping"
  6615. },{
  6616. "name": "Chromium dashboard - ES6 Promises",
  6617. "href": "https://www.chromestatus.com/features/5681726336532480"
  6618. },{
  6619. "name": "JavaScript Promises: an Introduction",
  6620. "href": "https://developers.google.com/web/fundamentals/primers/promises/"
  6621. }]
  6622. }
  6623. !*/
  6624. /* DOC
  6625. Check if browser implements ECMAScript 6 Promises per specification.
  6626. */
  6627. Modernizr.addTest('promises', function() {
  6628. return 'Promise' in window &&
  6629. // Some of these methods are missing from
  6630. // Firefox/Chrome experimental implementations
  6631. 'resolve' in window.Promise &&
  6632. 'reject' in window.Promise &&
  6633. 'all' in window.Promise &&
  6634. 'race' in window.Promise &&
  6635. // Older version of the spec had a resolver object
  6636. // as the arg rather than a function
  6637. (function() {
  6638. var resolve;
  6639. new window.Promise(function(r) { resolve = r; });
  6640. return typeof resolve === 'function';
  6641. }());
  6642. });
  6643. /*!
  6644. {
  6645. "name": "ES6 String",
  6646. "property": "es6string",
  6647. "notes": [{
  6648. "name": "unofficial ECMAScript 6 draft specification",
  6649. "href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
  6650. }],
  6651. "polyfills": ["es6shim"],
  6652. "authors": ["Ron Waldon (@jokeyrhyme)"],
  6653. "warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
  6654. "tags": ["es6"]
  6655. }
  6656. !*/
  6657. /* DOC
  6658. Check if browser implements ECMAScript 6 String per specification.
  6659. */
  6660. Modernizr.addTest('es6string', !!(String.fromCodePoint &&
  6661. String.raw &&
  6662. String.prototype.codePointAt &&
  6663. String.prototype.repeat &&
  6664. String.prototype.startsWith &&
  6665. String.prototype.endsWith &&
  6666. String.prototype.includes));
  6667. /*!
  6668. {
  6669. "name": "Orientation and Motion Events",
  6670. "property": ["devicemotion", "deviceorientation"],
  6671. "caniuse": "deviceorientation",
  6672. "notes": [{
  6673. "name": "W3C Editor's Draft Spec",
  6674. "href": "https://w3c.github.io/deviceorientation/"
  6675. },{
  6676. "name": "MDN Docs",
  6677. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Detecting_device_orientation"
  6678. }],
  6679. "authors": ["Shi Chuan"],
  6680. "tags": ["event"],
  6681. "builderAliases": ["event_deviceorientation_motion"]
  6682. }
  6683. !*/
  6684. /* DOC
  6685. Part of Device Access aspect of HTML5, same category as geolocation.
  6686. `devicemotion` tests for Device Motion Event support, returns boolean value true/false.
  6687. `deviceorientation` tests for Device Orientation Event support, returns boolean value true/false
  6688. */
  6689. Modernizr.addTest('devicemotion', 'DeviceMotionEvent' in window);
  6690. Modernizr.addTest('deviceorientation', 'DeviceOrientationEvent' in window);
  6691. /*!
  6692. {
  6693. "name": "onInput Event",
  6694. "property": "oninput",
  6695. "notes": [{
  6696. "name": "MDN Docs",
  6697. "href": "https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.oninput"
  6698. },{
  6699. "name": "WHATWG Spec",
  6700. "href": "https://html.spec.whatwg.org/multipage/input.html#common-input-element-attributes"
  6701. },{
  6702. "name": "Related Github Issue",
  6703. "href": "https://github.com/Modernizr/Modernizr/issues/210"
  6704. }],
  6705. "authors": ["Patrick Kettner"],
  6706. "tags": ["event"]
  6707. }
  6708. !*/
  6709. /* DOC
  6710. `oninput` tests if the browser is able to detect the input event
  6711. */
  6712. Modernizr.addTest('oninput', function() {
  6713. var input = createElement('input');
  6714. var supportsOnInput;
  6715. input.setAttribute('oninput', 'return');
  6716. if (hasEvent('oninput', docElement) || typeof input.oninput === 'function') {
  6717. return true;
  6718. }
  6719. // IE doesn't support onInput, so we wrap up the non IE APIs
  6720. // (createEvent, addEventListener) in a try catch, rather than test for
  6721. // their trident equivalent.
  6722. try {
  6723. // Older Firefox didn't map oninput attribute to oninput property
  6724. var testEvent = document.createEvent('KeyboardEvent');
  6725. supportsOnInput = false;
  6726. var handler = function(e) {
  6727. supportsOnInput = true;
  6728. e.preventDefault();
  6729. e.stopPropagation();
  6730. };
  6731. testEvent.initKeyEvent('keypress', true, true, window, false, false, false, false, 0, 'e'.charCodeAt(0));
  6732. docElement.appendChild(input);
  6733. input.addEventListener('input', handler, false);
  6734. input.focus();
  6735. input.dispatchEvent(testEvent);
  6736. input.removeEventListener('input', handler, false);
  6737. docElement.removeChild(input);
  6738. } catch (e) {
  6739. supportsOnInput = false;
  6740. }
  6741. return supportsOnInput;
  6742. });
  6743. /*!
  6744. {
  6745. "name": "File API",
  6746. "property": "filereader",
  6747. "caniuse": "fileapi",
  6748. "notes": [{
  6749. "name": "W3C Working Draft Spec",
  6750. "href": "https://www.w3.org/TR/FileAPI/"
  6751. }],
  6752. "tags": ["file"],
  6753. "builderAliases": ["file_api"],
  6754. "knownBugs": ["Will fail in Safari 5 due to its lack of support for the standards defined FileReader object"]
  6755. }
  6756. !*/
  6757. /* DOC
  6758. `filereader` tests for the File API specification
  6759. Tests for objects specific to the File API W3C specification without
  6760. being redundant (don't bother testing for Blob since it is assumed
  6761. to be the File object's prototype.)
  6762. */
  6763. Modernizr.addTest('filereader', !!(window.File && window.FileList && window.FileReader));
  6764. /*!
  6765. {
  6766. "name": "Filesystem API",
  6767. "property": "filesystem",
  6768. "caniuse": "filesystem",
  6769. "notes": [{
  6770. "name": "W3C Spec",
  6771. "href": "https://www.w3.org/TR/file-system-api/"
  6772. }],
  6773. "authors": ["Eric Bidelman (@ebidel)"],
  6774. "tags": ["file"],
  6775. "builderAliases": ["file_filesystem"],
  6776. "knownBugs": ["The API will be present in Chrome incognito, but will throw an exception. See crbug.com/93417"]
  6777. }
  6778. !*/
  6779. Modernizr.addTest('filesystem', !!prefixed('requestFileSystem', window));
  6780. /*!
  6781. {
  6782. "name": "input[capture] Attribute",
  6783. "property": "capture",
  6784. "tags": ["video", "image", "audio", "media", "attribute"],
  6785. "notes": [{
  6786. "name": "W3C Draft Spec",
  6787. "href": "https://www.w3.org/TR/html-media-capture/"
  6788. }]
  6789. }
  6790. !*/
  6791. /* DOC
  6792. When used on an `<input>`, this attribute signifies that the resource it takes should be generated via device's camera, camcorder, sound recorder.
  6793. */
  6794. // testing for capture attribute in inputs
  6795. Modernizr.addTest('capture', ('capture' in createElement('input')));
  6796. /*!
  6797. {
  6798. "name": "input[file] Attribute",
  6799. "property": "fileinput",
  6800. "caniuse": "forms",
  6801. "tags": ["file", "forms", "input"],
  6802. "builderAliases": ["forms_fileinput"]
  6803. }
  6804. !*/
  6805. /* DOC
  6806. Detects whether input type="file" is available on the platform
  6807. E.g. iOS < 6, some android versions and embedded Chrome WebViews don't support this
  6808. */
  6809. Modernizr.addTest('fileinput', function() {
  6810. var ua = navigator.userAgent;
  6811. if (ua.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/) ||
  6812. ua.match(/\swv\).+(chrome)\/([\w\.]+)/i)) {
  6813. return false;
  6814. }
  6815. var elem = createElement('input');
  6816. elem.type = 'file';
  6817. return !elem.disabled;
  6818. });
  6819. /*!
  6820. {
  6821. "name": "input[directory] Attribute",
  6822. "property": "directory",
  6823. "authors": ["silverwind"],
  6824. "tags": ["file", "input", "attribute"]
  6825. }
  6826. !*/
  6827. /* DOC
  6828. When used on an `<input type="file">`, the `directory` attribute instructs
  6829. the user agent to present a directory selection dialog instead of the usual
  6830. file selection dialog.
  6831. */
  6832. Modernizr.addTest('fileinputdirectory', function() {
  6833. var elem = createElement('input'), dir = 'directory';
  6834. elem.type = 'file';
  6835. if (dir in elem) {
  6836. return true;
  6837. } else {
  6838. for (var i = 0, len = domPrefixes.length; i < len; i++) {
  6839. if (domPrefixes[i] + dir in elem) {
  6840. return true;
  6841. }
  6842. }
  6843. }
  6844. return false;
  6845. });
  6846. /*!
  6847. {
  6848. "name": "input[form] Attribute",
  6849. "property": "formattribute",
  6850. "tags": ["attribute", "forms", "input"],
  6851. "builderAliases": ["forms_formattribute"]
  6852. }
  6853. !*/
  6854. /* DOC
  6855. Detects whether input form="form_id" is available on the platform
  6856. E.g. IE 10 (and below), don't support this
  6857. */
  6858. Modernizr.addTest('formattribute', function() {
  6859. var form = createElement('form');
  6860. var input = createElement('input');
  6861. var div = createElement('div');
  6862. var id = 'formtest' + (new Date()).getTime();
  6863. var attr;
  6864. var bool = false;
  6865. form.id = id;
  6866. //IE6/7 confuses the form idl attribute and the form content attribute, so we use document.createAttribute
  6867. try {
  6868. input.setAttribute('form', id);
  6869. }
  6870. catch (e) {
  6871. if (document.createAttribute) {
  6872. attr = document.createAttribute('form');
  6873. attr.nodeValue = id;
  6874. input.setAttributeNode(attr);
  6875. }
  6876. }
  6877. div.appendChild(form);
  6878. div.appendChild(input);
  6879. docElement.appendChild(div);
  6880. bool = form.elements && form.elements.length === 1 && input.form === form;
  6881. div.parentNode.removeChild(div);
  6882. return bool;
  6883. });
  6884. /*!
  6885. {
  6886. "name": "Form Validation",
  6887. "property": "formvalidation",
  6888. "tags": ["forms", "validation", "attribute"],
  6889. "builderAliases": ["forms_validation"]
  6890. }
  6891. !*/
  6892. /* DOC
  6893. This implementation only tests support for interactive form validation.
  6894. To check validation for a specific type or a specific other constraint,
  6895. the test can be combined:
  6896. - `Modernizr.inputtypes.number && Modernizr.formvalidation` (browser supports rangeOverflow, typeMismatch etc. for type=number)
  6897. - `Modernizr.input.required && Modernizr.formvalidation` (browser supports valueMissing)
  6898. */
  6899. Modernizr.addTest('formvalidation', function() {
  6900. var form = createElement('form');
  6901. if (!('checkValidity' in form) || !('addEventListener' in form)) {
  6902. return false;
  6903. }
  6904. if ('reportValidity' in form) {
  6905. return true;
  6906. }
  6907. var invalidFired = false;
  6908. var input;
  6909. Modernizr.formvalidationapi = true;
  6910. // Prevent form from being submitted
  6911. form.addEventListener('submit', function(e) {
  6912. // Old Presto based Opera does not validate form, if submit is prevented
  6913. // although Opera Mini servers use newer Presto.
  6914. if (!window.opera || window.operamini) {
  6915. e.preventDefault();
  6916. }
  6917. e.stopPropagation();
  6918. }, false);
  6919. // Calling form.submit() doesn't trigger interactive validation,
  6920. // use a submit button instead
  6921. //older opera browsers need a name attribute
  6922. form.innerHTML = '<input name="modTest" required="required" /><button></button>';
  6923. testStyles('#modernizr form{position:absolute;top:-99999em}', function(node) {
  6924. node.appendChild(form);
  6925. input = form.getElementsByTagName('input')[0];
  6926. // Record whether "invalid" event is fired
  6927. input.addEventListener('invalid', function(e) {
  6928. invalidFired = true;
  6929. e.preventDefault();
  6930. e.stopPropagation();
  6931. }, false);
  6932. //Opera does not fully support the validationMessage property
  6933. Modernizr.formvalidationmessage = !!input.validationMessage;
  6934. // Submit form by clicking submit button
  6935. form.getElementsByTagName('button')[0].click();
  6936. });
  6937. return invalidFired;
  6938. });
  6939. /*!
  6940. {
  6941. "name": "input[type=\"number\"] Localization",
  6942. "property": "localizednumber",
  6943. "tags": ["forms", "localization", "attribute"],
  6944. "authors": ["Peter Janes"],
  6945. "notes": [{
  6946. "name": "Webkit Bug Tracker Listing",
  6947. "href": "https://bugs.webkit.org/show_bug.cgi?id=42484"
  6948. },{
  6949. "name": "Based on This",
  6950. "href": "https://trac.webkit.org/browser/trunk/LayoutTests/fast/forms/script-tests/input-number-keyoperation.js?rev=80096#L9"
  6951. }],
  6952. "knownBugs": ["Only ever returns true if the browser/OS is configured to use comma as a decimal separator. This is probably fine for most use cases."]
  6953. }
  6954. !*/
  6955. /* DOC
  6956. Detects whether input type="number" is capable of receiving and displaying localized numbers, e.g. with comma separator.
  6957. */
  6958. Modernizr.addTest('localizednumber', function() {
  6959. /* this extends our testing of input[type=number], so bomb out if that's missing */
  6960. if (!Modernizr.inputtypes.number) { return false; }
  6961. /* we rely on checkValidity later, so bomb out early if we don't have it */
  6962. if (!Modernizr.formvalidation) { return false; }
  6963. var body = getBody();
  6964. var div = createElement('div');
  6965. var firstChild = body.firstElementChild || body.firstChild;
  6966. var result;
  6967. body.insertBefore(div, firstChild);
  6968. div.innerHTML = '<input type="number" value="1.0" step="0.1"/>';
  6969. var input = div.childNodes[0];
  6970. body.appendChild(div);
  6971. input.focus();
  6972. try {
  6973. document.execCommand('SelectAll', false); // Overwrite current input value, rather than appending text
  6974. document.execCommand('InsertText', false, '1,1');
  6975. } catch (e) {} // prevent warnings in IE
  6976. /* results */
  6977. result = input.type === 'number' && input.valueAsNumber === 1.1 && input.checkValidity();
  6978. /* cleanup */
  6979. body.removeChild(div);
  6980. if (body.fake) {
  6981. body.parentNode.removeChild(body);
  6982. }
  6983. return result;
  6984. });
  6985. /*!
  6986. {
  6987. "name": "placeholder attribute",
  6988. "property": "placeholder",
  6989. "tags": ["forms", "attribute"],
  6990. "builderAliases": ["forms_placeholder"]
  6991. }
  6992. !*/
  6993. /* DOC
  6994. Tests for placeholder attribute in inputs and textareas
  6995. */
  6996. Modernizr.addTest('placeholder', ('placeholder' in createElement('input') && 'placeholder' in createElement('textarea')));
  6997. /*!
  6998. {
  6999. "name": "form#requestAutocomplete()",
  7000. "property": "requestautocomplete",
  7001. "tags": ["form", "forms", "requestAutocomplete", "payments"],
  7002. "notes": [{
  7003. "name": "WHATWG Spec",
  7004. "href": "https://wiki.whatwg.org/wiki/RequestAutocomplete"
  7005. }]
  7006. }
  7007. !*/
  7008. /* DOC
  7009. When used with input[autocomplete] to annotate a form, form.requestAutocomplete() shows a dialog in Chrome that speeds up
  7010. checkout flows (payments specific for now).
  7011. */
  7012. Modernizr.addTest('requestautocomplete', !!prefixed('requestAutocomplete', createElement('form')));
  7013. /*!
  7014. {
  7015. "name": "iframe[sandbox] Attribute",
  7016. "property": "sandbox",
  7017. "tags": ["iframe"],
  7018. "builderAliases": ["iframe_sandbox"],
  7019. "notes": [
  7020. {
  7021. "name": "WHATWG Spec",
  7022. "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox"
  7023. }],
  7024. "knownBugs": ["False-positive on Firefox < 29"]
  7025. }
  7026. !*/
  7027. /* DOC
  7028. Test for `sandbox` attribute in iframes.
  7029. */
  7030. Modernizr.addTest('sandbox', 'sandbox' in createElement('iframe'));
  7031. /*!
  7032. {
  7033. "name": "iframe[seamless] Attribute",
  7034. "property": "seamless",
  7035. "tags": ["iframe"],
  7036. "builderAliases": ["iframe_seamless"],
  7037. "notes": [{
  7038. "name": "WHATWG Spec",
  7039. "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-seamless"
  7040. }]
  7041. }
  7042. !*/
  7043. /* DOC
  7044. Test for `seamless` attribute in iframes.
  7045. */
  7046. Modernizr.addTest('seamless', 'seamless' in createElement('iframe'));
  7047. /*!
  7048. {
  7049. "name": "iframe[srcdoc] Attribute",
  7050. "property": "srcdoc",
  7051. "tags": ["iframe"],
  7052. "builderAliases": ["iframe_srcdoc"],
  7053. "notes": [{
  7054. "name": "WHATWG Spec",
  7055. "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-srcdoc"
  7056. }]
  7057. }
  7058. !*/
  7059. /* DOC
  7060. Test for `srcdoc` attribute in iframes.
  7061. */
  7062. Modernizr.addTest('srcdoc', 'srcdoc' in createElement('iframe'));
  7063. /*!
  7064. {
  7065. "name": "Animated PNG",
  7066. "async": true,
  7067. "property": "apng",
  7068. "tags": ["image"],
  7069. "builderAliases": ["img_apng"],
  7070. "notes": [{
  7071. "name": "Wikipedia Article",
  7072. "href": "https://en.wikipedia.org/wiki/APNG"
  7073. }]
  7074. }
  7075. !*/
  7076. /* DOC
  7077. Test for animated png support.
  7078. */
  7079. Modernizr.addAsyncTest(function() {
  7080. if (!Modernizr.canvas) {
  7081. return false;
  7082. }
  7083. var image = new Image();
  7084. var canvas = createElement('canvas');
  7085. var ctx = canvas.getContext('2d');
  7086. image.onload = function() {
  7087. addTest('apng', function() {
  7088. if (typeof canvas.getContext === 'undefined') {
  7089. return false;
  7090. }
  7091. else {
  7092. ctx.drawImage(image, 0, 0);
  7093. return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
  7094. }
  7095. });
  7096. };
  7097. image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==';
  7098. });
  7099. /*!
  7100. {
  7101. "name": "Image crossOrigin",
  7102. "property": "imgcrossorigin",
  7103. "notes": [{
  7104. "name": "Cross Domain Images and the Tainted Canvas",
  7105. "href": "https://blog.codepen.io/2013/10/08/cross-domain-images-tainted-canvas/"
  7106. }]
  7107. }
  7108. !*/
  7109. /* DOC
  7110. Detects support for the crossOrigin attribute on images, which allow for cross domain images inside of a canvas without tainting it
  7111. */
  7112. Modernizr.addTest('imgcrossorigin', 'crossOrigin' in createElement('img'));
  7113. /*!
  7114. {
  7115. "name": "JPEG 2000",
  7116. "async": true,
  7117. "aliases": ["jpeg-2000", "jpg2"],
  7118. "property": "jpeg2000",
  7119. "tags": ["image"],
  7120. "authors": ["@eric_wvgg"],
  7121. "notes": [{
  7122. "name": "Wikipedia Article",
  7123. "href": "https://en.wikipedia.org/wiki/JPEG_2000"
  7124. }]
  7125. }
  7126. !*/
  7127. /* DOC
  7128. Test for JPEG 2000 support
  7129. */
  7130. Modernizr.addAsyncTest(function() {
  7131. var image = new Image();
  7132. image.onload = image.onerror = function() {
  7133. addTest('jpeg2000', image.width === 1);
  7134. };
  7135. image.src = 'data:image/jp2;base64,/0//UQAyAAAAAAABAAAAAgAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAEBwEBBwEBBwEBBwEB/1IADAAAAAEAAAQEAAH/XAAEQED/ZAAlAAFDcmVhdGVkIGJ5IE9wZW5KUEVHIHZlcnNpb24gMi4wLjD/kAAKAAAAAABYAAH/UwAJAQAABAQAAf9dAAUBQED/UwAJAgAABAQAAf9dAAUCQED/UwAJAwAABAQAAf9dAAUDQED/k8+kEAGvz6QQAa/PpBABr994EAk//9k=';
  7136. });
  7137. /*!
  7138. {
  7139. "name": "JPEG XR (extended range)",
  7140. "async": true,
  7141. "aliases": ["jpeg-xr"],
  7142. "property": "jpegxr",
  7143. "tags": ["image"],
  7144. "notes": [{
  7145. "name": "Wikipedia Article",
  7146. "href": "https://en.wikipedia.org/wiki/JPEG_XR"
  7147. }]
  7148. }
  7149. !*/
  7150. /* DOC
  7151. Test for JPEG XR support
  7152. */
  7153. Modernizr.addAsyncTest(function() {
  7154. var image = new Image();
  7155. image.onload = image.onerror = function() {
  7156. addTest('jpegxr', image.width === 1, {aliases: ['jpeg-xr']});
  7157. };
  7158. image.src = 'data:image/vnd.ms-photo;base64,SUm8AQgAAAAFAAG8AQAQAAAASgAAAIC8BAABAAAAAQAAAIG8BAABAAAAAQAAAMC8BAABAAAAWgAAAMG8BAABAAAAHwAAAAAAAAAkw91vA07+S7GFPXd2jckNV01QSE9UTwAZAYBxAAAAABP/gAAEb/8AAQAAAQAAAA==';
  7159. });
  7160. /*!
  7161. {
  7162. "name": "sizes attribute",
  7163. "async": true,
  7164. "property": "sizes",
  7165. "tags": ["image"],
  7166. "authors": ["Mat Marquis"],
  7167. "notes": [{
  7168. "name": "WHATWG Spec",
  7169. "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element"
  7170. },{
  7171. "name": "Srcset and sizes",
  7172. "href": "https://ericportis.com/posts/2014/srcset-sizes/"
  7173. }]
  7174. }
  7175. !*/
  7176. /* DOC
  7177. Test for the `sizes` attribute on images
  7178. */
  7179. Modernizr.addAsyncTest(function() {
  7180. var width1, width2, test;
  7181. var image = createElement('img');
  7182. // in a perfect world this would be the test...
  7183. var isSizes = 'sizes' in image;
  7184. // ... but we need to deal with Safari 9...
  7185. if (!isSizes && ('srcset' in image)) {
  7186. width2 = 'data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw==';
  7187. width1 = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
  7188. test = function() {
  7189. addTest('sizes', image.width === 2);
  7190. };
  7191. image.onload = test;
  7192. image.onerror = test;
  7193. image.setAttribute('sizes', '9px');
  7194. image.srcset = width1 + ' 1w,' + width2 + ' 8w';
  7195. image.src = width1;
  7196. } else {
  7197. addTest('sizes', isSizes);
  7198. }
  7199. });
  7200. /*!
  7201. {
  7202. "name": "srcset attribute",
  7203. "property": "srcset",
  7204. "caniuse": "srcset",
  7205. "tags": ["image"],
  7206. "notes": [{
  7207. "name": "Smashing Magazine Article",
  7208. "href": "https://www.smashingmagazine.com/2013/08/webkit-implements-srcset-and-why-its-a-good-thing/"
  7209. },{
  7210. "name": "Generate multi-resolution images for srcset with Grunt",
  7211. "href": "https://addyosmani.com/blog/generate-multi-resolution-images-for-srcset-with-grunt/"
  7212. }]
  7213. }
  7214. !*/
  7215. /* DOC
  7216. Test for the srcset attribute of images
  7217. */
  7218. Modernizr.addTest('srcset', 'srcset' in createElement('img'));
  7219. /*!
  7220. {
  7221. "name": "Webp Alpha",
  7222. "async": true,
  7223. "property": "webpalpha",
  7224. "aliases": ["webp-alpha"],
  7225. "tags": ["image"],
  7226. "authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
  7227. "notes": [{
  7228. "name": "WebP Info",
  7229. "href": "https://developers.google.com/speed/webp/"
  7230. },{
  7231. "name": "Article about WebP support",
  7232. "href": "https://optimus.keycdn.com/support/webp-support/"
  7233. },{
  7234. "name": "Chromium WebP announcement",
  7235. "href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
  7236. }]
  7237. }
  7238. !*/
  7239. /* DOC
  7240. Tests for transparent webp support.
  7241. */
  7242. Modernizr.addAsyncTest(function() {
  7243. var image = new Image();
  7244. image.onerror = function() {
  7245. addTest('webpalpha', false, {aliases: ['webp-alpha']});
  7246. };
  7247. image.onload = function() {
  7248. addTest('webpalpha', image.width === 1, {aliases: ['webp-alpha']});
  7249. };
  7250. image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==';
  7251. });
  7252. /*!
  7253. {
  7254. "name": "Webp Animation",
  7255. "async": true,
  7256. "property": "webpanimation",
  7257. "aliases": ["webp-animation"],
  7258. "tags": ["image"],
  7259. "authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
  7260. "notes": [{
  7261. "name": "WebP Info",
  7262. "href": "https://developers.google.com/speed/webp/"
  7263. },{
  7264. "name": "Chromium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
  7265. "href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
  7266. }]
  7267. }
  7268. !*/
  7269. /* DOC
  7270. Tests for animated webp support.
  7271. */
  7272. Modernizr.addAsyncTest(function() {
  7273. var image = new Image();
  7274. image.onerror = function() {
  7275. addTest('webpanimation', false, {aliases: ['webp-animation']});
  7276. };
  7277. image.onload = function() {
  7278. addTest('webpanimation', image.width === 1, {aliases: ['webp-animation']});
  7279. };
  7280. image.src = 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA';
  7281. });
  7282. /*!
  7283. {
  7284. "name": "Webp Lossless",
  7285. "async": true,
  7286. "property": ["webplossless", "webp-lossless"],
  7287. "tags": ["image"],
  7288. "authors": ["@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
  7289. "notes": [{
  7290. "name": "Webp Info",
  7291. "href": "https://developers.google.com/speed/webp/"
  7292. },{
  7293. "name": "Webp Lossless Spec",
  7294. "href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
  7295. }]
  7296. }
  7297. !*/
  7298. /* DOC
  7299. Tests for non-alpha lossless webp support.
  7300. */
  7301. Modernizr.addAsyncTest(function() {
  7302. var image = new Image();
  7303. image.onerror = function() {
  7304. addTest('webplossless', false, {aliases: ['webp-lossless']});
  7305. };
  7306. image.onload = function() {
  7307. addTest('webplossless', image.width === 1, {aliases: ['webp-lossless']});
  7308. };
  7309. image.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
  7310. });
  7311. /*!
  7312. {
  7313. "name": "Webp",
  7314. "async": true,
  7315. "property": "webp",
  7316. "tags": ["image"],
  7317. "builderAliases": ["img_webp"],
  7318. "authors": ["Krister Kari", "@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
  7319. "notes": [{
  7320. "name": "Webp Info",
  7321. "href": "https://developers.google.com/speed/webp/"
  7322. }, {
  7323. "name": "Chromium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
  7324. "href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
  7325. }, {
  7326. "name": "Webp Lossless Spec",
  7327. "href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
  7328. }, {
  7329. "name": "Article about WebP support",
  7330. "href": "https://optimus.keycdn.com/support/webp-support/"
  7331. }, {
  7332. "name": "Chromium WebP announcement",
  7333. "href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
  7334. }]
  7335. }
  7336. !*/
  7337. /* DOC
  7338. Tests for lossy, non-alpha webp support.
  7339. Tests for all forms of webp support (lossless, lossy, alpha, and animated)..
  7340. Modernizr.webp // Basic support (lossy)
  7341. Modernizr.webp.lossless // Lossless
  7342. Modernizr.webp.alpha // Alpha (both lossy and lossless)
  7343. Modernizr.webp.animation // Animated WebP
  7344. */
  7345. Modernizr.addAsyncTest(function() {
  7346. var webpTests = [{
  7347. 'uri': 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=',
  7348. 'name': 'webp'
  7349. }, {
  7350. 'uri': 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==',
  7351. 'name': 'webp.alpha'
  7352. }, {
  7353. 'uri': 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA',
  7354. 'name': 'webp.animation'
  7355. }, {
  7356. 'uri': 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=',
  7357. 'name': 'webp.lossless'
  7358. }];
  7359. var webp = webpTests.shift();
  7360. function test(name, uri, cb) {
  7361. var image = new Image();
  7362. function addResult(event) {
  7363. // if the event is from 'onload', check the see if the image's width is
  7364. // 1 pixel (which indicates support). otherwise, it fails
  7365. var result = event && event.type === 'load' ? image.width === 1 : false;
  7366. var baseTest = name === 'webp';
  7367. // if it is the base test, and the result is false, just set a literal false
  7368. // rather than use the Boolean constructor
  7369. addTest(name, (baseTest && result) ? new Boolean(result) : result);
  7370. if (cb) {
  7371. cb(event);
  7372. }
  7373. }
  7374. image.onerror = addResult;
  7375. image.onload = addResult;
  7376. image.src = uri;
  7377. }
  7378. // test for webp support in general
  7379. test(webp.name, webp.uri, function(e) {
  7380. // if the webp test loaded, test everything else.
  7381. if (e && e.type === 'load') {
  7382. for (var i = 0; i < webpTests.length; i++) {
  7383. test(webpTests[i].name, webpTests[i].uri);
  7384. }
  7385. }
  7386. });
  7387. });
  7388. /*!
  7389. {
  7390. "name": "input formaction",
  7391. "property": "inputformaction",
  7392. "aliases": ["input-formaction"],
  7393. "notes": [{
  7394. "name": "WHATWG Spec",
  7395. "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formaction"
  7396. }, {
  7397. "name": "Wufoo demo",
  7398. "href": "https://www.wufoo.com/html5/formaction-attribute/"
  7399. }],
  7400. "polyfills": ["webshims"]
  7401. }
  7402. !*/
  7403. /* DOC
  7404. Detect support for the formaction attribute on form inputs
  7405. */
  7406. Modernizr.addTest('inputformaction', !!('formAction' in createElement('input')), {aliases: ['input-formaction']});
  7407. /*!
  7408. {
  7409. "name": "input formenctype",
  7410. "property": "inputformenctype",
  7411. "aliases": ["input-formenctype"],
  7412. "notes": [{
  7413. "name": "WHATWG Spec",
  7414. "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formenctype"
  7415. }, {
  7416. "name": "Wufoo demo",
  7417. "href": "https://www.wufoo.com/html5/formenctype-attribute/"
  7418. }],
  7419. "polyfills": ["html5formshim"]
  7420. }
  7421. !*/
  7422. /* DOC
  7423. Detect support for the formenctype attribute on form inputs, which overrides the form enctype attribute
  7424. */
  7425. Modernizr.addTest('inputformenctype', !!('formEnctype' in createElement('input')), {aliases: ['input-formenctype']});
  7426. /*!
  7427. {
  7428. "name": "input formmethod",
  7429. "property": "inputformmethod",
  7430. "notes": [{
  7431. "name": "WHATWG Spec",
  7432. "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formmethod"
  7433. }, {
  7434. "name": "Wufoo demo",
  7435. "href": "https://www.wufoo.com/html5/formmethod-attribute/"
  7436. }],
  7437. "polyfills": ["webshims"]
  7438. }
  7439. !*/
  7440. /* DOC
  7441. Detect support for the formmethod attribute on form inputs
  7442. */
  7443. Modernizr.addTest('inputformmethod', !!('formMethod' in createElement('input')));
  7444. /*!
  7445. {
  7446. "name": "input formnovalidate",
  7447. "property": "inputformnovalidate",
  7448. "aliases": ["input-formnovalidate"],
  7449. "notes": [{
  7450. "name": "WHATWG Spec",
  7451. "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formnovalidate"
  7452. }, {
  7453. "name": "Wufoo demo",
  7454. "href": "https://www.wufoo.com/html5/formnovalidate-attribute/"
  7455. }],
  7456. "polyfills": ["html5formshim"]
  7457. }
  7458. !*/
  7459. /* DOC
  7460. Detect support for the formnovalidate attribute on form inputs, which overrides the form novalidate attribute
  7461. */
  7462. Modernizr.addTest('inputformnovalidate', !!('formNoValidate' in createElement('input')), {aliases: ['input-formnovalidate']});
  7463. /*!
  7464. {
  7465. "name": "input formtarget",
  7466. "property": "inputformtarget",
  7467. "aliases": ["input-formtarget"],
  7468. "notes": [{
  7469. "name": "WHATWG Spec",
  7470. "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formtarget"
  7471. }, {
  7472. "name": "Wufoo demo",
  7473. "href": "https://www.wufoo.com/html5/formtarget-attribute/"
  7474. }],
  7475. "polyfills": ["html5formshim"]
  7476. }
  7477. !*/
  7478. /* DOC
  7479. Detect support for the formtarget attribute on form inputs, which overrides the form target attribute
  7480. */
  7481. Modernizr.addTest('inputformtarget', !!('formTarget' in createElement('input')), {aliases: ['input-formtarget']});
  7482. /*!
  7483. {
  7484. "name": "Hover Media Query",
  7485. "property": "hovermq"
  7486. }
  7487. !*/
  7488. /* DOC
  7489. Detect support for Hover based media queries
  7490. */
  7491. Modernizr.addTest('hovermq', mq('(hover)'));
  7492. /*!
  7493. {
  7494. "name": "Pointer Media Query",
  7495. "property": "pointermq"
  7496. }
  7497. !*/
  7498. /* DOC
  7499. Detect support for Pointer based media queries
  7500. */
  7501. Modernizr.addTest('pointermq', mq(('(pointer:coarse),(pointer:fine),(pointer:none)')));
  7502. /*!
  7503. {
  7504. "name": "Beacon API",
  7505. "notes": [{
  7506. "name": "MDN Docs",
  7507. "href": "https://developer.mozilla.org/en-US/docs/Web/API/navigator.sendBeacon"
  7508. },{
  7509. "name": "W3C Spec",
  7510. "href": "https://w3c.github.io/beacon/"
  7511. }],
  7512. "property": "beacon",
  7513. "tags": ["beacon", "network"],
  7514. "authors": ["Cătălin Mariș"]
  7515. }
  7516. !*/
  7517. /* DOC
  7518. Detects support for an API that allows for asynchronous transfer of small HTTP data from the client to a server.
  7519. */
  7520. Modernizr.addTest('beacon', 'sendBeacon' in navigator);
  7521. /*!
  7522. {
  7523. "name": "Connection Effective Type",
  7524. "notes": [{
  7525. "name": "MDN documentation",
  7526. "href": "https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType"
  7527. }],
  7528. "property": "connectioneffectivetype",
  7529. "builderAliases": ["network_connection"],
  7530. "tags": ["network"]
  7531. }
  7532. !*/
  7533. /* DOC
  7534. Detects support for determining signal bandwidth via `navigator.connection.effectiveType`
  7535. */
  7536. Modernizr.addTest('effectiveType', function () {
  7537. // polyfill
  7538. var connection = navigator.connection || { effectiveType: 0 };
  7539. if (connection.effectiveType !== 0) {
  7540. return true;
  7541. }
  7542. return false;
  7543. });
  7544. /*!
  7545. {
  7546. "name": "Low Bandwidth Connection",
  7547. "property": "lowbandwidth",
  7548. "tags": ["network"],
  7549. "builderAliases": ["network_connection"]
  7550. }
  7551. !*/
  7552. /* DOC
  7553. Tests for determining low-bandwidth via `navigator.connection`
  7554. There are two iterations of the `navigator.connection` interface.
  7555. The first is present in Android 2.2+ and only in the Browser (not WebView)
  7556. - http://docs.phonegap.com/en/1.2.0/phonegap_connection_connection.md.html#connection.type
  7557. - https://davidbcalhoun.com/2010/using-navigator-connection-android
  7558. The second is speced at https://dvcs.w3.org/hg/dap/raw-file/tip/network-api/Overview.html and perhaps landing in WebKit
  7559. - https://bugs.webkit.org/show_bug.cgi?id=73528
  7560. Unknown devices are assumed as fast
  7561. For more rigorous network testing, consider boomerang.js: https://github.com/bluesmoon/boomerang/
  7562. */
  7563. Modernizr.addTest('lowbandwidth', function() {
  7564. // polyfill
  7565. var connection = navigator.connection || {type: 0};
  7566. return connection.type === 3 || // connection.CELL_2G
  7567. connection.type === 4 || // connection.CELL_3G
  7568. /^[23]g$/.test(connection.type); // string value in new spec
  7569. });
  7570. /*!
  7571. {
  7572. "name": "Server Sent Events",
  7573. "property": "eventsource",
  7574. "tags": ["network"],
  7575. "builderAliases": ["network_eventsource"],
  7576. "notes": [{
  7577. "name": "WHATWG Spec",
  7578. "href": "https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events"
  7579. }]
  7580. }
  7581. !*/
  7582. /* DOC
  7583. Tests for server sent events aka eventsource.
  7584. */
  7585. Modernizr.addTest('eventsource', 'EventSource' in window);
  7586. /*!
  7587. {
  7588. "name": "Fetch API",
  7589. "property": "fetch",
  7590. "tags": ["network"],
  7591. "caniuse": "fetch",
  7592. "notes": [{
  7593. "name": "WHATWG Spec",
  7594. "href": "https://fetch.spec.whatwg.org/"
  7595. }],
  7596. "polyfills": ["fetch"]
  7597. }
  7598. !*/
  7599. /* DOC
  7600. Detects support for the fetch API, a modern replacement for XMLHttpRequest.
  7601. */
  7602. Modernizr.addTest('fetch', 'fetch' in window);
  7603. /**
  7604. * https://mathiasbynens.be/notes/xhr-responsetype-json#comment-4
  7605. *
  7606. * @author Mathias Bynens
  7607. * @access private
  7608. * @function testXhrType
  7609. * @param {string} type - String name of the XHR type you want to detect
  7610. * @returns {boolean} true if the responseType is of the specified type
  7611. */
  7612. var testXhrType = function(type) {
  7613. if (typeof XMLHttpRequest === 'undefined') {
  7614. return false;
  7615. }
  7616. var xhr = new XMLHttpRequest();
  7617. xhr.open('get', '/', true);
  7618. try {
  7619. xhr.responseType = type;
  7620. } catch (error) {
  7621. return false;
  7622. }
  7623. return 'response' in xhr && xhr.responseType === type;
  7624. };
  7625. /*!
  7626. {
  7627. "name": "XHR responseType='arraybuffer'",
  7628. "property": "xhrresponsetypearraybuffer",
  7629. "tags": ["network"],
  7630. "notes": [{
  7631. "name": "WHATWG Spec",
  7632. "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
  7633. }]
  7634. }
  7635. !*/
  7636. /* DOC
  7637. Tests for XMLHttpRequest xhr.responseType='arraybuffer'.
  7638. */
  7639. Modernizr.addTest('xhrresponsetypearraybuffer', testXhrType('arraybuffer'));
  7640. /*!
  7641. {
  7642. "name": "XHR responseType='blob'",
  7643. "property": "xhrresponsetypeblob",
  7644. "tags": ["network"],
  7645. "notes": [{
  7646. "name": "WHATWG Spec",
  7647. "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
  7648. }]
  7649. }
  7650. !*/
  7651. /* DOC
  7652. Tests for XMLHttpRequest xhr.responseType='blob'.
  7653. */
  7654. Modernizr.addTest('xhrresponsetypeblob', testXhrType('blob'));
  7655. /*!
  7656. {
  7657. "name": "XHR responseType='document'",
  7658. "property": "xhrresponsetypedocument",
  7659. "tags": ["network"],
  7660. "notes": [{
  7661. "name": "WHATWG Spec",
  7662. "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
  7663. }]
  7664. }
  7665. !*/
  7666. /* DOC
  7667. Tests for XMLHttpRequest xhr.responseType='document'.
  7668. */
  7669. Modernizr.addTest('xhrresponsetypedocument', testXhrType('document'));
  7670. /*!
  7671. {
  7672. "name": "XHR responseType='json'",
  7673. "property": "xhrresponsetypejson",
  7674. "tags": ["network"],
  7675. "notes": [{
  7676. "name": "WHATWG Spec",
  7677. "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
  7678. },{
  7679. "name": "Explanation of xhr.responseType='json'",
  7680. "href": "https://mathiasbynens.be/notes/xhr-responsetype-json"
  7681. }]
  7682. }
  7683. !*/
  7684. /* DOC
  7685. Tests for XMLHttpRequest xhr.responseType='json'.
  7686. */
  7687. Modernizr.addTest('xhrresponsetypejson', testXhrType('json'));
  7688. /*!
  7689. {
  7690. "name": "XHR responseType='text'",
  7691. "property": "xhrresponsetypetext",
  7692. "tags": ["network"],
  7693. "notes": [{
  7694. "name": "WHATWG Spec",
  7695. "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
  7696. }]
  7697. }
  7698. !*/
  7699. /* DOC
  7700. Tests for XMLHttpRequest xhr.responseType='text'.
  7701. */
  7702. Modernizr.addTest('xhrresponsetypetext', testXhrType('text'));
  7703. /*!
  7704. {
  7705. "name": "XHR responseType",
  7706. "property": "xhrresponsetype",
  7707. "tags": ["network"],
  7708. "notes": [{
  7709. "name": "WHATWG Spec",
  7710. "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
  7711. }]
  7712. }
  7713. !*/
  7714. /* DOC
  7715. Tests for XMLHttpRequest xhr.responseType.
  7716. */
  7717. Modernizr.addTest('xhrresponsetype', (function() {
  7718. if (typeof XMLHttpRequest === 'undefined') {
  7719. return false;
  7720. }
  7721. var xhr = new XMLHttpRequest();
  7722. xhr.open('get', '/', true);
  7723. return 'response' in xhr;
  7724. }()));
  7725. /*!
  7726. {
  7727. "name": "XML HTTP Request Level 2 XHR2",
  7728. "property": "xhr2",
  7729. "tags": ["network"],
  7730. "builderAliases": ["network_xhr2"],
  7731. "notes": [{
  7732. "name": "W3C Spec",
  7733. "href": "https://www.w3.org/TR/XMLHttpRequest2/"
  7734. },{
  7735. "name": "Details on Related Github Issue",
  7736. "href": "https://github.com/Modernizr/Modernizr/issues/385"
  7737. }]
  7738. }
  7739. !*/
  7740. /* DOC
  7741. Tests for XHR2.
  7742. */
  7743. // all three of these details report consistently across all target browsers:
  7744. // !!(window.ProgressEvent);
  7745. // 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest
  7746. Modernizr.addTest('xhr2', 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest());
  7747. /*!
  7748. {
  7749. "name": "script[async]",
  7750. "property": "scriptasync",
  7751. "caniuse": "script-async",
  7752. "tags": ["script"],
  7753. "builderAliases": ["script_async"],
  7754. "authors": ["Theodoor van Donge"]
  7755. }
  7756. !*/
  7757. /* DOC
  7758. Detects support for the `async` attribute on the `<script>` element.
  7759. */
  7760. Modernizr.addTest('scriptasync', 'async' in createElement('script'));
  7761. /*!
  7762. {
  7763. "name": "script[defer]",
  7764. "property": "scriptdefer",
  7765. "caniuse": "script-defer",
  7766. "tags": ["script"],
  7767. "builderAliases": ["script_defer"],
  7768. "authors": ["Theodoor van Donge"],
  7769. "warnings": ["Browser implementation of the `defer` attribute vary: https://stackoverflow.com/questions/3952009/defer-attribute-chrome#answer-3982619"],
  7770. "knownBugs": ["False positive in Opera 12"]
  7771. }
  7772. !*/
  7773. /* DOC
  7774. Detects support for the `defer` attribute on the `<script>` element.
  7775. */
  7776. Modernizr.addTest('scriptdefer', 'defer' in createElement('script'));
  7777. /*!
  7778. {
  7779. "property": "speechrecognition",
  7780. "tags": ["input", "speech"],
  7781. "authors": ["Cătălin Mariș"],
  7782. "name": "Speech Recognition API",
  7783. "notes": [{
  7784. "name": "W3C Spec",
  7785. "href": "https://w3c.github.io/speech-api/speechapi.html#speechreco-section"
  7786. },{
  7787. "name": "Introduction to the Web Speech API",
  7788. "href": "https://developers.google.com/web/updates/2013/01/Voice-Driven-Web-Apps-Introduction-to-the-Web-Speech-API"
  7789. }]
  7790. }
  7791. !*/
  7792. Modernizr.addTest('speechrecognition', !!prefixed('SpeechRecognition', window));
  7793. /*!
  7794. {
  7795. "property": "speechsynthesis",
  7796. "tags": ["input", "speech"],
  7797. "authors": ["Cătălin Mariș"],
  7798. "name": "Speech Synthesis API",
  7799. "notes": [{
  7800. "name": "W3C Spec",
  7801. "href": "https://w3c.github.io/speech-api/speechapi.html#tts-section"
  7802. }]
  7803. }
  7804. !*/
  7805. Modernizr.addTest('speechsynthesis', 'SpeechSynthesisUtterance' in window);
  7806. /*!
  7807. {
  7808. "name": "Local Storage",
  7809. "property": "localstorage",
  7810. "caniuse": "namevalue-storage",
  7811. "tags": ["storage"],
  7812. "polyfills": [
  7813. "joshuabell-polyfill",
  7814. "cupcake",
  7815. "storagepolyfill",
  7816. "amplifyjs",
  7817. "yui-cacheoffline"
  7818. ]
  7819. }
  7820. !*/
  7821. // In FF4, if disabled, window.localStorage should === null.
  7822. // Normally, we could not test that directly and need to do a
  7823. // `('localStorage' in window)` test first because otherwise Firefox will
  7824. // throw bugzil.la/365772 if cookies are disabled
  7825. // Similarly, in Chrome with "Block third-party cookies and site data" enabled,
  7826. // attempting to access `window.sessionStorage` will throw an exception. crbug.com/357625
  7827. // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
  7828. // will throw the exception:
  7829. // QUOTA_EXCEEDED_ERROR DOM Exception 22.
  7830. // Peculiarly, getItem and removeItem calls do not throw.
  7831. // Because we are forced to try/catch this, we'll go aggressive.
  7832. // Just FWIW: IE8 Compat mode supports these features completely:
  7833. // www.quirksmode.org/dom/html5.html
  7834. // But IE8 doesn't support either with local files
  7835. Modernizr.addTest('localstorage', function() {
  7836. var mod = 'modernizr';
  7837. try {
  7838. localStorage.setItem(mod, mod);
  7839. localStorage.removeItem(mod);
  7840. return true;
  7841. } catch (e) {
  7842. return false;
  7843. }
  7844. });
  7845. /*!
  7846. {
  7847. "name": "Session Storage",
  7848. "property": "sessionstorage",
  7849. "tags": ["storage"],
  7850. "polyfills": ["joshuabell-polyfill", "cupcake", "sessionstorage"]
  7851. }
  7852. !*/
  7853. // Because we are forced to try/catch this, we'll go aggressive.
  7854. // Just FWIW: IE8 Compat mode supports these features completely:
  7855. // www.quirksmode.org/dom/html5.html
  7856. // But IE8 doesn't support either with local files
  7857. Modernizr.addTest('sessionstorage', function() {
  7858. var mod = 'modernizr';
  7859. try {
  7860. sessionStorage.setItem(mod, mod);
  7861. sessionStorage.removeItem(mod);
  7862. return true;
  7863. } catch (e) {
  7864. return false;
  7865. }
  7866. });
  7867. /*!
  7868. {
  7869. "name": "Web SQL Database",
  7870. "property": "websqldatabase",
  7871. "caniuse": "sql-storage",
  7872. "tags": ["storage"]
  7873. }
  7874. !*/
  7875. // Chrome incognito mode used to throw an exception when using openDatabase
  7876. // It doesn't anymore.
  7877. Modernizr.addTest('websqldatabase', 'openDatabase' in window);
  7878. /*!
  7879. {
  7880. "name": "style[scoped]",
  7881. "property": "stylescoped",
  7882. "caniuse": "style-scoped",
  7883. "tags": ["dom"],
  7884. "builderAliases": ["style_scoped"],
  7885. "authors": ["Cătălin Mariș"],
  7886. "notes": [{
  7887. "name": "WHATWG Spec",
  7888. "href": "https://html.spec.whatwg.org/multipage/semantics.html#attr-style-scoped"
  7889. }],
  7890. "polyfills": ["scoped-styles"]
  7891. }
  7892. !*/
  7893. /* DOC
  7894. Support for the `scoped` attribute of the `<style>` element.
  7895. */
  7896. Modernizr.addTest('stylescoped', 'scoped' in createElement('style'));
  7897. /*!
  7898. {
  7899. "name": "SVG as an <img> tag source",
  7900. "property": "svgasimg",
  7901. "caniuse": "svg-img",
  7902. "tags": ["svg"],
  7903. "aliases": ["svgincss"],
  7904. "authors": ["Chris Coyier"],
  7905. "notes": [{
  7906. "name": "HTML5 Spec",
  7907. "href": "https://www.w3.org/TR/html5/embedded-content-0.html#the-img-element"
  7908. }]
  7909. }
  7910. !*/
  7911. // Original Async test by Stu Cox
  7912. // https://gist.github.com/chriscoyier/8774501
  7913. // Now a Sync test based on good results here
  7914. // https://codepen.io/chriscoyier/pen/bADFx
  7915. // Note http://www.w3.org/TR/SVG11/feature#Image is *supposed* to represent
  7916. // support for the `<image>` tag in SVG, not an SVG file linked from an `<img>`
  7917. // tag in HTML – but it’s a heuristic which works
  7918. Modernizr.addTest('svgasimg', document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1'));
  7919. /**
  7920. * Object.prototype.toString can be used with every object and allows you to
  7921. * get its class easily. Abstracting it off of an object prevents situations
  7922. * where the toString property has been overridden
  7923. *
  7924. * @access private
  7925. * @function toStringFn
  7926. * @returns {function} An abstracted toString function
  7927. */
  7928. var toStringFn = ({}).toString;
  7929. /*!
  7930. {
  7931. "name": "SVG clip paths",
  7932. "property": "svgclippaths",
  7933. "tags": ["svg"],
  7934. "notes": [{
  7935. "name": "Demo",
  7936. "href": "http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg"
  7937. }]
  7938. }
  7939. !*/
  7940. /* DOC
  7941. Detects support for clip paths in SVG (only, not on HTML content).
  7942. See [this discussion](https://github.com/Modernizr/Modernizr/issues/213) regarding applying SVG clip paths to HTML content.
  7943. */
  7944. Modernizr.addTest('svgclippaths', function() {
  7945. return !!document.createElementNS &&
  7946. /SVGClipPath/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'clipPath')));
  7947. });
  7948. /*!
  7949. {
  7950. "name": "SVG filters",
  7951. "property": "svgfilters",
  7952. "caniuse": "svg-filters",
  7953. "tags": ["svg"],
  7954. "builderAliases": ["svg_filters"],
  7955. "authors": ["Erik Dahlstrom"],
  7956. "notes": [{
  7957. "name": "W3C Spec",
  7958. "href": "https://www.w3.org/TR/SVG11/filters.html"
  7959. }]
  7960. }
  7961. !*/
  7962. // Should fail in Safari: https://stackoverflow.com/questions/9739955/feature-detecting-support-for-svg-filters.
  7963. Modernizr.addTest('svgfilters', function() {
  7964. var result = false;
  7965. try {
  7966. result = 'SVGFEColorMatrixElement' in window &&
  7967. SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE === 2;
  7968. }
  7969. catch (e) {}
  7970. return result;
  7971. });
  7972. /*!
  7973. {
  7974. "name": "SVG foreignObject",
  7975. "property": "svgforeignobject",
  7976. "tags": ["svg"],
  7977. "notes": [{
  7978. "name": "W3C Spec",
  7979. "href": "https://www.w3.org/TR/SVG11/extend.html"
  7980. }]
  7981. }
  7982. !*/
  7983. /* DOC
  7984. Detects support for foreignObject tag in SVG.
  7985. */
  7986. Modernizr.addTest('svgforeignobject', function() {
  7987. return !!document.createElementNS &&
  7988. /SVGForeignObject/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')));
  7989. });
  7990. /*!
  7991. {
  7992. "name": "Inline SVG",
  7993. "property": "inlinesvg",
  7994. "caniuse": "svg-html5",
  7995. "tags": ["svg"],
  7996. "notes": [{
  7997. "name": "Test page",
  7998. "href": "https://paulirish.com/demo/inline-svg"
  7999. }, {
  8000. "name": "Test page and results",
  8001. "href": "https://codepen.io/eltonmesquita/full/GgXbvo/"
  8002. }],
  8003. "polyfills": ["inline-svg-polyfill"],
  8004. "knownBugs": ["False negative on some Chromia browsers."]
  8005. }
  8006. !*/
  8007. /* DOC
  8008. Detects support for inline SVG in HTML (not within XHTML).
  8009. */
  8010. Modernizr.addTest('inlinesvg', function() {
  8011. var div = createElement('div');
  8012. div.innerHTML = '<svg/>';
  8013. return (typeof SVGRect !== 'undefined' && div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg';
  8014. });
  8015. /*!
  8016. {
  8017. "name": "SVG SMIL animation",
  8018. "property": "smil",
  8019. "caniuse": "svg-smil",
  8020. "tags": ["svg"],
  8021. "notes": [{
  8022. "name": "W3C Spec",
  8023. "href": "https://www.w3.org/AudioVideo/"
  8024. }]
  8025. }
  8026. !*/
  8027. // SVG SMIL animation
  8028. Modernizr.addTest('smil', function() {
  8029. return !!document.createElementNS &&
  8030. /SVGAnimate/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'animate')));
  8031. });
  8032. /*!
  8033. {
  8034. "name": "textarea maxlength",
  8035. "property": "textareamaxlength",
  8036. "aliases": ["textarea-maxlength"],
  8037. "notes": [{
  8038. "name": "MDN Docs",
  8039. "href": "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea"
  8040. }],
  8041. "polyfills": ["maxlength"]
  8042. }
  8043. !*/
  8044. /* DOC
  8045. Detect support for the maxlength attribute of a textarea element
  8046. */
  8047. Modernizr.addTest('textareamaxlength', !!('maxLength' in createElement('textarea')));
  8048. /*!
  8049. {
  8050. "name": "Blob URLs",
  8051. "property": "bloburls",
  8052. "caniuse": "bloburls",
  8053. "notes": [{
  8054. "name": "W3C Working Draft Spec",
  8055. "href": "https://www.w3.org/TR/FileAPI/#creating-revoking"
  8056. }],
  8057. "tags": ["file", "url"],
  8058. "authors": ["Ron Waldon (@jokeyrhyme)"]
  8059. }
  8060. !*/
  8061. /* DOC
  8062. Detects support for creating Blob URLs
  8063. */
  8064. var url = prefixed('URL', window, false);
  8065. url = url && window[url];
  8066. Modernizr.addTest('bloburls', url && 'revokeObjectURL' in url && 'createObjectURL' in url);
  8067. /*!
  8068. {
  8069. "name": "Data URI",
  8070. "property": "datauri",
  8071. "caniuse": "datauri",
  8072. "tags": ["url"],
  8073. "builderAliases": ["url_data_uri"],
  8074. "async": true,
  8075. "notes": [{
  8076. "name": "Wikipedia article",
  8077. "href": "https://en.wikipedia.org/wiki/Data_URI_scheme"
  8078. }],
  8079. "warnings": ["Support in Internet Explorer 8 is limited to images and linked resources like CSS files, not HTML files"]
  8080. }
  8081. !*/
  8082. /* DOC
  8083. Detects support for data URIs. Provides a subproperty to report support for data URIs over 32kb in size:
  8084. ```javascript
  8085. Modernizr.datauri // true
  8086. Modernizr.datauri.over32kb // false in IE8
  8087. ```
  8088. */
  8089. // https://github.com/Modernizr/Modernizr/issues/14
  8090. Modernizr.addAsyncTest(function() {
  8091. // IE7 throw a mixed content warning on HTTPS for this test, so we'll
  8092. // just blacklist it (we know it doesn't support data URIs anyway)
  8093. // https://github.com/Modernizr/Modernizr/issues/362
  8094. if (navigator.userAgent.indexOf('MSIE 7.') !== -1) {
  8095. // Keep the test async
  8096. setTimeout(function() {
  8097. addTest('datauri', false);
  8098. }, 10);
  8099. }
  8100. var datauri = new Image();
  8101. datauri.onerror = function() {
  8102. addTest('datauri', false);
  8103. };
  8104. datauri.onload = function() {
  8105. if (datauri.width === 1 && datauri.height === 1) {
  8106. testOver32kb();
  8107. }
  8108. else {
  8109. addTest('datauri', false);
  8110. }
  8111. };
  8112. datauri.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
  8113. // Once we have datauri, let's check to see if we can use data URIs over
  8114. // 32kb (IE8 can't). https://github.com/Modernizr/Modernizr/issues/321
  8115. function testOver32kb() {
  8116. var datauriBig = new Image();
  8117. datauriBig.onerror = function() {
  8118. addTest('datauri', true);
  8119. Modernizr.datauri = new Boolean(true);
  8120. Modernizr.datauri.over32kb = false;
  8121. };
  8122. datauriBig.onload = function() {
  8123. addTest('datauri', true);
  8124. Modernizr.datauri = new Boolean(true);
  8125. Modernizr.datauri.over32kb = (datauriBig.width === 1 && datauriBig.height === 1);
  8126. };
  8127. var base64str = 'R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
  8128. while (base64str.length < 33000) {
  8129. base64str = '\r\n' + base64str;
  8130. }
  8131. datauriBig.src = 'data:image/gif;base64,' + base64str;
  8132. }
  8133. });
  8134. /*!
  8135. {
  8136. "name": "URL parser",
  8137. "property": "urlparser",
  8138. "notes": [{
  8139. "name": "WHATWG Spec",
  8140. "href": "https://url.spec.whatwg.org/"
  8141. }],
  8142. "polyfills": ["urlparser"],
  8143. "authors": ["Ron Waldon (@jokeyrhyme)"],
  8144. "tags": ["url"]
  8145. }
  8146. !*/
  8147. /* DOC
  8148. Check if browser implements the URL constructor for parsing URLs.
  8149. */
  8150. Modernizr.addTest('urlparser', function() {
  8151. var url;
  8152. try {
  8153. // have to actually try use it, because Safari defines a dud constructor
  8154. url = new URL('http://modernizr.com/');
  8155. return url.href === 'http://modernizr.com/';
  8156. } catch (e) {
  8157. return false;
  8158. }
  8159. });
  8160. /*!
  8161. {
  8162. "property": "urlsearchparams",
  8163. "tags": ["querystring", "url"],
  8164. "authors": ["Cătălin Mariș"],
  8165. "name": "URLSearchParams API",
  8166. "notes": [{
  8167. "name": "WHATWG Spec",
  8168. "href": "https://url.spec.whatwg.org/#interface-urlsearchparams"
  8169. },{
  8170. "name": "MDN Docs",
  8171. "href": "https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams"
  8172. }]
  8173. }
  8174. !*/
  8175. /* DOC
  8176. Detects support for an API that provides utility methods for working with the query string of a URL.
  8177. */
  8178. Modernizr.addTest('urlsearchparams', 'URLSearchParams' in window);
  8179. /*!
  8180. {
  8181. "name": "Video Autoplay",
  8182. "property": "videoautoplay",
  8183. "tags": ["video"],
  8184. "async": true,
  8185. "warnings": ["This test is very large – only include it if you absolutely need it"],
  8186. "knownBugs": ["crashes with an alert on iOS7 when added to homescreen"]
  8187. }
  8188. !*/
  8189. /* DOC
  8190. Checks for support of the autoplay attribute of the video element.
  8191. */
  8192. Modernizr.addAsyncTest(function() {
  8193. var timeout;
  8194. var waitTime = 200;
  8195. var retries = 5;
  8196. var currentTry = 0;
  8197. var elem = createElement('video');
  8198. var elemStyle = elem.style;
  8199. function testAutoplay(arg) {
  8200. currentTry++;
  8201. clearTimeout(timeout);
  8202. var result = arg && arg.type === 'playing' || elem.currentTime !== 0;
  8203. if (!result && currentTry < retries) {
  8204. //Detection can be flaky if the browser is slow, so lets retry in a little bit
  8205. timeout = setTimeout(testAutoplay, waitTime);
  8206. return;
  8207. }
  8208. elem.removeEventListener('playing', testAutoplay, false);
  8209. addTest('videoautoplay', result);
  8210. // Cleanup, but don't assume elem is still in the page -
  8211. // an extension (eg Flashblock) may already have removed it.
  8212. if (elem.parentNode) {
  8213. elem.parentNode.removeChild(elem);
  8214. }
  8215. }
  8216. //skip the test if video itself, or the autoplay
  8217. //element on it isn't supported
  8218. if (!Modernizr.video || !('autoplay' in elem)) {
  8219. addTest('videoautoplay', false);
  8220. return;
  8221. }
  8222. elemStyle.position = 'absolute';
  8223. elemStyle.height = 0;
  8224. elemStyle.width = 0;
  8225. try {
  8226. if (Modernizr.video.ogg) {
  8227. elem.src = 'data:video/ogg;base64,T2dnUwACAAAAAAAAAABmnCATAAAAAHDEixYBKoB0aGVvcmEDAgEAAQABAAAQAAAQAAAAAAAFAAAAAQAAAAAAAAAAAGIAYE9nZ1MAAAAAAAAAAAAAZpwgEwEAAAACrA7TDlj///////////////+QgXRoZW9yYSsAAABYaXBoLk9yZyBsaWJ0aGVvcmEgMS4xIDIwMDkwODIyIChUaHVzbmVsZGEpAQAAABoAAABFTkNPREVSPWZmbXBlZzJ0aGVvcmEtMC4yOYJ0aGVvcmG+zSj3uc1rGLWpSUoQc5zmMYxSlKQhCDGMYhCEIQhAAAAAAAAAAAAAEW2uU2eSyPxWEvx4OVts5ir1aKtUKBMpJFoQ/nk5m41mUwl4slUpk4kkghkIfDwdjgajQYC8VioUCQRiIQh8PBwMhgLBQIg4FRba5TZ5LI/FYS/Hg5W2zmKvVoq1QoEykkWhD+eTmbjWZTCXiyVSmTiSSCGQh8PB2OBqNBgLxWKhQJBGIhCHw8HAyGAsFAiDgUCw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDAwPEhQUFQ0NDhESFRUUDg4PEhQVFRUOEBETFBUVFRARFBUVFRUVEhMUFRUVFRUUFRUVFRUVFRUVFRUVFRUVEAwLEBQZGxwNDQ4SFRwcGw4NEBQZHBwcDhATFhsdHRwRExkcHB4eHRQYGxwdHh4dGxwdHR4eHh4dHR0dHh4eHRALChAYKDM9DAwOExo6PDcODRAYKDlFOA4RFh0zV1A+EhYlOkRtZ00YIzdAUWhxXDFATldneXhlSFxfYnBkZ2MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEhIVGRoaGhoSFBYaGhoaGhUWGRoaGhoaGRoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhESFh8kJCQkEhQYIiQkJCQWGCEkJCQkJB8iJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQREhgvY2NjYxIVGkJjY2NjGBo4Y2NjY2MvQmNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRISEhUXGBkbEhIVFxgZGxwSFRcYGRscHRUXGBkbHB0dFxgZGxwdHR0YGRscHR0dHhkbHB0dHR4eGxwdHR0eHh4REREUFxocIBERFBcaHCAiERQXGhwgIiUUFxocICIlJRcaHCAiJSUlGhwgIiUlJSkcICIlJSUpKiAiJSUlKSoqEBAQFBgcICgQEBQYHCAoMBAUGBwgKDBAFBgcICgwQEAYHCAoMEBAQBwgKDBAQEBgICgwQEBAYIAoMEBAQGCAgAfF5cdH1e3Ow/L66wGmYnfIUbwdUTe3LMRbqON8B+5RJEvcGxkvrVUjTMrsXYhAnIwe0dTJfOYbWrDYyqUrz7dw/JO4hpmV2LsQQvkUeGq1BsZLx+cu5iV0e0eScJ91VIQYrmqfdVSK7GgjOU0oPaPOu5IcDK1mNvnD+K8LwS87f8Jx2mHtHnUkTGAurWZlNQa74ZLSFH9oF6FPGxzLsjQO5Qe0edcpttd7BXBSqMCL4k/4tFrHIPuEQ7m1/uIWkbDMWVoDdOSuRQ9286kvVUlQjzOE6VrNguN4oRXYGkgcnih7t13/9kxvLYKQezwLTrO44sVmMPgMqORo1E0sm1/9SludkcWHwfJwTSybR4LeAz6ugWVgRaY8mV/9SluQmtHrzsBtRF/wPY+X0JuYTs+ltgrXAmlk10xQHmTu9VSIAk1+vcvU4ml2oNzrNhEtQ3CysNP8UeR35wqpKUBdGdZMSjX4WVi8nJpdpHnbhzEIdx7mwf6W1FKAiucMXrWUWVjyRf23chNtR9mIzDoT/6ZLYailAjhFlZuvPtSeZ+2oREubDoWmT3TguY+JHPdRVSLKxfKH3vgNqJ/9emeEYikGXDFNzaLjvTeGAL61mogOoeG3y6oU4rW55ydoj0lUTSR/mmRhPmF86uwIfzp3FtiufQCmppaHDlGE0r2iTzXIw3zBq5hvaTldjG4CPb9wdxAme0SyedVKczJ9AtYbgPOzYKJvZZImsN7ecrxWZg5dR6ZLj/j4qpWsIA+vYwE+Tca9ounMIsrXMB4Stiib2SPQtZv+FVIpfEbzv8ncZoLBXc3YBqTG1HsskTTotZOYTG+oVUjLk6zhP8bg4RhMUNtfZdO7FdpBuXzhJ5Fh8IKlJG7wtD9ik8rWOJxy6iQ3NwzBpQ219mlyv+FLicYs2iJGSE0u2txzed++D61ZWCiHD/cZdQVCqkO2gJpdpNaObhnDfAPrT89RxdWFZ5hO3MseBSIlANppdZNIV/Rwe5eLTDvkfWKzFnH+QJ7m9QWV1KdwnuIwTNtZdJMoXBf74OhRnh2t+OTGL+AVUnIkyYY+QG7g9itHXyF3OIygG2s2kud679ZWKqSFa9n3IHD6MeLv1lZ0XyduRhiDRtrNnKoyiFVLcBm0ba5Yy3fQkDh4XsFE34isVpOzpa9nR8iCpS4HoxG2rJpnRhf3YboVa1PcRouh5LIJv/uQcPNd095ickTaiGBnWLKVWRc0OnYTSyex/n2FofEPnDG8y3PztHrzOLK1xo6RAml2k9owKajOC0Wr4D5x+3nA0UEhK2m198wuBHF3zlWWVKWLN1CHzLClUfuoYBcx4b1llpeBKmbayaR58njtE9onD66lUcsg0Spm2snsb+8HaJRn4dYcLbCuBuYwziB8/5U1C1DOOz2gZjSZtrLJk6vrLF3hwY4Io9xuT/ruUFRSBkNtUzTOWhjh26irLEPx4jPZL3Fo3QrReoGTTM21xYTT9oFdhTUIvjqTkfkvt0bzgVUjq/hOYY8j60IaO/0AzRBtqkTS6R5ellZd5uKdzzhb8BFlDdAcrwkE0rbXTOPB+7Y0FlZO96qFL4Ykg21StJs8qIW7h16H5hGiv8V2Cflau7QVDepTAHa6Lgt6feiEvJDM21StJsmOH/hynURrKxvUpQ8BH0JF7BiyG2qZpnL/7AOU66gt+reLEXY8pVOCQvSsBtqZTNM8bk9ohRcwD18o/WVkbvrceVKRb9I59IEKysjBeTMmmbA21xu/6iHadLRxuIzkLpi8wZYmmbbWi32RVAUjruxWlJ//iFxE38FI9hNKOoCdhwf5fDe4xZ81lgREhK2m1j78vW1CqkuMu/AjBNK210kzRUX/B+69cMMUG5bYrIeZxVSEZISmkzbXOi9yxwIfPgdsov7R71xuJ7rFcACjG/9PzApqFq7wEgzNJm2suWESPuwrQvejj7cbnQxMkxpm21lUYJL0fKmogPPqywn7e3FvB/FCNxPJ85iVUkCE9/tLKx31G4CgNtWTTPFhMvlu8G4/TrgaZttTChljfNJGgOT2X6EqpETy2tYd9cCBI4lIXJ1/3uVUllZEJz4baqGF64yxaZ+zPLYwde8Uqn1oKANtUrSaTOPHkhvuQP3bBlEJ/LFe4pqQOHUI8T8q7AXx3fLVBgSCVpMba55YxN3rv8U1Dv51bAPSOLlZWebkL8vSMGI21lJmmeVxPRwFlZF1CpqCN8uLwymaZyjbXHCRytogPN3o/n74CNykfT+qqRv5AQlHcRxYrC5KvGmbbUwmZY/29BvF6C1/93x4WVglXDLFpmbapmF89HKTogRwqqSlGbu+oiAkcWFbklC6Zhf+NtTLFpn8oWz+HsNRVSgIxZWON+yVyJlE5tq/+GWLTMutYX9ekTySEQPLVNQQ3OfycwJBM0zNtZcse7CvcKI0V/zh16Dr9OSA21MpmmcrHC+6pTAPHPwoit3LHHqs7jhFNRD6W8+EBGoSEoaZttTCZljfduH/fFisn+dRBGAZYtMzbVMwvul/T/crK1NQh8gN0SRRa9cOux6clC0/mDLFpmbarmF8/e6CopeOLCNW6S/IUUg3jJIYiAcDoMcGeRbOvuTPjXR/tyo79LK3kqqkbxkkMRAOB0GODPItnX3Jnxro/25Ud+llbyVVSN4ySGIgHA6DHBnkWzr7kz410f7cqO/Syt5KqpFVJwn6gBEvBM0zNtZcpGOEPiysW8vvRd2R0f7gtjhqUvXL+gWVwHm4XJDBiMpmmZtrLfPwd/IugP5+fKVSysH1EXreFAcEhelGmbbUmZY4Xdo1vQWVnK19P4RuEnbf0gQnR+lDCZlivNM22t1ESmopPIgfT0duOfQrsjgG4tPxli0zJmF5trdL1JDUIUT1ZXSqQDeR4B8mX3TrRro/2McGeUvLtwo6jIEKMkCUXWsLyZROd9P/rFYNtXPBli0z398iVUlVKAjFlY437JXImUTm2r/4ZYtMy61hf16RPJIU9nZ1MABAwAAAAAAAAAZpwgEwIAAABhp658BScAAAAAAADnUFBQXIDGXLhwtttNHDhw5OcpQRMETBEwRPduylKVB0HRdF0A';
  8228. }
  8229. else if (Modernizr.video.h264) {
  8230. elem.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAs1tZGF0AAACrgYF//+q3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0OCByMjYwMSBhMGNkN2QzIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEwIHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAD2WIhAA3//728P4FNjuZQQAAAu5tb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAZAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACGHRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAgAAAAIAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAGQAAAAAAAEAAAAAAZBtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAACgAAAAEAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAE7bWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAA+3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAgACAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFkAAr/4QAYZ2QACqzZX4iIhAAAAwAEAAADAFA8SJZYAQAGaOvjyyLAAAAAGHN0dHMAAAAAAAAAAQAAAAEAAAQAAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAABAAAAAQAAABRzdHN6AAAAAAAAAsUAAAABAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjU2LjQwLjEwMQ==';
  8231. }
  8232. else {
  8233. addTest('videoautoplay', false);
  8234. return;
  8235. }
  8236. }
  8237. catch (e) {
  8238. addTest('videoautoplay', false);
  8239. return;
  8240. }
  8241. elem.setAttribute('autoplay', '');
  8242. elemStyle.cssText = 'display:none';
  8243. docElement.appendChild(elem);
  8244. // wait for the next tick to add the listener, otherwise the element may
  8245. // not have time to play in high load situations (e.g. the test suite)
  8246. setTimeout(function() {
  8247. elem.addEventListener('playing', testAutoplay, false);
  8248. timeout = setTimeout(testAutoplay, waitTime);
  8249. }, 0);
  8250. });
  8251. /*!
  8252. {
  8253. "name": "Video crossOrigin",
  8254. "property": "videocrossorigin",
  8255. "caniuse": "cors",
  8256. "authors": ["Florian Mailliet"],
  8257. "notes": [{
  8258. "name": "MDN Docs",
  8259. "href": "https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes"
  8260. }]
  8261. }
  8262. !*/
  8263. /* DOC
  8264. Detects support for the crossOrigin attribute on video tag
  8265. */
  8266. Modernizr.addTest('videocrossorigin', 'crossOrigin' in createElement('video'));
  8267. /*!
  8268. {
  8269. "name": "Video Loop Attribute",
  8270. "property": "videoloop",
  8271. "tags": ["video", "media"]
  8272. }
  8273. !*/
  8274. Modernizr.addTest('videoloop', 'loop' in createElement('video'));
  8275. /*!
  8276. {
  8277. "name": "Video Preload Attribute",
  8278. "property": "videopreload",
  8279. "tags": ["video", "media"]
  8280. }
  8281. !*/
  8282. Modernizr.addTest('videopreload', 'preload' in createElement('video'));
  8283. /*!
  8284. {
  8285. "name": "PublicKeyCredential",
  8286. "notes": [
  8287. {
  8288. "name": "MDN Documentation",
  8289. "href": "https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential"
  8290. },
  8291. {
  8292. "name": "Google Developers solution",
  8293. "href": "https://developers.google.com/web/updates/2018/03/webauthn-credential-management#the_solution"
  8294. }
  8295. ],
  8296. "property": "publicKeyCredential",
  8297. "tags": ["webauthn", "web authentication"],
  8298. "authors": ["Eric Delia"]
  8299. }
  8300. !*/
  8301. /* DOC
  8302. Detects support for PublicKeyCredential as part of the Web Authentication API (also known as webauthn)
  8303. */
  8304. Modernizr.addTest('publicKeyCredential', function() {
  8305. if (window.PublicKeyCredential) {
  8306. return true;
  8307. }
  8308. return false;
  8309. });
  8310. /*!
  8311. {
  8312. "name": "WebGL Extensions",
  8313. "property": "webglextensions",
  8314. "tags": ["webgl", "graphics"],
  8315. "builderAliases": ["webgl_extensions"],
  8316. "async": true,
  8317. "authors": ["Ilmari Heikkinen"],
  8318. "notes": [{
  8319. "name": "Kronos extensions registry",
  8320. "href": "https://www.khronos.org/registry/webgl/extensions/"
  8321. }]
  8322. }
  8323. !*/
  8324. /* DOC
  8325. Detects support for OpenGL extensions in WebGL. It's `true` if the [WebGL extensions API](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Using_Extensions) is supported, then exposes the supported extensions as subproperties, e.g.:
  8326. ```javascript
  8327. if (Modernizr.webglextensions) {
  8328. // WebGL extensions API supported
  8329. }
  8330. if ('OES_vertex_array_object' in Modernizr.webglextensions) {
  8331. // Vertex Array Objects extension supported
  8332. }
  8333. ```
  8334. */
  8335. // based on code from ilmari heikkinen
  8336. // code.google.com/p/graphics-detect/source/browse/js/detect.js
  8337. // Not Async but handles it's own self
  8338. Modernizr.addAsyncTest(function() {
  8339. // Not a good candidate for css classes, so we avoid addTest stuff
  8340. Modernizr.webglextensions = false;
  8341. if (!Modernizr.webgl) {
  8342. return;
  8343. }
  8344. var canvas;
  8345. var ctx;
  8346. var exts;
  8347. try {
  8348. canvas = createElement('canvas');
  8349. ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  8350. exts = ctx.getSupportedExtensions();
  8351. }
  8352. catch (e) {
  8353. return;
  8354. }
  8355. if (ctx !== undefined) {
  8356. Modernizr.webglextensions = new Boolean(true);
  8357. }
  8358. for (var i = -1, len = exts.length; ++i < len;) {
  8359. Modernizr.webglextensions[exts[i]] = true;
  8360. }
  8361. canvas = undefined;
  8362. });
  8363. /*!
  8364. {
  8365. "name": "RTC Peer Connection",
  8366. "property": "peerconnection",
  8367. "tags": ["webrtc"],
  8368. "authors": ["Ankur Oberoi"],
  8369. "notes": [{
  8370. "name": "W3C Spec",
  8371. "href": "https://www.w3.org/TR/webrtc/"
  8372. }]
  8373. }
  8374. !*/
  8375. Modernizr.addTest('peerconnection', !!prefixed('RTCPeerConnection', window));
  8376. /*!
  8377. {
  8378. "name": "RTC Data Channel",
  8379. "property": "datachannel",
  8380. "notes": [{
  8381. "name": "HTML5 Rocks Tutorial",
  8382. "href": "https://www.html5rocks.com/en/tutorials/webrtc/datachannels/"
  8383. }]
  8384. }
  8385. !*/
  8386. /* DOC
  8387. Detect for the RTCDataChannel API that allows for transfer data directly from one peer to another
  8388. */
  8389. Modernizr.addTest('datachannel', function() {
  8390. if (!Modernizr.peerconnection) {
  8391. return false;
  8392. }
  8393. for (var i = 0, l = domPrefixes.length; i < l; i++) {
  8394. var PeerConnectionConstructor = window[domPrefixes[i] + 'RTCPeerConnection'];
  8395. if (PeerConnectionConstructor) {
  8396. var peerConnection = new PeerConnectionConstructor(null);
  8397. return 'createDataChannel' in peerConnection;
  8398. }
  8399. }
  8400. return false;
  8401. });
  8402. /*!
  8403. {
  8404. "name": "getUserMedia",
  8405. "property": "getusermedia",
  8406. "caniuse": "stream",
  8407. "tags": ["webrtc"],
  8408. "authors": ["Eric Bidelman", "Masataka Yakura"],
  8409. "notes": [{
  8410. "name": "W3C Spec",
  8411. "href": "https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia"
  8412. }]
  8413. }
  8414. !*/
  8415. /* DOC
  8416. Detects support for the new Promise-based `getUserMedia` API.
  8417. */
  8418. Modernizr.addTest('getUserMedia', 'mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices);
  8419. /*!
  8420. {
  8421. "name": "Binary WebSockets",
  8422. "property": "websocketsbinary",
  8423. "tags": ["websockets"],
  8424. "builderAliases": ["websockets_binary"]
  8425. }
  8426. !*/
  8427. // binaryType is truthy if there is support.. returns "blob" in new-ish chrome.
  8428. // plus.google.com/115535723976198353696/posts/ERN6zYozENV
  8429. // github.com/Modernizr/Modernizr/issues/370
  8430. Modernizr.addTest('websocketsbinary', function() {
  8431. var protocol = 'https:' === location.protocol ? 'wss' : 'ws',
  8432. protoBin;
  8433. if ('WebSocket' in window) {
  8434. protoBin = 'binaryType' in WebSocket.prototype;
  8435. if (protoBin) {
  8436. return protoBin;
  8437. }
  8438. try {
  8439. return !!(new WebSocket(protocol + '://.').binaryType);
  8440. } catch (e) {}
  8441. }
  8442. return false;
  8443. });
  8444. /*!
  8445. {
  8446. "name": "Base 64 encoding/decoding",
  8447. "property": "atobbtoa",
  8448. "builderAliases": ["atob-btoa"],
  8449. "caniuse": "atob-btoa",
  8450. "tags": ["atob", "base64", "WindowBase64", "btoa"],
  8451. "authors": ["Christian Ulbrich"],
  8452. "notes": [{
  8453. "name": "WindowBase64",
  8454. "href": "https://www.w3.org/TR/html5/webappapis.html#windowbase64"
  8455. }, {
  8456. "name": "MDN Docs",
  8457. "href": "https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/atob"
  8458. }],
  8459. "polyfills": ["base64js"]
  8460. }
  8461. !*/
  8462. /* DOC
  8463. Detects support for WindowBase64 API (window.atob && window.btoa).
  8464. */
  8465. Modernizr.addTest('atobbtoa', 'atob' in window && 'btoa' in window, {aliases: ['atob-btoa']});
  8466. /*!
  8467. {
  8468. "name": "Framed window",
  8469. "property": "framed",
  8470. "tags": ["window"],
  8471. "builderAliases": ["window_framed"]
  8472. }
  8473. !*/
  8474. /* DOC
  8475. Tests if page is iframed.
  8476. */
  8477. // github.com/Modernizr/Modernizr/issues/242
  8478. Modernizr.addTest('framed', window.location !== top.location);
  8479. /*!
  8480. {
  8481. "name": "matchMedia",
  8482. "property": "matchmedia",
  8483. "caniuse": "matchmedia",
  8484. "tags": ["matchmedia"],
  8485. "authors": ["Alberto Elias"],
  8486. "notes": [{
  8487. "name": "W3C Spec",
  8488. "href": "https://drafts.csswg.org/cssom-view/#the-mediaquerylist-interface"
  8489. }, {
  8490. "name": "MDN Docs",
  8491. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Window.matchMedia"
  8492. }],
  8493. "polyfills": ["matchmediajs"]
  8494. }
  8495. !*/
  8496. /* DOC
  8497. Detects support for matchMedia.
  8498. */
  8499. Modernizr.addTest('matchmedia', !!prefixed('matchMedia', window));
  8500. /*!
  8501. {
  8502. "name": "Workers from Blob URIs",
  8503. "property": "blobworkers",
  8504. "tags": ["performance", "workers"],
  8505. "builderAliases": ["workers_blobworkers"],
  8506. "notes": [{
  8507. "name": "W3C Spec",
  8508. "href": "https://www.w3.org/TR/workers/"
  8509. }],
  8510. "knownBugs": ["This test may output garbage to console."],
  8511. "authors": ["Jussi Kalliokoski"],
  8512. "async": true
  8513. }
  8514. !*/
  8515. /* DOC
  8516. Detects support for creating Web Workers from Blob URIs.
  8517. */
  8518. Modernizr.addAsyncTest(function() {
  8519. try {
  8520. // we're avoiding using Modernizr._domPrefixes as the prefix capitalization on
  8521. // these guys are notoriously peculiar.
  8522. var BlobBuilder = window.BlobBuilder;
  8523. var URL = window.URL;
  8524. if (Modernizr._config.usePrefix) {
  8525. BlobBuilder = BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder || window.OBlobBuilder;
  8526. URL = URL || window.MozURL || window.webkitURL || window.MSURL || window.OURL;
  8527. }
  8528. var data = 'Modernizr',
  8529. blob,
  8530. bb,
  8531. worker,
  8532. url,
  8533. timeout,
  8534. scriptText = 'this.onmessage=function(e){postMessage(e.data)}';
  8535. try {
  8536. blob = new Blob([scriptText], {type: 'text/javascript'});
  8537. } catch (e) {
  8538. // we'll fall back to the deprecated BlobBuilder
  8539. }
  8540. if (!blob) {
  8541. bb = new BlobBuilder();
  8542. bb.append(scriptText);
  8543. blob = bb.getBlob();
  8544. }
  8545. url = URL.createObjectURL(blob);
  8546. worker = new Worker(url);
  8547. worker.onmessage = function(e) {
  8548. addTest('blobworkers', data === e.data);
  8549. cleanup();
  8550. };
  8551. // Just in case...
  8552. worker.onerror = fail;
  8553. timeout = setTimeout(fail, 200);
  8554. worker.postMessage(data);
  8555. } catch (e) {
  8556. fail();
  8557. }
  8558. function fail() {
  8559. addTest('blobworkers', false);
  8560. cleanup();
  8561. }
  8562. function cleanup() {
  8563. if (url) {
  8564. URL.revokeObjectURL(url);
  8565. }
  8566. if (worker) {
  8567. worker.terminate();
  8568. }
  8569. if (timeout) {
  8570. clearTimeout(timeout);
  8571. }
  8572. }
  8573. });
  8574. /*!
  8575. {
  8576. "name": "Workers from Data URIs",
  8577. "property": "dataworkers",
  8578. "tags": ["performance", "workers"],
  8579. "builderAliases": ["workers_dataworkers"],
  8580. "notes": [{
  8581. "name": "W3C Spec",
  8582. "href": "https://www.w3.org/TR/workers/"
  8583. }],
  8584. "knownBugs": ["This test may output garbage to console."],
  8585. "authors": ["Jussi Kalliokoski"],
  8586. "async": true
  8587. }
  8588. !*/
  8589. /* DOC
  8590. Detects support for creating Web Workers from Data URIs.
  8591. */
  8592. Modernizr.addAsyncTest(function() {
  8593. try {
  8594. var data = 'Modernizr',
  8595. worker = new Worker('data:text/javascript;base64,dGhpcy5vbm1lc3NhZ2U9ZnVuY3Rpb24oZSl7cG9zdE1lc3NhZ2UoZS5kYXRhKX0=');
  8596. worker.onmessage = function(e) {
  8597. worker.terminate();
  8598. addTest('dataworkers', data === e.data);
  8599. worker = null;
  8600. };
  8601. // Just in case...
  8602. worker.onerror = function() {
  8603. addTest('dataworkers', false);
  8604. worker = null;
  8605. };
  8606. setTimeout(function() {
  8607. addTest('dataworkers', false);
  8608. }, 200);
  8609. worker.postMessage(data);
  8610. } catch (e) {
  8611. setTimeout(function() {
  8612. addTest('dataworkers', false);
  8613. }, 0);
  8614. }
  8615. });
  8616. /*!
  8617. {
  8618. "name": "Shared Workers",
  8619. "property": "sharedworkers",
  8620. "caniuse": "sharedworkers",
  8621. "tags": ["performance", "workers"],
  8622. "builderAliases": ["workers_sharedworkers"],
  8623. "notes": [{
  8624. "name": "W3C Spec",
  8625. "href": "https://www.w3.org/TR/workers/"
  8626. }]
  8627. }
  8628. !*/
  8629. /* DOC
  8630. Detects support for the `SharedWorker` API from the Web Workers spec.
  8631. */
  8632. Modernizr.addTest('sharedworkers', 'SharedWorker' in window);
  8633. /*!
  8634. {
  8635. "name": "Web Workers",
  8636. "property": "webworkers",
  8637. "caniuse": "webworkers",
  8638. "tags": ["performance", "workers"],
  8639. "notes": [{
  8640. "name": "W3C Spec",
  8641. "href": "https://www.w3.org/TR/workers/"
  8642. }, {
  8643. "name": "HTML5 Rocks Tutorial",
  8644. "href": "https://www.html5rocks.com/en/tutorials/workers/basics/"
  8645. }, {
  8646. "name": "MDN Docs",
  8647. "href": "https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"
  8648. }],
  8649. "polyfills": ["fakeworker", "html5shims"]
  8650. }
  8651. !*/
  8652. /* DOC
  8653. Detects support for the basic `Worker` API from the Web Workers spec. Web Workers provide a simple means for web content to run scripts in background threads.
  8654. */
  8655. Modernizr.addTest('webworkers', 'Worker' in window);
  8656. /*!
  8657. {
  8658. "name": "Transferables Objects",
  8659. "property": "transferables",
  8660. "tags": ["performance", "workers"],
  8661. "builderAliases": ["transferables"],
  8662. "notes": [{
  8663. "name": "Transferable Objects: Lightning Fast!",
  8664. "href": "https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast"
  8665. }],
  8666. "async": true
  8667. }
  8668. !*/
  8669. /* DOC
  8670. Detects whether web workers can use `transferables` objects.
  8671. */
  8672. Modernizr.addAsyncTest(function() {
  8673. var prerequisites = !!(Modernizr.blobconstructor &&
  8674. Modernizr.bloburls &&
  8675. Modernizr.webworkers &&
  8676. Modernizr.typedarrays);
  8677. // Early exit
  8678. if (!prerequisites) {
  8679. return addTest('transferables', false);
  8680. }
  8681. // Proper test if prerequisites are met
  8682. try {
  8683. var buffer,
  8684. scriptText = 'var hello = "world"',
  8685. blob = new Blob([scriptText], {type: 'text/javascript'}),
  8686. url = URL.createObjectURL(blob),
  8687. worker = new Worker(url),
  8688. timeout;
  8689. // Just in case...
  8690. worker.onerror = fail;
  8691. timeout = setTimeout(fail, 200);
  8692. // Building an minimal array buffer to send to the worker
  8693. buffer = new ArrayBuffer(1);
  8694. // Sending the buffer to the worker
  8695. worker.postMessage(buffer, [buffer]);
  8696. // If length of buffer is now 0, transferables are working
  8697. addTest('transferables', buffer.byteLength === 0);
  8698. cleanup();
  8699. } catch (e) {
  8700. fail();
  8701. }
  8702. function fail() {
  8703. addTest('transferables', false);
  8704. cleanup();
  8705. }
  8706. function cleanup() {
  8707. if (url) {
  8708. URL.revokeObjectURL(url);
  8709. }
  8710. if (worker) {
  8711. worker.terminate();
  8712. }
  8713. if (timeout) {
  8714. clearTimeout(timeout);
  8715. }
  8716. }
  8717. });
  8718. // Run each test
  8719. testRunner();
  8720. // Remove the "no-js" class if it exists
  8721. setClasses(classes);
  8722. delete ModernizrProto.addTest;
  8723. delete ModernizrProto.addAsyncTest;
  8724. // Run the things that are supposed to run after the tests
  8725. for (var i = 0; i < Modernizr._q.length; i++) {
  8726. Modernizr._q[i]();
  8727. }
  8728. // Leak Modernizr namespace
  8729. window.Modernizr = Modernizr;
  8730. ;
  8731. })(window, document);