moxie.js 292 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714
  1. ;var MXI_DEBUG = true;
  2. /**
  3. * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
  4. * v1.5.7
  5. *
  6. * Copyright 2013, Moxiecode Systems AB
  7. * Released under GPL License.
  8. *
  9. * License: http://www.plupload.com/license
  10. * Contributing: http://www.plupload.com/contributing
  11. *
  12. * Date: 2017-11-03
  13. */
  14. ;(function (global, factory) {
  15. var extract = function() {
  16. var ctx = {};
  17. factory.apply(ctx, arguments);
  18. return ctx.moxie;
  19. };
  20. if (typeof define === "function" && define.amd) {
  21. define("moxie", [], extract);
  22. } else if (typeof module === "object" && module.exports) {
  23. module.exports = extract();
  24. } else {
  25. global.moxie = extract();
  26. }
  27. }(this || window, function() {
  28. /**
  29. * Compiled inline version. (Library mode)
  30. */
  31. /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
  32. /*globals $code */
  33. (function(exports, undefined) {
  34. "use strict";
  35. var modules = {};
  36. function require(ids, callback) {
  37. var module, defs = [];
  38. for (var i = 0; i < ids.length; ++i) {
  39. module = modules[ids[i]] || resolve(ids[i]);
  40. if (!module) {
  41. throw 'module definition dependecy not found: ' + ids[i];
  42. }
  43. defs.push(module);
  44. }
  45. callback.apply(null, defs);
  46. }
  47. function define(id, dependencies, definition) {
  48. if (typeof id !== 'string') {
  49. throw 'invalid module definition, module id must be defined and be a string';
  50. }
  51. if (dependencies === undefined) {
  52. throw 'invalid module definition, dependencies must be specified';
  53. }
  54. if (definition === undefined) {
  55. throw 'invalid module definition, definition function must be specified';
  56. }
  57. require(dependencies, function() {
  58. modules[id] = definition.apply(null, arguments);
  59. });
  60. }
  61. function defined(id) {
  62. return !!modules[id];
  63. }
  64. function resolve(id) {
  65. var target = exports;
  66. var fragments = id.split(/[.\/]/);
  67. for (var fi = 0; fi < fragments.length; ++fi) {
  68. if (!target[fragments[fi]]) {
  69. return;
  70. }
  71. target = target[fragments[fi]];
  72. }
  73. return target;
  74. }
  75. function expose(ids) {
  76. for (var i = 0; i < ids.length; i++) {
  77. var target = exports;
  78. var id = ids[i];
  79. var fragments = id.split(/[.\/]/);
  80. for (var fi = 0; fi < fragments.length - 1; ++fi) {
  81. if (target[fragments[fi]] === undefined) {
  82. target[fragments[fi]] = {};
  83. }
  84. target = target[fragments[fi]];
  85. }
  86. target[fragments[fragments.length - 1]] = modules[id];
  87. }
  88. }
  89. // Included from: src/javascript/core/utils/Basic.js
  90. /**
  91. * Basic.js
  92. *
  93. * Copyright 2013, Moxiecode Systems AB
  94. * Released under GPL License.
  95. *
  96. * License: http://www.plupload.com/license
  97. * Contributing: http://www.plupload.com/contributing
  98. */
  99. /**
  100. @class moxie/core/utils/Basic
  101. @public
  102. @static
  103. */
  104. define('moxie/core/utils/Basic', [], function() {
  105. /**
  106. Gets the true type of the built-in object (better version of typeof).
  107. @author Angus Croll (http://javascriptweblog.wordpress.com/)
  108. @method typeOf
  109. @static
  110. @param {Object} o Object to check.
  111. @return {String} Object [[Class]]
  112. */
  113. function typeOf(o) {
  114. var undef;
  115. if (o === undef) {
  116. return 'undefined';
  117. } else if (o === null) {
  118. return 'null';
  119. } else if (o.nodeType) {
  120. return 'node';
  121. }
  122. // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8
  123. return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
  124. }
  125. /**
  126. Extends the specified object with another object(s).
  127. @method extend
  128. @static
  129. @param {Object} target Object to extend.
  130. @param {Object} [obj]* Multiple objects to extend with.
  131. @return {Object} Same as target, the extended object.
  132. */
  133. function extend() {
  134. return merge(false, false, arguments);
  135. }
  136. /**
  137. Extends the specified object with another object(s), but only if the property exists in the target.
  138. @method extendIf
  139. @static
  140. @param {Object} target Object to extend.
  141. @param {Object} [obj]* Multiple objects to extend with.
  142. @return {Object} Same as target, the extended object.
  143. */
  144. function extendIf() {
  145. return merge(true, false, arguments);
  146. }
  147. function extendImmutable() {
  148. return merge(false, true, arguments);
  149. }
  150. function extendImmutableIf() {
  151. return merge(true, true, arguments);
  152. }
  153. function clone(value) {
  154. switch (typeOf(value)) {
  155. case 'array':
  156. return merge(false, true, [[], value]);
  157. case 'object':
  158. return merge(false, true, [{}, value]);
  159. default:
  160. return value;
  161. }
  162. }
  163. function shallowCopy(obj) {
  164. switch (typeOf(obj)) {
  165. case 'array':
  166. return Array.prototype.slice.call(obj);
  167. case 'object':
  168. return extend({}, obj);
  169. }
  170. return obj;
  171. }
  172. function merge(strict, immutable, args) {
  173. var undef;
  174. var target = args[0];
  175. each(args, function(arg, i) {
  176. if (i > 0) {
  177. each(arg, function(value, key) {
  178. var isComplex = inArray(typeOf(value), ['array', 'object']) !== -1;
  179. if (value === undef || strict && target[key] === undef) {
  180. return true;
  181. }
  182. if (isComplex && immutable) {
  183. value = shallowCopy(value);
  184. }
  185. if (typeOf(target[key]) === typeOf(value) && isComplex) {
  186. merge(strict, immutable, [target[key], value]);
  187. } else {
  188. target[key] = value;
  189. }
  190. });
  191. }
  192. });
  193. return target;
  194. }
  195. /**
  196. A way to inherit one `class` from another in a consisstent way (more or less)
  197. @method inherit
  198. @static
  199. @since >1.4.1
  200. @param {Function} child
  201. @param {Function} parent
  202. @return {Function} Prepared constructor
  203. */
  204. function inherit(child, parent) {
  205. // copy over all parent properties
  206. for (var key in parent) {
  207. if ({}.hasOwnProperty.call(parent, key)) {
  208. child[key] = parent[key];
  209. }
  210. }
  211. // give child `class` a place to define its own methods
  212. function ctor() {
  213. this.constructor = child;
  214. if (MXI_DEBUG) {
  215. var getCtorName = function(fn) {
  216. var m = fn.toString().match(/^function\s([^\(\s]+)/);
  217. return m ? m[1] : false;
  218. };
  219. this.ctorName = getCtorName(child);
  220. }
  221. }
  222. ctor.prototype = parent.prototype;
  223. child.prototype = new ctor();
  224. // keep a way to reference parent methods
  225. child.parent = parent.prototype;
  226. return child;
  227. }
  228. /**
  229. Executes the callback function for each item in array/object. If you return false in the
  230. callback it will break the loop.
  231. @method each
  232. @static
  233. @param {Object} obj Object to iterate.
  234. @param {function} callback Callback function to execute for each item.
  235. */
  236. function each(obj, callback) {
  237. var length, key, i, undef;
  238. if (obj) {
  239. try {
  240. length = obj.length;
  241. } catch(ex) {
  242. length = undef;
  243. }
  244. if (length === undef || typeof(length) !== 'number') {
  245. // Loop object items
  246. for (key in obj) {
  247. if (obj.hasOwnProperty(key)) {
  248. if (callback(obj[key], key) === false) {
  249. return;
  250. }
  251. }
  252. }
  253. } else {
  254. // Loop array items
  255. for (i = 0; i < length; i++) {
  256. if (callback(obj[i], i) === false) {
  257. return;
  258. }
  259. }
  260. }
  261. }
  262. }
  263. /**
  264. Checks if object is empty.
  265. @method isEmptyObj
  266. @static
  267. @param {Object} o Object to check.
  268. @return {Boolean}
  269. */
  270. function isEmptyObj(obj) {
  271. var prop;
  272. if (!obj || typeOf(obj) !== 'object') {
  273. return true;
  274. }
  275. for (prop in obj) {
  276. return false;
  277. }
  278. return true;
  279. }
  280. /**
  281. Recieve an array of functions (usually async) to call in sequence, each function
  282. receives a callback as first argument that it should call, when it completes. Finally,
  283. after everything is complete, main callback is called. Passing truthy value to the
  284. callback as a first argument will interrupt the sequence and invoke main callback
  285. immediately.
  286. @method inSeries
  287. @static
  288. @param {Array} queue Array of functions to call in sequence
  289. @param {Function} cb Main callback that is called in the end, or in case of error
  290. */
  291. function inSeries(queue, cb) {
  292. var i = 0, length = queue.length;
  293. if (typeOf(cb) !== 'function') {
  294. cb = function() {};
  295. }
  296. if (!queue || !queue.length) {
  297. cb();
  298. }
  299. function callNext(i) {
  300. if (typeOf(queue[i]) === 'function') {
  301. queue[i](function(error) {
  302. /*jshint expr:true */
  303. ++i < length && !error ? callNext(i) : cb(error);
  304. });
  305. }
  306. }
  307. callNext(i);
  308. }
  309. /**
  310. Recieve an array of functions (usually async) to call in parallel, each function
  311. receives a callback as first argument that it should call, when it completes. After
  312. everything is complete, main callback is called. Passing truthy value to the
  313. callback as a first argument will interrupt the process and invoke main callback
  314. immediately.
  315. @method inParallel
  316. @static
  317. @param {Array} queue Array of functions to call in sequence
  318. @param {Function} cb Main callback that is called in the end, or in case of erro
  319. */
  320. function inParallel(queue, cb) {
  321. var count = 0, num = queue.length, cbArgs = new Array(num);
  322. each(queue, function(fn, i) {
  323. fn(function(error) {
  324. if (error) {
  325. return cb(error);
  326. }
  327. var args = [].slice.call(arguments);
  328. args.shift(); // strip error - undefined or not
  329. cbArgs[i] = args;
  330. count++;
  331. if (count === num) {
  332. cbArgs.unshift(null);
  333. cb.apply(this, cbArgs);
  334. }
  335. });
  336. });
  337. }
  338. /**
  339. Find an element in array and return it's index if present, otherwise return -1.
  340. @method inArray
  341. @static
  342. @param {Mixed} needle Element to find
  343. @param {Array} array
  344. @return {Int} Index of the element, or -1 if not found
  345. */
  346. function inArray(needle, array) {
  347. if (array) {
  348. if (Array.prototype.indexOf) {
  349. return Array.prototype.indexOf.call(array, needle);
  350. }
  351. for (var i = 0, length = array.length; i < length; i++) {
  352. if (array[i] === needle) {
  353. return i;
  354. }
  355. }
  356. }
  357. return -1;
  358. }
  359. /**
  360. Returns elements of first array if they are not present in second. And false - otherwise.
  361. @private
  362. @method arrayDiff
  363. @param {Array} needles
  364. @param {Array} array
  365. @return {Array|Boolean}
  366. */
  367. function arrayDiff(needles, array) {
  368. var diff = [];
  369. if (typeOf(needles) !== 'array') {
  370. needles = [needles];
  371. }
  372. if (typeOf(array) !== 'array') {
  373. array = [array];
  374. }
  375. for (var i in needles) {
  376. if (inArray(needles[i], array) === -1) {
  377. diff.push(needles[i]);
  378. }
  379. }
  380. return diff.length ? diff : false;
  381. }
  382. /**
  383. Find intersection of two arrays.
  384. @private
  385. @method arrayIntersect
  386. @param {Array} array1
  387. @param {Array} array2
  388. @return {Array} Intersection of two arrays or null if there is none
  389. */
  390. function arrayIntersect(array1, array2) {
  391. var result = [];
  392. each(array1, function(item) {
  393. if (inArray(item, array2) !== -1) {
  394. result.push(item);
  395. }
  396. });
  397. return result.length ? result : null;
  398. }
  399. /**
  400. Forces anything into an array.
  401. @method toArray
  402. @static
  403. @param {Object} obj Object with length field.
  404. @return {Array} Array object containing all items.
  405. */
  406. function toArray(obj) {
  407. var i, arr = [];
  408. for (i = 0; i < obj.length; i++) {
  409. arr[i] = obj[i];
  410. }
  411. return arr;
  412. }
  413. /**
  414. Generates an unique ID. The only way a user would be able to get the same ID is if the two persons
  415. at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses
  416. a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth
  417. to be hit with an asteroid.
  418. @method guid
  419. @static
  420. @param {String} prefix to prepend (by default 'o' will be prepended).
  421. @method guid
  422. @return {String} Virtually unique id.
  423. */
  424. var guid = (function() {
  425. var counter = 0;
  426. return function(prefix) {
  427. var guid = new Date().getTime().toString(32), i;
  428. for (i = 0; i < 5; i++) {
  429. guid += Math.floor(Math.random() * 65535).toString(32);
  430. }
  431. return (prefix || 'o_') + guid + (counter++).toString(32);
  432. };
  433. }());
  434. /**
  435. Trims white spaces around the string
  436. @method trim
  437. @static
  438. @param {String} str
  439. @return {String}
  440. */
  441. function trim(str) {
  442. if (!str) {
  443. return str;
  444. }
  445. return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, '');
  446. }
  447. /**
  448. Parses the specified size string into a byte value. For example 10kb becomes 10240.
  449. @method parseSizeStr
  450. @static
  451. @param {String/Number} size String to parse or number to just pass through.
  452. @return {Number} Size in bytes.
  453. */
  454. function parseSizeStr(size) {
  455. if (typeof(size) !== 'string') {
  456. return size;
  457. }
  458. var muls = {
  459. t: 1099511627776,
  460. g: 1073741824,
  461. m: 1048576,
  462. k: 1024
  463. },
  464. mul;
  465. size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, ''));
  466. mul = size[2];
  467. size = +size[1];
  468. if (muls.hasOwnProperty(mul)) {
  469. size *= muls[mul];
  470. }
  471. return Math.floor(size);
  472. }
  473. /**
  474. * Pseudo sprintf implementation - simple way to replace tokens with specified values.
  475. *
  476. * @param {String} str String with tokens
  477. * @return {String} String with replaced tokens
  478. */
  479. function sprintf(str) {
  480. var args = [].slice.call(arguments, 1);
  481. return str.replace(/%([a-z])/g, function($0, $1) {
  482. var value = args.shift();
  483. switch ($1) {
  484. case 's':
  485. return value + '';
  486. case 'd':
  487. return parseInt(value, 10);
  488. case 'f':
  489. return parseFloat(value);
  490. case 'c':
  491. return '';
  492. default:
  493. return value;
  494. }
  495. });
  496. }
  497. function delay(cb, timeout) {
  498. var self = this;
  499. setTimeout(function() {
  500. cb.call(self);
  501. }, timeout || 1);
  502. }
  503. return {
  504. guid: guid,
  505. typeOf: typeOf,
  506. extend: extend,
  507. extendIf: extendIf,
  508. extendImmutable: extendImmutable,
  509. extendImmutableIf: extendImmutableIf,
  510. clone: clone,
  511. inherit: inherit,
  512. each: each,
  513. isEmptyObj: isEmptyObj,
  514. inSeries: inSeries,
  515. inParallel: inParallel,
  516. inArray: inArray,
  517. arrayDiff: arrayDiff,
  518. arrayIntersect: arrayIntersect,
  519. toArray: toArray,
  520. trim: trim,
  521. sprintf: sprintf,
  522. parseSizeStr: parseSizeStr,
  523. delay: delay
  524. };
  525. });
  526. // Included from: src/javascript/core/utils/Encode.js
  527. /**
  528. * Encode.js
  529. *
  530. * Copyright 2013, Moxiecode Systems AB
  531. * Released under GPL License.
  532. *
  533. * License: http://www.plupload.com/license
  534. * Contributing: http://www.plupload.com/contributing
  535. */
  536. /**
  537. @class moxie/core/utils/Encode
  538. @public
  539. @static
  540. */
  541. define('moxie/core/utils/Encode', [], function() {
  542. /**
  543. Encode string with UTF-8
  544. @method utf8_encode
  545. @static
  546. @param {String} str String to encode
  547. @return {String} UTF-8 encoded string
  548. */
  549. var utf8_encode = function(str) {
  550. return unescape(encodeURIComponent(str));
  551. };
  552. /**
  553. Decode UTF-8 encoded string
  554. @method utf8_decode
  555. @static
  556. @param {String} str String to decode
  557. @return {String} Decoded string
  558. */
  559. var utf8_decode = function(str_data) {
  560. return decodeURIComponent(escape(str_data));
  561. };
  562. /**
  563. Decode Base64 encoded string (uses browser's default method if available),
  564. from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
  565. @method atob
  566. @static
  567. @param {String} data String to decode
  568. @return {String} Decoded string
  569. */
  570. var atob = function(data, utf8) {
  571. if (typeof(window.atob) === 'function') {
  572. return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
  573. }
  574. // http://kevin.vanzonneveld.net
  575. // + original by: Tyler Akins (http://rumkin.com)
  576. // + improved by: Thunder.m
  577. // + input by: Aman Gupta
  578. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  579. // + bugfixed by: Onno Marsman
  580. // + bugfixed by: Pellentesque Malesuada
  581. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  582. // + input by: Brett Zamir (http://brett-zamir.me)
  583. // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  584. // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
  585. // * returns 1: 'Kevin van Zonneveld'
  586. // mozilla has this native
  587. // - but breaks in 2.0.0.12!
  588. //if (typeof this.window.atob == 'function') {
  589. // return atob(data);
  590. //}
  591. var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  592. var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
  593. ac = 0,
  594. dec = "",
  595. tmp_arr = [];
  596. if (!data) {
  597. return data;
  598. }
  599. data += '';
  600. do { // unpack four hexets into three octets using index points in b64
  601. h1 = b64.indexOf(data.charAt(i++));
  602. h2 = b64.indexOf(data.charAt(i++));
  603. h3 = b64.indexOf(data.charAt(i++));
  604. h4 = b64.indexOf(data.charAt(i++));
  605. bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
  606. o1 = bits >> 16 & 0xff;
  607. o2 = bits >> 8 & 0xff;
  608. o3 = bits & 0xff;
  609. if (h3 == 64) {
  610. tmp_arr[ac++] = String.fromCharCode(o1);
  611. } else if (h4 == 64) {
  612. tmp_arr[ac++] = String.fromCharCode(o1, o2);
  613. } else {
  614. tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
  615. }
  616. } while (i < data.length);
  617. dec = tmp_arr.join('');
  618. return utf8 ? utf8_decode(dec) : dec;
  619. };
  620. /**
  621. Base64 encode string (uses browser's default method if available),
  622. from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
  623. @method btoa
  624. @static
  625. @param {String} data String to encode
  626. @return {String} Base64 encoded string
  627. */
  628. var btoa = function(data, utf8) {
  629. if (utf8) {
  630. data = utf8_encode(data);
  631. }
  632. if (typeof(window.btoa) === 'function') {
  633. return window.btoa(data);
  634. }
  635. // http://kevin.vanzonneveld.net
  636. // + original by: Tyler Akins (http://rumkin.com)
  637. // + improved by: Bayron Guevara
  638. // + improved by: Thunder.m
  639. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  640. // + bugfixed by: Pellentesque Malesuada
  641. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  642. // + improved by: Rafał Kukawski (http://kukawski.pl)
  643. // * example 1: base64_encode('Kevin van Zonneveld');
  644. // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
  645. // mozilla has this native
  646. // - but breaks in 2.0.0.12!
  647. var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  648. var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
  649. ac = 0,
  650. enc = "",
  651. tmp_arr = [];
  652. if (!data) {
  653. return data;
  654. }
  655. do { // pack three octets into four hexets
  656. o1 = data.charCodeAt(i++);
  657. o2 = data.charCodeAt(i++);
  658. o3 = data.charCodeAt(i++);
  659. bits = o1 << 16 | o2 << 8 | o3;
  660. h1 = bits >> 18 & 0x3f;
  661. h2 = bits >> 12 & 0x3f;
  662. h3 = bits >> 6 & 0x3f;
  663. h4 = bits & 0x3f;
  664. // use hexets to index into b64, and append result to encoded string
  665. tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
  666. } while (i < data.length);
  667. enc = tmp_arr.join('');
  668. var r = data.length % 3;
  669. return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
  670. };
  671. return {
  672. utf8_encode: utf8_encode,
  673. utf8_decode: utf8_decode,
  674. atob: atob,
  675. btoa: btoa
  676. };
  677. });
  678. // Included from: src/javascript/core/utils/Env.js
  679. /**
  680. * Env.js
  681. *
  682. * Copyright 2013, Moxiecode Systems AB
  683. * Released under GPL License.
  684. *
  685. * License: http://www.plupload.com/license
  686. * Contributing: http://www.plupload.com/contributing
  687. */
  688. /**
  689. @class moxie/core/utils/Env
  690. @public
  691. @static
  692. */
  693. define("moxie/core/utils/Env", [
  694. "moxie/core/utils/Basic"
  695. ], function(Basic) {
  696. /**
  697. * UAParser.js v0.7.7
  698. * Lightweight JavaScript-based User-Agent string parser
  699. * https://github.com/faisalman/ua-parser-js
  700. *
  701. * Copyright © 2012-2015 Faisal Salman <fyzlman@gmail.com>
  702. * Dual licensed under GPLv2 & MIT
  703. */
  704. var UAParser = (function (undefined) {
  705. //////////////
  706. // Constants
  707. /////////////
  708. var EMPTY = '',
  709. UNKNOWN = '?',
  710. FUNC_TYPE = 'function',
  711. UNDEF_TYPE = 'undefined',
  712. OBJ_TYPE = 'object',
  713. MAJOR = 'major',
  714. MODEL = 'model',
  715. NAME = 'name',
  716. TYPE = 'type',
  717. VENDOR = 'vendor',
  718. VERSION = 'version',
  719. ARCHITECTURE= 'architecture',
  720. CONSOLE = 'console',
  721. MOBILE = 'mobile',
  722. TABLET = 'tablet';
  723. ///////////
  724. // Helper
  725. //////////
  726. var util = {
  727. has : function (str1, str2) {
  728. return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
  729. },
  730. lowerize : function (str) {
  731. return str.toLowerCase();
  732. }
  733. };
  734. ///////////////
  735. // Map helper
  736. //////////////
  737. var mapper = {
  738. rgx : function () {
  739. // loop through all regexes maps
  740. for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
  741. var regex = args[i], // even sequence (0,2,4,..)
  742. props = args[i + 1]; // odd sequence (1,3,5,..)
  743. // construct object barebones
  744. if (typeof(result) === UNDEF_TYPE) {
  745. result = {};
  746. for (p in props) {
  747. q = props[p];
  748. if (typeof(q) === OBJ_TYPE) {
  749. result[q[0]] = undefined;
  750. } else {
  751. result[q] = undefined;
  752. }
  753. }
  754. }
  755. // try matching uastring with regexes
  756. for (j = k = 0; j < regex.length; j++) {
  757. matches = regex[j].exec(this.getUA());
  758. if (!!matches) {
  759. for (p = 0; p < props.length; p++) {
  760. match = matches[++k];
  761. q = props[p];
  762. // check if given property is actually array
  763. if (typeof(q) === OBJ_TYPE && q.length > 0) {
  764. if (q.length == 2) {
  765. if (typeof(q[1]) == FUNC_TYPE) {
  766. // assign modified match
  767. result[q[0]] = q[1].call(this, match);
  768. } else {
  769. // assign given value, ignore regex match
  770. result[q[0]] = q[1];
  771. }
  772. } else if (q.length == 3) {
  773. // check whether function or regex
  774. if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
  775. // call function (usually string mapper)
  776. result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
  777. } else {
  778. // sanitize match using given regex
  779. result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
  780. }
  781. } else if (q.length == 4) {
  782. result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
  783. }
  784. } else {
  785. result[q] = match ? match : undefined;
  786. }
  787. }
  788. break;
  789. }
  790. }
  791. if(!!matches) break; // break the loop immediately if match found
  792. }
  793. return result;
  794. },
  795. str : function (str, map) {
  796. for (var i in map) {
  797. // check if array
  798. if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
  799. for (var j = 0; j < map[i].length; j++) {
  800. if (util.has(map[i][j], str)) {
  801. return (i === UNKNOWN) ? undefined : i;
  802. }
  803. }
  804. } else if (util.has(map[i], str)) {
  805. return (i === UNKNOWN) ? undefined : i;
  806. }
  807. }
  808. return str;
  809. }
  810. };
  811. ///////////////
  812. // String map
  813. //////////////
  814. var maps = {
  815. browser : {
  816. oldsafari : {
  817. major : {
  818. '1' : ['/8', '/1', '/3'],
  819. '2' : '/4',
  820. '?' : '/'
  821. },
  822. version : {
  823. '1.0' : '/8',
  824. '1.2' : '/1',
  825. '1.3' : '/3',
  826. '2.0' : '/412',
  827. '2.0.2' : '/416',
  828. '2.0.3' : '/417',
  829. '2.0.4' : '/419',
  830. '?' : '/'
  831. }
  832. }
  833. },
  834. device : {
  835. sprint : {
  836. model : {
  837. 'Evo Shift 4G' : '7373KT'
  838. },
  839. vendor : {
  840. 'HTC' : 'APA',
  841. 'Sprint' : 'Sprint'
  842. }
  843. }
  844. },
  845. os : {
  846. windows : {
  847. version : {
  848. 'ME' : '4.90',
  849. 'NT 3.11' : 'NT3.51',
  850. 'NT 4.0' : 'NT4.0',
  851. '2000' : 'NT 5.0',
  852. 'XP' : ['NT 5.1', 'NT 5.2'],
  853. 'Vista' : 'NT 6.0',
  854. '7' : 'NT 6.1',
  855. '8' : 'NT 6.2',
  856. '8.1' : 'NT 6.3',
  857. 'RT' : 'ARM'
  858. }
  859. }
  860. }
  861. };
  862. //////////////
  863. // Regex map
  864. /////////////
  865. var regexes = {
  866. browser : [[
  867. // Presto based
  868. /(opera\smini)\/([\w\.-]+)/i, // Opera Mini
  869. /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet
  870. /(opera).+version\/([\w\.]+)/i, // Opera > 9.80
  871. /(opera)[\/\s]+([\w\.]+)/i // Opera < 9.80
  872. ], [NAME, VERSION], [
  873. /\s(opr)\/([\w\.]+)/i // Opera Webkit
  874. ], [[NAME, 'Opera'], VERSION], [
  875. // Mixed
  876. /(kindle)\/([\w\.]+)/i, // Kindle
  877. /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,
  878. // Lunascape/Maxthon/Netfront/Jasmine/Blazer
  879. // Trident based
  880. /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,
  881. // Avant/IEMobile/SlimBrowser/Baidu
  882. /(?:ms|\()(ie)\s([\w\.]+)/i, // Internet Explorer
  883. // Webkit/KHTML based
  884. /(rekonq)\/([\w\.]+)*/i, // Rekonq
  885. /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i
  886. // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron
  887. ], [NAME, VERSION], [
  888. /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i // IE11
  889. ], [[NAME, 'IE'], VERSION], [
  890. /(edge)\/((\d+)?[\w\.]+)/i // Microsoft Edge
  891. ], [NAME, VERSION], [
  892. /(yabrowser)\/([\w\.]+)/i // Yandex
  893. ], [[NAME, 'Yandex'], VERSION], [
  894. /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
  895. ], [[NAME, /_/g, ' '], VERSION], [
  896. /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,
  897. // Chrome/OmniWeb/Arora/Tizen/Nokia
  898. /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i
  899. // UCBrowser/QQBrowser
  900. ], [NAME, VERSION], [
  901. /(dolfin)\/([\w\.]+)/i // Dolphin
  902. ], [[NAME, 'Dolphin'], VERSION], [
  903. /((?:android.+)crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
  904. ], [[NAME, 'Chrome'], VERSION], [
  905. /XiaoMi\/MiuiBrowser\/([\w\.]+)/i // MIUI Browser
  906. ], [VERSION, [NAME, 'MIUI Browser']], [
  907. /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i // Android Browser
  908. ], [VERSION, [NAME, 'Android Browser']], [
  909. /FBAV\/([\w\.]+);/i // Facebook App for iOS
  910. ], [VERSION, [NAME, 'Facebook']], [
  911. /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari
  912. ], [VERSION, [NAME, 'Mobile Safari']], [
  913. /version\/([\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile
  914. ], [VERSION, NAME], [
  915. /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
  916. ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [
  917. /(konqueror)\/([\w\.]+)/i, // Konqueror
  918. /(webkit|khtml)\/([\w\.]+)/i
  919. ], [NAME, VERSION], [
  920. // Gecko based
  921. /(navigator|netscape)\/([\w\.-]+)/i // Netscape
  922. ], [[NAME, 'Netscape'], VERSION], [
  923. /(swiftfox)/i, // Swiftfox
  924. /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,
  925. // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
  926. /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,
  927. // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
  928. /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla
  929. // Other
  930. /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i,
  931. // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf
  932. /(links)\s\(([\w\.]+)/i, // Links
  933. /(gobrowser)\/?([\w\.]+)*/i, // GoBrowser
  934. /(ice\s?browser)\/v?([\w\._]+)/i, // ICE Browser
  935. /(mosaic)[\/\s]([\w\.]+)/i // Mosaic
  936. ], [NAME, VERSION]
  937. ],
  938. engine : [[
  939. /windows.+\sedge\/([\w\.]+)/i // EdgeHTML
  940. ], [VERSION, [NAME, 'EdgeHTML']], [
  941. /(presto)\/([\w\.]+)/i, // Presto
  942. /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
  943. /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links
  944. /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab
  945. ], [NAME, VERSION], [
  946. /rv\:([\w\.]+).*(gecko)/i // Gecko
  947. ], [VERSION, NAME]
  948. ],
  949. os : [[
  950. // Windows based
  951. /microsoft\s(windows)\s(vista|xp)/i // Windows (iTunes)
  952. ], [NAME, VERSION], [
  953. /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT
  954. /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
  955. ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
  956. /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
  957. ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
  958. // Mobile/Embedded OS
  959. /\((bb)(10);/i // BlackBerry 10
  960. ], [[NAME, 'BlackBerry'], VERSION], [
  961. /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry
  962. /(tizen)[\/\s]([\w\.]+)/i, // Tizen
  963. /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,
  964. // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki
  965. /linux;.+(sailfish);/i // Sailfish OS
  966. ], [NAME, VERSION], [
  967. /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian
  968. ], [[NAME, 'Symbian'], VERSION], [
  969. /\((series40);/i // Series 40
  970. ], [NAME], [
  971. /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS
  972. ], [[NAME, 'Firefox OS'], VERSION], [
  973. // Console
  974. /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation
  975. // GNU/Linux based
  976. /(mint)[\/\s\(]?(\w+)*/i, // Mint
  977. /(mageia|vectorlinux)[;\s]/i, // Mageia/VectorLinux
  978. /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,
  979. // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
  980. // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus
  981. /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux
  982. /(gnu)\s?([\w\.]+)*/i // GNU
  983. ], [NAME, VERSION], [
  984. /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS
  985. ], [[NAME, 'Chromium OS'], VERSION],[
  986. // Solaris
  987. /(sunos)\s?([\w\.]+\d)*/i // Solaris
  988. ], [[NAME, 'Solaris'], VERSION], [
  989. // BSD based
  990. /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
  991. ], [NAME, VERSION],[
  992. /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS
  993. ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
  994. /(mac\sos\sx)\s?([\w\s\.]+\w)*/i,
  995. /(macintosh|mac(?=_powerpc)\s)/i // Mac OS
  996. ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
  997. // Other
  998. /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i, // Solaris
  999. /(haiku)\s(\w+)/i, // Haiku
  1000. /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX
  1001. /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,
  1002. // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS
  1003. /(unix)\s?([\w\.]+)*/i // UNIX
  1004. ], [NAME, VERSION]
  1005. ]
  1006. };
  1007. /////////////////
  1008. // Constructor
  1009. ////////////////
  1010. var UAParser = function (uastring) {
  1011. var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
  1012. this.getBrowser = function () {
  1013. return mapper.rgx.apply(this, regexes.browser);
  1014. };
  1015. this.getEngine = function () {
  1016. return mapper.rgx.apply(this, regexes.engine);
  1017. };
  1018. this.getOS = function () {
  1019. return mapper.rgx.apply(this, regexes.os);
  1020. };
  1021. this.getResult = function() {
  1022. return {
  1023. ua : this.getUA(),
  1024. browser : this.getBrowser(),
  1025. engine : this.getEngine(),
  1026. os : this.getOS()
  1027. };
  1028. };
  1029. this.getUA = function () {
  1030. return ua;
  1031. };
  1032. this.setUA = function (uastring) {
  1033. ua = uastring;
  1034. return this;
  1035. };
  1036. this.setUA(ua);
  1037. };
  1038. return UAParser;
  1039. })();
  1040. function version_compare(v1, v2, operator) {
  1041. // From: http://phpjs.org/functions
  1042. // + original by: Philippe Jausions (http://pear.php.net/user/jausions)
  1043. // + original by: Aidan Lister (http://aidanlister.com/)
  1044. // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
  1045. // + improved by: Brett Zamir (http://brett-zamir.me)
  1046. // + improved by: Scott Baker
  1047. // + improved by: Theriault
  1048. // * example 1: version_compare('8.2.5rc', '8.2.5a');
  1049. // * returns 1: 1
  1050. // * example 2: version_compare('8.2.50', '8.2.52', '<');
  1051. // * returns 2: true
  1052. // * example 3: version_compare('5.3.0-dev', '5.3.0');
  1053. // * returns 3: -1
  1054. // * example 4: version_compare('4.1.0.52','4.01.0.51');
  1055. // * returns 4: 1
  1056. // Important: compare must be initialized at 0.
  1057. var i = 0,
  1058. x = 0,
  1059. compare = 0,
  1060. // vm maps textual PHP versions to negatives so they're less than 0.
  1061. // PHP currently defines these as CASE-SENSITIVE. It is important to
  1062. // leave these as negatives so that they can come before numerical versions
  1063. // and as if no letters were there to begin with.
  1064. // (1alpha is < 1 and < 1.1 but > 1dev1)
  1065. // If a non-numerical value can't be mapped to this table, it receives
  1066. // -7 as its value.
  1067. vm = {
  1068. 'dev': -6,
  1069. 'alpha': -5,
  1070. 'a': -5,
  1071. 'beta': -4,
  1072. 'b': -4,
  1073. 'RC': -3,
  1074. 'rc': -3,
  1075. '#': -2,
  1076. 'p': 1,
  1077. 'pl': 1
  1078. },
  1079. // This function will be called to prepare each version argument.
  1080. // It replaces every _, -, and + with a dot.
  1081. // It surrounds any nonsequence of numbers/dots with dots.
  1082. // It replaces sequences of dots with a single dot.
  1083. // version_compare('4..0', '4.0') == 0
  1084. // Important: A string of 0 length needs to be converted into a value
  1085. // even less than an unexisting value in vm (-7), hence [-8].
  1086. // It's also important to not strip spaces because of this.
  1087. // version_compare('', ' ') == 1
  1088. prepVersion = function (v) {
  1089. v = ('' + v).replace(/[_\-+]/g, '.');
  1090. v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
  1091. return (!v.length ? [-8] : v.split('.'));
  1092. },
  1093. // This converts a version component to a number.
  1094. // Empty component becomes 0.
  1095. // Non-numerical component becomes a negative number.
  1096. // Numerical component becomes itself as an integer.
  1097. numVersion = function (v) {
  1098. return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
  1099. };
  1100. v1 = prepVersion(v1);
  1101. v2 = prepVersion(v2);
  1102. x = Math.max(v1.length, v2.length);
  1103. for (i = 0; i < x; i++) {
  1104. if (v1[i] == v2[i]) {
  1105. continue;
  1106. }
  1107. v1[i] = numVersion(v1[i]);
  1108. v2[i] = numVersion(v2[i]);
  1109. if (v1[i] < v2[i]) {
  1110. compare = -1;
  1111. break;
  1112. } else if (v1[i] > v2[i]) {
  1113. compare = 1;
  1114. break;
  1115. }
  1116. }
  1117. if (!operator) {
  1118. return compare;
  1119. }
  1120. // Important: operator is CASE-SENSITIVE.
  1121. // "No operator" seems to be treated as "<."
  1122. // Any other values seem to make the function return null.
  1123. switch (operator) {
  1124. case '>':
  1125. case 'gt':
  1126. return (compare > 0);
  1127. case '>=':
  1128. case 'ge':
  1129. return (compare >= 0);
  1130. case '<=':
  1131. case 'le':
  1132. return (compare <= 0);
  1133. case '==':
  1134. case '=':
  1135. case 'eq':
  1136. return (compare === 0);
  1137. case '<>':
  1138. case '!=':
  1139. case 'ne':
  1140. return (compare !== 0);
  1141. case '':
  1142. case '<':
  1143. case 'lt':
  1144. return (compare < 0);
  1145. default:
  1146. return null;
  1147. }
  1148. }
  1149. var can = (function() {
  1150. var caps = {
  1151. access_global_ns: function () {
  1152. return !!window.moxie;
  1153. },
  1154. define_property: (function() {
  1155. /* // currently too much extra code required, not exactly worth it
  1156. try { // as of IE8, getters/setters are supported only on DOM elements
  1157. var obj = {};
  1158. if (Object.defineProperty) {
  1159. Object.defineProperty(obj, 'prop', {
  1160. enumerable: true,
  1161. configurable: true
  1162. });
  1163. return true;
  1164. }
  1165. } catch(ex) {}
  1166. if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
  1167. return true;
  1168. }*/
  1169. return false;
  1170. }()),
  1171. create_canvas: function() {
  1172. // On the S60 and BB Storm, getContext exists, but always returns undefined
  1173. // so we actually have to call getContext() to verify
  1174. // github.com/Modernizr/Modernizr/issues/issue/97/
  1175. var el = document.createElement('canvas');
  1176. var isSupported = !!(el.getContext && el.getContext('2d'));
  1177. caps.create_canvas = isSupported;
  1178. return isSupported;
  1179. },
  1180. return_response_type: function(responseType) {
  1181. try {
  1182. if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
  1183. return true;
  1184. } else if (window.XMLHttpRequest) {
  1185. var xhr = new XMLHttpRequest();
  1186. xhr.open('get', '/'); // otherwise Gecko throws an exception
  1187. if ('responseType' in xhr) {
  1188. xhr.responseType = responseType;
  1189. // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
  1190. if (xhr.responseType !== responseType) {
  1191. return false;
  1192. }
  1193. return true;
  1194. }
  1195. }
  1196. } catch (ex) {}
  1197. return false;
  1198. },
  1199. use_blob_uri: function() {
  1200. var URL = window.URL;
  1201. caps.use_blob_uri = (URL &&
  1202. 'createObjectURL' in URL &&
  1203. 'revokeObjectURL' in URL &&
  1204. (Env.browser !== 'IE' || Env.verComp(Env.version, '11.0.46', '>=')) // IE supports createObjectURL, but not fully, for example it fails to use it as a src for the image
  1205. );
  1206. return caps.use_blob_uri;
  1207. },
  1208. // ideas for this heavily come from Modernizr (http://modernizr.com/)
  1209. use_data_uri: (function() {
  1210. var du = new Image();
  1211. du.onload = function() {
  1212. caps.use_data_uri = (du.width === 1 && du.height === 1);
  1213. };
  1214. setTimeout(function() {
  1215. du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
  1216. }, 1);
  1217. return false;
  1218. }()),
  1219. use_data_uri_over32kb: function() { // IE8
  1220. return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
  1221. },
  1222. use_data_uri_of: function(bytes) {
  1223. return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
  1224. },
  1225. use_fileinput: function() {
  1226. if (navigator.userAgent.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))/)) {
  1227. return false;
  1228. }
  1229. var el = document.createElement('input');
  1230. el.setAttribute('type', 'file');
  1231. return caps.use_fileinput = !el.disabled;
  1232. },
  1233. use_webgl: function() {
  1234. var canvas = document.createElement('canvas');
  1235. var gl = null, isSupported;
  1236. try {
  1237. gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
  1238. }
  1239. catch(e) {}
  1240. if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context
  1241. gl = null;
  1242. }
  1243. isSupported = !!gl;
  1244. caps.use_webgl = isSupported; // save result of our check
  1245. canvas = undefined;
  1246. return isSupported;
  1247. }
  1248. };
  1249. return function(cap) {
  1250. var args = [].slice.call(arguments);
  1251. args.shift(); // shift of cap
  1252. return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap];
  1253. };
  1254. }());
  1255. var uaResult = new UAParser().getResult();
  1256. var Env = {
  1257. can: can,
  1258. uaParser: UAParser,
  1259. browser: uaResult.browser.name,
  1260. version: uaResult.browser.version,
  1261. os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason
  1262. osVersion: uaResult.os.version,
  1263. verComp: version_compare,
  1264. swf_url: "../flash/Moxie.swf",
  1265. xap_url: "../silverlight/Moxie.xap",
  1266. global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
  1267. };
  1268. // for backward compatibility
  1269. // @deprecated Use `Env.os` instead
  1270. Env.OS = Env.os;
  1271. if (MXI_DEBUG) {
  1272. Env.debug = {
  1273. runtime: true,
  1274. events: false
  1275. };
  1276. Env.log = function() {
  1277. function logObj(data) {
  1278. // TODO: this should recursively print out the object in a pretty way
  1279. console.appendChild(document.createTextNode(data + "\n"));
  1280. }
  1281. // if debugger present, IE8 might have window.console.log method, but not be able to apply on it (why...)
  1282. if (window && window.console && window.console.log && window.console.log.apply) {
  1283. window.console.log.apply(window.console, arguments);
  1284. } else if (document) {
  1285. var console = document.getElementById('moxie-console');
  1286. if (!console) {
  1287. console = document.createElement('pre');
  1288. console.id = 'moxie-console';
  1289. //console.style.display = 'none';
  1290. document.body.appendChild(console);
  1291. }
  1292. var data = arguments[0];
  1293. if (Basic.typeOf(data) === 'string') {
  1294. data = Basic.sprintf.apply(this, arguments);
  1295. } else if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
  1296. logObj(data);
  1297. return;
  1298. }
  1299. console.appendChild(document.createTextNode(data + "\n"));
  1300. }
  1301. };
  1302. }
  1303. return Env;
  1304. });
  1305. // Included from: src/javascript/core/Exceptions.js
  1306. /**
  1307. * Exceptions.js
  1308. *
  1309. * Copyright 2013, Moxiecode Systems AB
  1310. * Released under GPL License.
  1311. *
  1312. * License: http://www.plupload.com/license
  1313. * Contributing: http://www.plupload.com/contributing
  1314. */
  1315. define('moxie/core/Exceptions', [
  1316. 'moxie/core/utils/Basic'
  1317. ], function(Basic) {
  1318. function _findKey(obj, value) {
  1319. var key;
  1320. for (key in obj) {
  1321. if (obj[key] === value) {
  1322. return key;
  1323. }
  1324. }
  1325. return null;
  1326. }
  1327. /**
  1328. @class moxie/core/Exception
  1329. */
  1330. return {
  1331. RuntimeError: (function() {
  1332. var namecodes = {
  1333. NOT_INIT_ERR: 1,
  1334. EXCEPTION_ERR: 3,
  1335. NOT_SUPPORTED_ERR: 9,
  1336. JS_ERR: 4
  1337. };
  1338. function RuntimeError(code, message) {
  1339. this.code = code;
  1340. this.name = _findKey(namecodes, code);
  1341. this.message = this.name + (message || ": RuntimeError " + this.code);
  1342. }
  1343. Basic.extend(RuntimeError, namecodes);
  1344. RuntimeError.prototype = Error.prototype;
  1345. return RuntimeError;
  1346. }()),
  1347. OperationNotAllowedException: (function() {
  1348. function OperationNotAllowedException(code) {
  1349. this.code = code;
  1350. this.name = 'OperationNotAllowedException';
  1351. }
  1352. Basic.extend(OperationNotAllowedException, {
  1353. NOT_ALLOWED_ERR: 1
  1354. });
  1355. OperationNotAllowedException.prototype = Error.prototype;
  1356. return OperationNotAllowedException;
  1357. }()),
  1358. ImageError: (function() {
  1359. var namecodes = {
  1360. WRONG_FORMAT: 1,
  1361. MAX_RESOLUTION_ERR: 2,
  1362. INVALID_META_ERR: 3
  1363. };
  1364. function ImageError(code) {
  1365. this.code = code;
  1366. this.name = _findKey(namecodes, code);
  1367. this.message = this.name + ": ImageError " + this.code;
  1368. }
  1369. Basic.extend(ImageError, namecodes);
  1370. ImageError.prototype = Error.prototype;
  1371. return ImageError;
  1372. }()),
  1373. FileException: (function() {
  1374. var namecodes = {
  1375. NOT_FOUND_ERR: 1,
  1376. SECURITY_ERR: 2,
  1377. ABORT_ERR: 3,
  1378. NOT_READABLE_ERR: 4,
  1379. ENCODING_ERR: 5,
  1380. NO_MODIFICATION_ALLOWED_ERR: 6,
  1381. INVALID_STATE_ERR: 7,
  1382. SYNTAX_ERR: 8
  1383. };
  1384. function FileException(code) {
  1385. this.code = code;
  1386. this.name = _findKey(namecodes, code);
  1387. this.message = this.name + ": FileException " + this.code;
  1388. }
  1389. Basic.extend(FileException, namecodes);
  1390. FileException.prototype = Error.prototype;
  1391. return FileException;
  1392. }()),
  1393. DOMException: (function() {
  1394. var namecodes = {
  1395. INDEX_SIZE_ERR: 1,
  1396. DOMSTRING_SIZE_ERR: 2,
  1397. HIERARCHY_REQUEST_ERR: 3,
  1398. WRONG_DOCUMENT_ERR: 4,
  1399. INVALID_CHARACTER_ERR: 5,
  1400. NO_DATA_ALLOWED_ERR: 6,
  1401. NO_MODIFICATION_ALLOWED_ERR: 7,
  1402. NOT_FOUND_ERR: 8,
  1403. NOT_SUPPORTED_ERR: 9,
  1404. INUSE_ATTRIBUTE_ERR: 10,
  1405. INVALID_STATE_ERR: 11,
  1406. SYNTAX_ERR: 12,
  1407. INVALID_MODIFICATION_ERR: 13,
  1408. NAMESPACE_ERR: 14,
  1409. INVALID_ACCESS_ERR: 15,
  1410. VALIDATION_ERR: 16,
  1411. TYPE_MISMATCH_ERR: 17,
  1412. SECURITY_ERR: 18,
  1413. NETWORK_ERR: 19,
  1414. ABORT_ERR: 20,
  1415. URL_MISMATCH_ERR: 21,
  1416. QUOTA_EXCEEDED_ERR: 22,
  1417. TIMEOUT_ERR: 23,
  1418. INVALID_NODE_TYPE_ERR: 24,
  1419. DATA_CLONE_ERR: 25
  1420. };
  1421. function DOMException(code) {
  1422. this.code = code;
  1423. this.name = _findKey(namecodes, code);
  1424. this.message = this.name + ": DOMException " + this.code;
  1425. }
  1426. Basic.extend(DOMException, namecodes);
  1427. DOMException.prototype = Error.prototype;
  1428. return DOMException;
  1429. }()),
  1430. EventException: (function() {
  1431. function EventException(code) {
  1432. this.code = code;
  1433. this.name = 'EventException';
  1434. }
  1435. Basic.extend(EventException, {
  1436. UNSPECIFIED_EVENT_TYPE_ERR: 0
  1437. });
  1438. EventException.prototype = Error.prototype;
  1439. return EventException;
  1440. }())
  1441. };
  1442. });
  1443. // Included from: src/javascript/core/utils/Dom.js
  1444. /**
  1445. * Dom.js
  1446. *
  1447. * Copyright 2013, Moxiecode Systems AB
  1448. * Released under GPL License.
  1449. *
  1450. * License: http://www.plupload.com/license
  1451. * Contributing: http://www.plupload.com/contributing
  1452. */
  1453. /**
  1454. @class moxie/core/utils/Dom
  1455. @public
  1456. @static
  1457. */
  1458. define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
  1459. /**
  1460. Get DOM Element by it's id.
  1461. @method get
  1462. @param {String} id Identifier of the DOM Element
  1463. @return {DOMElement}
  1464. */
  1465. var get = function(id) {
  1466. if (typeof id !== 'string') {
  1467. return id;
  1468. }
  1469. return document.getElementById(id);
  1470. };
  1471. /**
  1472. Checks if specified DOM element has specified class.
  1473. @method hasClass
  1474. @static
  1475. @param {Object} obj DOM element like object to add handler to.
  1476. @param {String} name Class name
  1477. */
  1478. var hasClass = function(obj, name) {
  1479. if (!obj.className) {
  1480. return false;
  1481. }
  1482. var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
  1483. return regExp.test(obj.className);
  1484. };
  1485. /**
  1486. Adds specified className to specified DOM element.
  1487. @method addClass
  1488. @static
  1489. @param {Object} obj DOM element like object to add handler to.
  1490. @param {String} name Class name
  1491. */
  1492. var addClass = function(obj, name) {
  1493. if (!hasClass(obj, name)) {
  1494. obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
  1495. }
  1496. };
  1497. /**
  1498. Removes specified className from specified DOM element.
  1499. @method removeClass
  1500. @static
  1501. @param {Object} obj DOM element like object to add handler to.
  1502. @param {String} name Class name
  1503. */
  1504. var removeClass = function(obj, name) {
  1505. if (obj.className) {
  1506. var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
  1507. obj.className = obj.className.replace(regExp, function($0, $1, $2) {
  1508. return $1 === ' ' && $2 === ' ' ? ' ' : '';
  1509. });
  1510. }
  1511. };
  1512. /**
  1513. Returns a given computed style of a DOM element.
  1514. @method getStyle
  1515. @static
  1516. @param {Object} obj DOM element like object.
  1517. @param {String} name Style you want to get from the DOM element
  1518. */
  1519. var getStyle = function(obj, name) {
  1520. if (obj.currentStyle) {
  1521. return obj.currentStyle[name];
  1522. } else if (window.getComputedStyle) {
  1523. return window.getComputedStyle(obj, null)[name];
  1524. }
  1525. };
  1526. /**
  1527. Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
  1528. @method getPos
  1529. @static
  1530. @param {Element} node HTML element or element id to get x, y position from.
  1531. @param {Element} root Optional root element to stop calculations at.
  1532. @return {object} Absolute position of the specified element object with x, y fields.
  1533. */
  1534. var getPos = function(node, root) {
  1535. var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
  1536. node = node;
  1537. root = root || doc.body;
  1538. // Returns the x, y cordinate for an element on IE 6 and IE 7
  1539. function getIEPos(node) {
  1540. var bodyElm, rect, x = 0, y = 0;
  1541. if (node) {
  1542. rect = node.getBoundingClientRect();
  1543. bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
  1544. x = rect.left + bodyElm.scrollLeft;
  1545. y = rect.top + bodyElm.scrollTop;
  1546. }
  1547. return {
  1548. x : x,
  1549. y : y
  1550. };
  1551. }
  1552. // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
  1553. if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) {
  1554. nodeRect = getIEPos(node);
  1555. rootRect = getIEPos(root);
  1556. return {
  1557. x : nodeRect.x - rootRect.x,
  1558. y : nodeRect.y - rootRect.y
  1559. };
  1560. }
  1561. parent = node;
  1562. while (parent && parent != root && parent.nodeType) {
  1563. x += parent.offsetLeft || 0;
  1564. y += parent.offsetTop || 0;
  1565. parent = parent.offsetParent;
  1566. }
  1567. parent = node.parentNode;
  1568. while (parent && parent != root && parent.nodeType) {
  1569. x -= parent.scrollLeft || 0;
  1570. y -= parent.scrollTop || 0;
  1571. parent = parent.parentNode;
  1572. }
  1573. return {
  1574. x : x,
  1575. y : y
  1576. };
  1577. };
  1578. /**
  1579. Returns the size of the specified node in pixels.
  1580. @method getSize
  1581. @static
  1582. @param {Node} node Node to get the size of.
  1583. @return {Object} Object with a w and h property.
  1584. */
  1585. var getSize = function(node) {
  1586. return {
  1587. w : node.offsetWidth || node.clientWidth,
  1588. h : node.offsetHeight || node.clientHeight
  1589. };
  1590. };
  1591. return {
  1592. get: get,
  1593. hasClass: hasClass,
  1594. addClass: addClass,
  1595. removeClass: removeClass,
  1596. getStyle: getStyle,
  1597. getPos: getPos,
  1598. getSize: getSize
  1599. };
  1600. });
  1601. // Included from: src/javascript/core/EventTarget.js
  1602. /**
  1603. * EventTarget.js
  1604. *
  1605. * Copyright 2013, Moxiecode Systems AB
  1606. * Released under GPL License.
  1607. *
  1608. * License: http://www.plupload.com/license
  1609. * Contributing: http://www.plupload.com/contributing
  1610. */
  1611. define('moxie/core/EventTarget', [
  1612. 'moxie/core/utils/Env',
  1613. 'moxie/core/Exceptions',
  1614. 'moxie/core/utils/Basic'
  1615. ], function(Env, x, Basic) {
  1616. // hash of event listeners by object uid
  1617. var eventpool = {};
  1618. /**
  1619. Parent object for all event dispatching components and objects
  1620. @class moxie/core/EventTarget
  1621. @constructor EventTarget
  1622. */
  1623. function EventTarget() {
  1624. /**
  1625. Unique id of the event dispatcher, usually overriden by children
  1626. @property uid
  1627. @type String
  1628. */
  1629. this.uid = Basic.guid();
  1630. }
  1631. Basic.extend(EventTarget.prototype, {
  1632. /**
  1633. Can be called from within a child in order to acquire uniqie id in automated manner
  1634. @method init
  1635. */
  1636. init: function() {
  1637. if (!this.uid) {
  1638. this.uid = Basic.guid('uid_');
  1639. }
  1640. },
  1641. /**
  1642. Register a handler to a specific event dispatched by the object
  1643. @method addEventListener
  1644. @param {String} type Type or basically a name of the event to subscribe to
  1645. @param {Function} fn Callback function that will be called when event happens
  1646. @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
  1647. @param {Object} [scope=this] A scope to invoke event handler in
  1648. */
  1649. addEventListener: function(type, fn, priority, scope) {
  1650. var self = this, list;
  1651. // without uid no event handlers can be added, so make sure we got one
  1652. if (!this.hasOwnProperty('uid')) {
  1653. this.uid = Basic.guid('uid_');
  1654. }
  1655. type = Basic.trim(type);
  1656. if (/\s/.test(type)) {
  1657. // multiple event types were passed for one handler
  1658. Basic.each(type.split(/\s+/), function(type) {
  1659. self.addEventListener(type, fn, priority, scope);
  1660. });
  1661. return;
  1662. }
  1663. type = type.toLowerCase();
  1664. priority = parseInt(priority, 10) || 0;
  1665. list = eventpool[this.uid] && eventpool[this.uid][type] || [];
  1666. list.push({fn : fn, priority : priority, scope : scope || this});
  1667. if (!eventpool[this.uid]) {
  1668. eventpool[this.uid] = {};
  1669. }
  1670. eventpool[this.uid][type] = list;
  1671. },
  1672. /**
  1673. Check if any handlers were registered to the specified event
  1674. @method hasEventListener
  1675. @param {String} [type] Type or basically a name of the event to check
  1676. @return {Mixed} Returns a handler if it was found and false, if - not
  1677. */
  1678. hasEventListener: function(type) {
  1679. var list;
  1680. if (type) {
  1681. type = type.toLowerCase();
  1682. list = eventpool[this.uid] && eventpool[this.uid][type];
  1683. } else {
  1684. list = eventpool[this.uid];
  1685. }
  1686. return list ? list : false;
  1687. },
  1688. /**
  1689. Unregister the handler from the event, or if former was not specified - unregister all handlers
  1690. @method removeEventListener
  1691. @param {String} type Type or basically a name of the event
  1692. @param {Function} [fn] Handler to unregister
  1693. */
  1694. removeEventListener: function(type, fn) {
  1695. var self = this, list, i;
  1696. type = type.toLowerCase();
  1697. if (/\s/.test(type)) {
  1698. // multiple event types were passed for one handler
  1699. Basic.each(type.split(/\s+/), function(type) {
  1700. self.removeEventListener(type, fn);
  1701. });
  1702. return;
  1703. }
  1704. list = eventpool[this.uid] && eventpool[this.uid][type];
  1705. if (list) {
  1706. if (fn) {
  1707. for (i = list.length - 1; i >= 0; i--) {
  1708. if (list[i].fn === fn) {
  1709. list.splice(i, 1);
  1710. break;
  1711. }
  1712. }
  1713. } else {
  1714. list = [];
  1715. }
  1716. // delete event list if it has become empty
  1717. if (!list.length) {
  1718. delete eventpool[this.uid][type];
  1719. // and object specific entry in a hash if it has no more listeners attached
  1720. if (Basic.isEmptyObj(eventpool[this.uid])) {
  1721. delete eventpool[this.uid];
  1722. }
  1723. }
  1724. }
  1725. },
  1726. /**
  1727. Remove all event handlers from the object
  1728. @method removeAllEventListeners
  1729. */
  1730. removeAllEventListeners: function() {
  1731. if (eventpool[this.uid]) {
  1732. delete eventpool[this.uid];
  1733. }
  1734. },
  1735. /**
  1736. Dispatch the event
  1737. @method dispatchEvent
  1738. @param {String/Object} Type of event or event object to dispatch
  1739. @param {Mixed} [...] Variable number of arguments to be passed to a handlers
  1740. @return {Boolean} true by default and false if any handler returned false
  1741. */
  1742. dispatchEvent: function(type) {
  1743. var uid, list, args, tmpEvt, evt = {}, result = true, undef;
  1744. if (Basic.typeOf(type) !== 'string') {
  1745. // we can't use original object directly (because of Silverlight)
  1746. tmpEvt = type;
  1747. if (Basic.typeOf(tmpEvt.type) === 'string') {
  1748. type = tmpEvt.type;
  1749. if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
  1750. evt.total = tmpEvt.total;
  1751. evt.loaded = tmpEvt.loaded;
  1752. }
  1753. evt.async = tmpEvt.async || false;
  1754. } else {
  1755. throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
  1756. }
  1757. }
  1758. // check if event is meant to be dispatched on an object having specific uid
  1759. if (type.indexOf('::') !== -1) {
  1760. (function(arr) {
  1761. uid = arr[0];
  1762. type = arr[1];
  1763. }(type.split('::')));
  1764. } else {
  1765. uid = this.uid;
  1766. }
  1767. type = type.toLowerCase();
  1768. list = eventpool[uid] && eventpool[uid][type];
  1769. if (list) {
  1770. // sort event list by prority
  1771. list.sort(function(a, b) { return b.priority - a.priority; });
  1772. args = [].slice.call(arguments);
  1773. // first argument will be pseudo-event object
  1774. args.shift();
  1775. evt.type = type;
  1776. args.unshift(evt);
  1777. if (MXI_DEBUG && Env.debug.events) {
  1778. Env.log("%cEvent '%s' fired on %s", 'color: #999;', evt.type, (this.ctorName ? this.ctorName + '::' : '') + uid);
  1779. }
  1780. // Dispatch event to all listeners
  1781. var queue = [];
  1782. Basic.each(list, function(handler) {
  1783. // explicitly set the target, otherwise events fired from shims do not get it
  1784. args[0].target = handler.scope;
  1785. // if event is marked as async, detach the handler
  1786. if (evt.async) {
  1787. queue.push(function(cb) {
  1788. setTimeout(function() {
  1789. cb(handler.fn.apply(handler.scope, args) === false);
  1790. }, 1);
  1791. });
  1792. } else {
  1793. queue.push(function(cb) {
  1794. cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
  1795. });
  1796. }
  1797. });
  1798. if (queue.length) {
  1799. Basic.inSeries(queue, function(err) {
  1800. result = !err;
  1801. });
  1802. }
  1803. }
  1804. return result;
  1805. },
  1806. /**
  1807. Register a handler to the event type that will run only once
  1808. @method bindOnce
  1809. @since >1.4.1
  1810. @param {String} type Type or basically a name of the event to subscribe to
  1811. @param {Function} fn Callback function that will be called when event happens
  1812. @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
  1813. @param {Object} [scope=this] A scope to invoke event handler in
  1814. */
  1815. bindOnce: function(type, fn, priority, scope) {
  1816. var self = this;
  1817. self.bind.call(this, type, function cb() {
  1818. self.unbind(type, cb);
  1819. return fn.apply(this, arguments);
  1820. }, priority, scope);
  1821. },
  1822. /**
  1823. Alias for addEventListener
  1824. @method bind
  1825. @protected
  1826. */
  1827. bind: function() {
  1828. this.addEventListener.apply(this, arguments);
  1829. },
  1830. /**
  1831. Alias for removeEventListener
  1832. @method unbind
  1833. @protected
  1834. */
  1835. unbind: function() {
  1836. this.removeEventListener.apply(this, arguments);
  1837. },
  1838. /**
  1839. Alias for removeAllEventListeners
  1840. @method unbindAll
  1841. @protected
  1842. */
  1843. unbindAll: function() {
  1844. this.removeAllEventListeners.apply(this, arguments);
  1845. },
  1846. /**
  1847. Alias for dispatchEvent
  1848. @method trigger
  1849. @protected
  1850. */
  1851. trigger: function() {
  1852. return this.dispatchEvent.apply(this, arguments);
  1853. },
  1854. /**
  1855. Handle properties of on[event] type.
  1856. @method handleEventProps
  1857. @private
  1858. */
  1859. handleEventProps: function(dispatches) {
  1860. var self = this;
  1861. this.bind(dispatches.join(' '), function(e) {
  1862. var prop = 'on' + e.type.toLowerCase();
  1863. if (Basic.typeOf(this[prop]) === 'function') {
  1864. this[prop].apply(this, arguments);
  1865. }
  1866. });
  1867. // object must have defined event properties, even if it doesn't make use of them
  1868. Basic.each(dispatches, function(prop) {
  1869. prop = 'on' + prop.toLowerCase(prop);
  1870. if (Basic.typeOf(self[prop]) === 'undefined') {
  1871. self[prop] = null;
  1872. }
  1873. });
  1874. }
  1875. });
  1876. EventTarget.instance = new EventTarget();
  1877. return EventTarget;
  1878. });
  1879. // Included from: src/javascript/runtime/Runtime.js
  1880. /**
  1881. * Runtime.js
  1882. *
  1883. * Copyright 2013, Moxiecode Systems AB
  1884. * Released under GPL License.
  1885. *
  1886. * License: http://www.plupload.com/license
  1887. * Contributing: http://www.plupload.com/contributing
  1888. */
  1889. define('moxie/runtime/Runtime', [
  1890. "moxie/core/utils/Env",
  1891. "moxie/core/utils/Basic",
  1892. "moxie/core/utils/Dom",
  1893. "moxie/core/EventTarget"
  1894. ], function(Env, Basic, Dom, EventTarget) {
  1895. var runtimeConstructors = {}, runtimes = {};
  1896. /**
  1897. Common set of methods and properties for every runtime instance
  1898. @class moxie/runtime/Runtime
  1899. @param {Object} options
  1900. @param {String} type Sanitized name of the runtime
  1901. @param {Object} [caps] Set of capabilities that differentiate specified runtime
  1902. @param {Object} [modeCaps] Set of capabilities that do require specific operational mode
  1903. @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested
  1904. */
  1905. function Runtime(options, type, caps, modeCaps, preferredMode) {
  1906. /**
  1907. Dispatched when runtime is initialized and ready.
  1908. Results in RuntimeInit on a connected component.
  1909. @event Init
  1910. */
  1911. /**
  1912. Dispatched when runtime fails to initialize.
  1913. Results in RuntimeError on a connected component.
  1914. @event Error
  1915. */
  1916. var self = this
  1917. , _shim
  1918. , _uid = Basic.guid(type + '_')
  1919. , defaultMode = preferredMode || 'browser'
  1920. ;
  1921. options = options || {};
  1922. // register runtime in private hash
  1923. runtimes[_uid] = this;
  1924. /**
  1925. Default set of capabilities, which can be redifined later by specific runtime
  1926. @private
  1927. @property caps
  1928. @type Object
  1929. */
  1930. caps = Basic.extend({
  1931. // Runtime can:
  1932. // provide access to raw binary data of the file
  1933. access_binary: false,
  1934. // provide access to raw binary data of the image (image extension is optional)
  1935. access_image_binary: false,
  1936. // display binary data as thumbs for example
  1937. display_media: false,
  1938. // make cross-domain requests
  1939. do_cors: false,
  1940. // accept files dragged and dropped from the desktop
  1941. drag_and_drop: false,
  1942. // filter files in selection dialog by their extensions
  1943. filter_by_extension: true,
  1944. // resize image (and manipulate it raw data of any file in general)
  1945. resize_image: false,
  1946. // periodically report how many bytes of total in the file were uploaded (loaded)
  1947. report_upload_progress: false,
  1948. // provide access to the headers of http response
  1949. return_response_headers: false,
  1950. // support response of specific type, which should be passed as an argument
  1951. // e.g. runtime.can('return_response_type', 'blob')
  1952. return_response_type: false,
  1953. // return http status code of the response
  1954. return_status_code: true,
  1955. // send custom http header with the request
  1956. send_custom_headers: false,
  1957. // pick up the files from a dialog
  1958. select_file: false,
  1959. // select whole folder in file browse dialog
  1960. select_folder: false,
  1961. // select multiple files at once in file browse dialog
  1962. select_multiple: true,
  1963. // send raw binary data, that is generated after image resizing or manipulation of other kind
  1964. send_binary_string: false,
  1965. // send cookies with http request and therefore retain session
  1966. send_browser_cookies: true,
  1967. // send data formatted as multipart/form-data
  1968. send_multipart: true,
  1969. // slice the file or blob to smaller parts
  1970. slice_blob: false,
  1971. // upload file without preloading it to memory, stream it out directly from disk
  1972. stream_upload: false,
  1973. // programmatically trigger file browse dialog
  1974. summon_file_dialog: false,
  1975. // upload file of specific size, size should be passed as argument
  1976. // e.g. runtime.can('upload_filesize', '500mb')
  1977. upload_filesize: true,
  1978. // initiate http request with specific http method, method should be passed as argument
  1979. // e.g. runtime.can('use_http_method', 'put')
  1980. use_http_method: true
  1981. }, caps);
  1982. // default to the mode that is compatible with preferred caps
  1983. if (options.preferred_caps) {
  1984. defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode);
  1985. }
  1986. if (MXI_DEBUG && Env.debug.runtime) {
  1987. Env.log("\tdefault mode: %s", defaultMode);
  1988. }
  1989. // small extension factory here (is meant to be extended with actual extensions constructors)
  1990. _shim = (function() {
  1991. var objpool = {};
  1992. return {
  1993. exec: function(uid, comp, fn, args) {
  1994. if (_shim[comp]) {
  1995. if (!objpool[uid]) {
  1996. objpool[uid] = {
  1997. context: this,
  1998. instance: new _shim[comp]()
  1999. };
  2000. }
  2001. if (objpool[uid].instance[fn]) {
  2002. return objpool[uid].instance[fn].apply(this, args);
  2003. }
  2004. }
  2005. },
  2006. removeInstance: function(uid) {
  2007. delete objpool[uid];
  2008. },
  2009. removeAllInstances: function() {
  2010. var self = this;
  2011. Basic.each(objpool, function(obj, uid) {
  2012. if (Basic.typeOf(obj.instance.destroy) === 'function') {
  2013. obj.instance.destroy.call(obj.context);
  2014. }
  2015. self.removeInstance(uid);
  2016. });
  2017. }
  2018. };
  2019. }());
  2020. // public methods
  2021. Basic.extend(this, {
  2022. /**
  2023. Specifies whether runtime instance was initialized or not
  2024. @property initialized
  2025. @type {Boolean}
  2026. @default false
  2027. */
  2028. initialized: false, // shims require this flag to stop initialization retries
  2029. /**
  2030. Unique ID of the runtime
  2031. @property uid
  2032. @type {String}
  2033. */
  2034. uid: _uid,
  2035. /**
  2036. Runtime type (e.g. flash, html5, etc)
  2037. @property type
  2038. @type {String}
  2039. */
  2040. type: type,
  2041. /**
  2042. Runtime (not native one) may operate in browser or client mode.
  2043. @property mode
  2044. @private
  2045. @type {String|Boolean} current mode or false, if none possible
  2046. */
  2047. mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode),
  2048. /**
  2049. id of the DOM container for the runtime (if available)
  2050. @property shimid
  2051. @type {String}
  2052. */
  2053. shimid: _uid + '_container',
  2054. /**
  2055. Number of connected clients. If equal to zero, runtime can be destroyed
  2056. @property clients
  2057. @type {Number}
  2058. */
  2059. clients: 0,
  2060. /**
  2061. Runtime initialization options
  2062. @property options
  2063. @type {Object}
  2064. */
  2065. options: options,
  2066. /**
  2067. Checks if the runtime has specific capability
  2068. @method can
  2069. @param {String} cap Name of capability to check
  2070. @param {Mixed} [value] If passed, capability should somehow correlate to the value
  2071. @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set)
  2072. @return {Boolean} true if runtime has such capability and false, if - not
  2073. */
  2074. can: function(cap, value) {
  2075. var refCaps = arguments[2] || caps;
  2076. // if cap var is a comma-separated list of caps, convert it to object (key/value)
  2077. if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') {
  2078. cap = Runtime.parseCaps(cap);
  2079. }
  2080. if (Basic.typeOf(cap) === 'object') {
  2081. for (var key in cap) {
  2082. if (!this.can(key, cap[key], refCaps)) {
  2083. return false;
  2084. }
  2085. }
  2086. return true;
  2087. }
  2088. // check the individual cap
  2089. if (Basic.typeOf(refCaps[cap]) === 'function') {
  2090. return refCaps[cap].call(this, value);
  2091. } else {
  2092. return (value === refCaps[cap]);
  2093. }
  2094. },
  2095. /**
  2096. Returns container for the runtime as DOM element
  2097. @method getShimContainer
  2098. @return {DOMElement}
  2099. */
  2100. getShimContainer: function() {
  2101. var container, shimContainer = Dom.get(this.shimid);
  2102. // if no container for shim, create one
  2103. if (!shimContainer) {
  2104. container = Dom.get(this.options.container) || document.body;
  2105. // create shim container and insert it at an absolute position into the outer container
  2106. shimContainer = document.createElement('div');
  2107. shimContainer.id = this.shimid;
  2108. shimContainer.className = 'moxie-shim moxie-shim-' + this.type;
  2109. Basic.extend(shimContainer.style, {
  2110. position: 'absolute',
  2111. top: '0px',
  2112. left: '0px',
  2113. width: '1px',
  2114. height: '1px',
  2115. overflow: 'hidden'
  2116. });
  2117. container.appendChild(shimContainer);
  2118. container = null;
  2119. }
  2120. return shimContainer;
  2121. },
  2122. /**
  2123. Returns runtime as DOM element (if appropriate)
  2124. @method getShim
  2125. @return {DOMElement}
  2126. */
  2127. getShim: function() {
  2128. return _shim;
  2129. },
  2130. /**
  2131. Invokes a method within the runtime itself (might differ across the runtimes)
  2132. @method shimExec
  2133. @param {Mixed} []
  2134. @protected
  2135. @return {Mixed} Depends on the action and component
  2136. */
  2137. shimExec: function(component, action) {
  2138. var args = [].slice.call(arguments, 2);
  2139. return self.getShim().exec.call(this, this.uid, component, action, args);
  2140. },
  2141. /**
  2142. Operaional interface that is used by components to invoke specific actions on the runtime
  2143. (is invoked in the scope of component)
  2144. @method exec
  2145. @param {Mixed} []*
  2146. @protected
  2147. @return {Mixed} Depends on the action and component
  2148. */
  2149. exec: function(component, action) { // this is called in the context of component, not runtime
  2150. var args = [].slice.call(arguments, 2);
  2151. if (self[component] && self[component][action]) {
  2152. return self[component][action].apply(this, args);
  2153. }
  2154. return self.shimExec.apply(this, arguments);
  2155. },
  2156. /**
  2157. Destroys the runtime (removes all events and deletes DOM structures)
  2158. @method destroy
  2159. */
  2160. destroy: function() {
  2161. if (!self) {
  2162. return; // obviously already destroyed
  2163. }
  2164. var shimContainer = Dom.get(this.shimid);
  2165. if (shimContainer) {
  2166. shimContainer.parentNode.removeChild(shimContainer);
  2167. }
  2168. if (_shim) {
  2169. _shim.removeAllInstances();
  2170. }
  2171. this.unbindAll();
  2172. delete runtimes[this.uid];
  2173. this.uid = null; // mark this runtime as destroyed
  2174. _uid = self = _shim = shimContainer = null;
  2175. }
  2176. });
  2177. // once we got the mode, test against all caps
  2178. if (this.mode && options.required_caps && !this.can(options.required_caps)) {
  2179. this.mode = false;
  2180. }
  2181. }
  2182. /**
  2183. Default order to try different runtime types
  2184. @property order
  2185. @type String
  2186. @static
  2187. */
  2188. Runtime.order = 'html5,flash,silverlight,html4';
  2189. /**
  2190. Retrieves runtime from private hash by it's uid
  2191. @method getRuntime
  2192. @private
  2193. @static
  2194. @param {String} uid Unique identifier of the runtime
  2195. @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not
  2196. */
  2197. Runtime.getRuntime = function(uid) {
  2198. return runtimes[uid] ? runtimes[uid] : false;
  2199. };
  2200. /**
  2201. Register constructor for the Runtime of new (or perhaps modified) type
  2202. @method addConstructor
  2203. @static
  2204. @param {String} type Runtime type (e.g. flash, html5, etc)
  2205. @param {Function} construct Constructor for the Runtime type
  2206. */
  2207. Runtime.addConstructor = function(type, constructor) {
  2208. constructor.prototype = EventTarget.instance;
  2209. runtimeConstructors[type] = constructor;
  2210. };
  2211. /**
  2212. Get the constructor for the specified type.
  2213. method getConstructor
  2214. @static
  2215. @param {String} type Runtime type (e.g. flash, html5, etc)
  2216. @return {Function} Constructor for the Runtime type
  2217. */
  2218. Runtime.getConstructor = function(type) {
  2219. return runtimeConstructors[type] || null;
  2220. };
  2221. /**
  2222. Get info about the runtime (uid, type, capabilities)
  2223. @method getInfo
  2224. @static
  2225. @param {String} uid Unique identifier of the runtime
  2226. @return {Mixed} Info object or null if runtime doesn't exist
  2227. */
  2228. Runtime.getInfo = function(uid) {
  2229. var runtime = Runtime.getRuntime(uid);
  2230. if (runtime) {
  2231. return {
  2232. uid: runtime.uid,
  2233. type: runtime.type,
  2234. mode: runtime.mode,
  2235. can: function() {
  2236. return runtime.can.apply(runtime, arguments);
  2237. }
  2238. };
  2239. }
  2240. return null;
  2241. };
  2242. /**
  2243. Convert caps represented by a comma-separated string to the object representation.
  2244. @method parseCaps
  2245. @static
  2246. @param {String} capStr Comma-separated list of capabilities
  2247. @return {Object}
  2248. */
  2249. Runtime.parseCaps = function(capStr) {
  2250. var capObj = {};
  2251. if (Basic.typeOf(capStr) !== 'string') {
  2252. return capStr || {};
  2253. }
  2254. Basic.each(capStr.split(','), function(key) {
  2255. capObj[key] = true; // we assume it to be - true
  2256. });
  2257. return capObj;
  2258. };
  2259. /**
  2260. Test the specified runtime for specific capabilities.
  2261. @method can
  2262. @static
  2263. @param {String} type Runtime type (e.g. flash, html5, etc)
  2264. @param {String|Object} caps Set of capabilities to check
  2265. @return {Boolean} Result of the test
  2266. */
  2267. Runtime.can = function(type, caps) {
  2268. var runtime
  2269. , constructor = Runtime.getConstructor(type)
  2270. , mode
  2271. ;
  2272. if (constructor) {
  2273. runtime = new constructor({
  2274. required_caps: caps
  2275. });
  2276. mode = runtime.mode;
  2277. runtime.destroy();
  2278. return !!mode;
  2279. }
  2280. return false;
  2281. };
  2282. /**
  2283. Figure out a runtime that supports specified capabilities.
  2284. @method thatCan
  2285. @static
  2286. @param {String|Object} caps Set of capabilities to check
  2287. @param {String} [runtimeOrder] Comma-separated list of runtimes to check against
  2288. @return {String} Usable runtime identifier or null
  2289. */
  2290. Runtime.thatCan = function(caps, runtimeOrder) {
  2291. var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/);
  2292. for (var i in types) {
  2293. if (Runtime.can(types[i], caps)) {
  2294. return types[i];
  2295. }
  2296. }
  2297. return null;
  2298. };
  2299. /**
  2300. Figure out an operational mode for the specified set of capabilities.
  2301. @method getMode
  2302. @static
  2303. @param {Object} modeCaps Set of capabilities that depend on particular runtime mode
  2304. @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
  2305. @param {String|Boolean} [defaultMode='browser'] Default mode to use
  2306. @return {String|Boolean} Compatible operational mode
  2307. */
  2308. Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
  2309. var mode = null;
  2310. if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
  2311. defaultMode = 'browser';
  2312. }
  2313. if (requiredCaps && !Basic.isEmptyObj(modeCaps)) {
  2314. // loop over required caps and check if they do require the same mode
  2315. Basic.each(requiredCaps, function(value, cap) {
  2316. if (modeCaps.hasOwnProperty(cap)) {
  2317. var capMode = modeCaps[cap](value);
  2318. // make sure we always have an array
  2319. if (typeof(capMode) === 'string') {
  2320. capMode = [capMode];
  2321. }
  2322. if (!mode) {
  2323. mode = capMode;
  2324. } else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
  2325. // if cap requires conflicting mode - runtime cannot fulfill required caps
  2326. if (MXI_DEBUG && Env.debug.runtime) {
  2327. Env.log("\t\t%s: %s (conflicting mode requested: %s)", cap, value, capMode);
  2328. }
  2329. return (mode = false);
  2330. }
  2331. }
  2332. if (MXI_DEBUG && Env.debug.runtime) {
  2333. Env.log("\t\t%s: %s (compatible modes: %s)", cap, value, mode);
  2334. }
  2335. });
  2336. if (mode) {
  2337. return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
  2338. } else if (mode === false) {
  2339. return false;
  2340. }
  2341. }
  2342. return defaultMode;
  2343. };
  2344. /**
  2345. * Third party shims (Flash and Silverlight) require global event target against which they
  2346. * will fire their events. However when moxie is not loaded to global namespace, default
  2347. * event target is not accessible and we have to create artificial ones.
  2348. *
  2349. * @method getGlobalEventTarget
  2350. * @static
  2351. * @return {String} Name of the global event target
  2352. */
  2353. Runtime.getGlobalEventTarget = function() {
  2354. if (/^moxie\./.test(Env.global_event_dispatcher) && !Env.can('access_global_ns')) {
  2355. var uniqueCallbackName = Basic.guid('moxie_event_target_');
  2356. window[uniqueCallbackName] = function(e, data) {
  2357. EventTarget.instance.dispatchEvent(e, data);
  2358. };
  2359. Env.global_event_dispatcher = uniqueCallbackName;
  2360. }
  2361. return Env.global_event_dispatcher;
  2362. };
  2363. /**
  2364. Capability check that always returns true
  2365. @private
  2366. @static
  2367. @return {True}
  2368. */
  2369. Runtime.capTrue = function() {
  2370. return true;
  2371. };
  2372. /**
  2373. Capability check that always returns false
  2374. @private
  2375. @static
  2376. @return {False}
  2377. */
  2378. Runtime.capFalse = function() {
  2379. return false;
  2380. };
  2381. /**
  2382. Evaluate the expression to boolean value and create a function that always returns it.
  2383. @private
  2384. @static
  2385. @param {Mixed} expr Expression to evaluate
  2386. @return {Function} Function returning the result of evaluation
  2387. */
  2388. Runtime.capTest = function(expr) {
  2389. return function() {
  2390. return !!expr;
  2391. };
  2392. };
  2393. return Runtime;
  2394. });
  2395. // Included from: src/javascript/runtime/RuntimeClient.js
  2396. /**
  2397. * RuntimeClient.js
  2398. *
  2399. * Copyright 2013, Moxiecode Systems AB
  2400. * Released under GPL License.
  2401. *
  2402. * License: http://www.plupload.com/license
  2403. * Contributing: http://www.plupload.com/contributing
  2404. */
  2405. define('moxie/runtime/RuntimeClient', [
  2406. 'moxie/core/utils/Env',
  2407. 'moxie/core/Exceptions',
  2408. 'moxie/core/utils/Basic',
  2409. 'moxie/runtime/Runtime'
  2410. ], function(Env, x, Basic, Runtime) {
  2411. /**
  2412. Set of methods and properties, required by a component to acquire ability to connect to a runtime
  2413. @class moxie/runtime/RuntimeClient
  2414. */
  2415. return function RuntimeClient() {
  2416. var runtime;
  2417. Basic.extend(this, {
  2418. /**
  2419. Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one.
  2420. Increments number of clients connected to the specified runtime.
  2421. @private
  2422. @method connectRuntime
  2423. @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites
  2424. */
  2425. connectRuntime: function(options) {
  2426. var comp = this, ruid;
  2427. function initialize(items) {
  2428. var type, constructor;
  2429. // if we ran out of runtimes
  2430. if (!items.length) {
  2431. comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
  2432. runtime = null;
  2433. return;
  2434. }
  2435. type = items.shift().toLowerCase();
  2436. constructor = Runtime.getConstructor(type);
  2437. if (!constructor) {
  2438. if (MXI_DEBUG && Env.debug.runtime) {
  2439. Env.log("Constructor for '%s' runtime is not available.", type);
  2440. }
  2441. initialize(items);
  2442. return;
  2443. }
  2444. if (MXI_DEBUG && Env.debug.runtime) {
  2445. Env.log("Trying runtime: %s", type);
  2446. Env.log(options);
  2447. }
  2448. // try initializing the runtime
  2449. runtime = new constructor(options);
  2450. runtime.bind('Init', function() {
  2451. // mark runtime as initialized
  2452. runtime.initialized = true;
  2453. if (MXI_DEBUG && Env.debug.runtime) {
  2454. Env.log("Runtime '%s' initialized", runtime.type);
  2455. }
  2456. // jailbreak ...
  2457. setTimeout(function() {
  2458. runtime.clients++;
  2459. comp.ruid = runtime.uid;
  2460. // this will be triggered on component
  2461. comp.trigger('RuntimeInit', runtime);
  2462. }, 1);
  2463. });
  2464. runtime.bind('Error', function() {
  2465. if (MXI_DEBUG && Env.debug.runtime) {
  2466. Env.log("Runtime '%s' failed to initialize", runtime.type);
  2467. }
  2468. runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here
  2469. initialize(items);
  2470. });
  2471. runtime.bind('Exception', function(e, err) {
  2472. var message = err.name + "(#" + err.code + ")" + (err.message ? ", from: " + err.message : '');
  2473. if (MXI_DEBUG && Env.debug.runtime) {
  2474. Env.log("Runtime '%s' has thrown an exception: %s", this.type, message);
  2475. }
  2476. comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.EXCEPTION_ERR, message));
  2477. });
  2478. if (MXI_DEBUG && Env.debug.runtime) {
  2479. Env.log("\tselected mode: %s", runtime.mode);
  2480. }
  2481. // check if runtime managed to pick-up operational mode
  2482. if (!runtime.mode) {
  2483. runtime.trigger('Error');
  2484. return;
  2485. }
  2486. runtime.init();
  2487. }
  2488. // check if a particular runtime was requested
  2489. if (Basic.typeOf(options) === 'string') {
  2490. ruid = options;
  2491. } else if (Basic.typeOf(options.ruid) === 'string') {
  2492. ruid = options.ruid;
  2493. }
  2494. if (ruid) {
  2495. runtime = Runtime.getRuntime(ruid);
  2496. if (runtime) {
  2497. comp.ruid = ruid;
  2498. runtime.clients++;
  2499. return runtime;
  2500. } else {
  2501. // there should be a runtime and there's none - weird case
  2502. throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR);
  2503. }
  2504. }
  2505. // initialize a fresh one, that fits runtime list and required features best
  2506. initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/));
  2507. },
  2508. /**
  2509. Disconnects from the runtime. Decrements number of clients connected to the specified runtime.
  2510. @private
  2511. @method disconnectRuntime
  2512. */
  2513. disconnectRuntime: function() {
  2514. if (runtime && --runtime.clients <= 0) {
  2515. runtime.destroy();
  2516. }
  2517. // once the component is disconnected, it shouldn't have access to the runtime
  2518. runtime = null;
  2519. },
  2520. /**
  2521. Returns the runtime to which the client is currently connected.
  2522. @method getRuntime
  2523. @return {Runtime} Runtime or null if client is not connected
  2524. */
  2525. getRuntime: function() {
  2526. if (runtime && runtime.uid) {
  2527. return runtime;
  2528. }
  2529. return runtime = null; // make sure we do not leave zombies rambling around
  2530. },
  2531. /**
  2532. Handy shortcut to safely invoke runtime extension methods.
  2533. @private
  2534. @method exec
  2535. @return {Mixed} Whatever runtime extension method returns
  2536. */
  2537. exec: function() {
  2538. return runtime ? runtime.exec.apply(this, arguments) : null;
  2539. },
  2540. /**
  2541. Test runtime client for specific capability
  2542. @method can
  2543. @param {String} cap
  2544. @return {Bool}
  2545. */
  2546. can: function(cap) {
  2547. return runtime ? runtime.can(cap) : false;
  2548. }
  2549. });
  2550. };
  2551. });
  2552. // Included from: src/javascript/file/Blob.js
  2553. /**
  2554. * Blob.js
  2555. *
  2556. * Copyright 2013, Moxiecode Systems AB
  2557. * Released under GPL License.
  2558. *
  2559. * License: http://www.plupload.com/license
  2560. * Contributing: http://www.plupload.com/contributing
  2561. */
  2562. define('moxie/file/Blob', [
  2563. 'moxie/core/utils/Basic',
  2564. 'moxie/core/utils/Encode',
  2565. 'moxie/runtime/RuntimeClient'
  2566. ], function(Basic, Encode, RuntimeClient) {
  2567. var blobpool = {};
  2568. /**
  2569. @class moxie/file/Blob
  2570. @constructor
  2571. @param {String} ruid Unique id of the runtime, to which this blob belongs to
  2572. @param {Object} blob Object "Native" blob object, as it is represented in the runtime
  2573. */
  2574. function Blob(ruid, blob) {
  2575. function _sliceDetached(start, end, type) {
  2576. var blob, data = blobpool[this.uid];
  2577. if (Basic.typeOf(data) !== 'string' || !data.length) {
  2578. return null; // or throw exception
  2579. }
  2580. blob = new Blob(null, {
  2581. type: type,
  2582. size: end - start
  2583. });
  2584. blob.detach(data.substr(start, blob.size));
  2585. return blob;
  2586. }
  2587. RuntimeClient.call(this);
  2588. if (ruid) {
  2589. this.connectRuntime(ruid);
  2590. }
  2591. if (!blob) {
  2592. blob = {};
  2593. } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string
  2594. blob = { data: blob };
  2595. }
  2596. Basic.extend(this, {
  2597. /**
  2598. Unique id of the component
  2599. @property uid
  2600. @type {String}
  2601. */
  2602. uid: blob.uid || Basic.guid('uid_'),
  2603. /**
  2604. Unique id of the connected runtime, if falsy, then runtime will have to be initialized
  2605. before this Blob can be used, modified or sent
  2606. @property ruid
  2607. @type {String}
  2608. */
  2609. ruid: ruid,
  2610. /**
  2611. Size of blob
  2612. @property size
  2613. @type {Number}
  2614. @default 0
  2615. */
  2616. size: blob.size || 0,
  2617. /**
  2618. Mime type of blob
  2619. @property type
  2620. @type {String}
  2621. @default ''
  2622. */
  2623. type: blob.type || '',
  2624. /**
  2625. @method slice
  2626. @param {Number} [start=0]
  2627. */
  2628. slice: function(start, end, type) {
  2629. if (this.isDetached()) {
  2630. return _sliceDetached.apply(this, arguments);
  2631. }
  2632. return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type);
  2633. },
  2634. /**
  2635. Returns "native" blob object (as it is represented in connected runtime) or null if not found
  2636. @method getSource
  2637. @return {Blob} Returns "native" blob object or null if not found
  2638. */
  2639. getSource: function() {
  2640. if (!blobpool[this.uid]) {
  2641. return null;
  2642. }
  2643. return blobpool[this.uid];
  2644. },
  2645. /**
  2646. Detaches blob from any runtime that it depends on and initialize with standalone value
  2647. @method detach
  2648. @protected
  2649. @param {DOMString} [data=''] Standalone value
  2650. */
  2651. detach: function(data) {
  2652. if (this.ruid) {
  2653. this.getRuntime().exec.call(this, 'Blob', 'destroy');
  2654. this.disconnectRuntime();
  2655. this.ruid = null;
  2656. }
  2657. data = data || '';
  2658. // if dataUrl, convert to binary string
  2659. if (data.substr(0, 5) == 'data:') {
  2660. var base64Offset = data.indexOf(';base64,');
  2661. this.type = data.substring(5, base64Offset);
  2662. data = Encode.atob(data.substring(base64Offset + 8));
  2663. }
  2664. this.size = data.length;
  2665. blobpool[this.uid] = data;
  2666. },
  2667. /**
  2668. Checks if blob is standalone (detached of any runtime)
  2669. @method isDetached
  2670. @protected
  2671. @return {Boolean}
  2672. */
  2673. isDetached: function() {
  2674. return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string';
  2675. },
  2676. /**
  2677. Destroy Blob and free any resources it was using
  2678. @method destroy
  2679. */
  2680. destroy: function() {
  2681. this.detach();
  2682. delete blobpool[this.uid];
  2683. }
  2684. });
  2685. if (blob.data) {
  2686. this.detach(blob.data); // auto-detach if payload has been passed
  2687. } else {
  2688. blobpool[this.uid] = blob;
  2689. }
  2690. }
  2691. return Blob;
  2692. });
  2693. // Included from: src/javascript/core/I18n.js
  2694. /**
  2695. * I18n.js
  2696. *
  2697. * Copyright 2013, Moxiecode Systems AB
  2698. * Released under GPL License.
  2699. *
  2700. * License: http://www.plupload.com/license
  2701. * Contributing: http://www.plupload.com/contributing
  2702. */
  2703. define("moxie/core/I18n", [
  2704. "moxie/core/utils/Basic"
  2705. ], function(Basic) {
  2706. var i18n = {};
  2707. /**
  2708. @class moxie/core/I18n
  2709. */
  2710. return {
  2711. /**
  2712. * Extends the language pack object with new items.
  2713. *
  2714. * @param {Object} pack Language pack items to add.
  2715. * @return {Object} Extended language pack object.
  2716. */
  2717. addI18n: function(pack) {
  2718. return Basic.extend(i18n, pack);
  2719. },
  2720. /**
  2721. * Translates the specified string by checking for the english string in the language pack lookup.
  2722. *
  2723. * @param {String} str String to look for.
  2724. * @return {String} Translated string or the input string if it wasn't found.
  2725. */
  2726. translate: function(str) {
  2727. return i18n[str] || str;
  2728. },
  2729. /**
  2730. * Shortcut for translate function
  2731. *
  2732. * @param {String} str String to look for.
  2733. * @return {String} Translated string or the input string if it wasn't found.
  2734. */
  2735. _: function(str) {
  2736. return this.translate(str);
  2737. },
  2738. /**
  2739. * Pseudo sprintf implementation - simple way to replace tokens with specified values.
  2740. *
  2741. * @param {String} str String with tokens
  2742. * @return {String} String with replaced tokens
  2743. */
  2744. sprintf: function(str) {
  2745. var args = [].slice.call(arguments, 1);
  2746. return str.replace(/%[a-z]/g, function() {
  2747. var value = args.shift();
  2748. return Basic.typeOf(value) !== 'undefined' ? value : '';
  2749. });
  2750. }
  2751. };
  2752. });
  2753. // Included from: src/javascript/core/utils/Mime.js
  2754. /**
  2755. * Mime.js
  2756. *
  2757. * Copyright 2013, Moxiecode Systems AB
  2758. * Released under GPL License.
  2759. *
  2760. * License: http://www.plupload.com/license
  2761. * Contributing: http://www.plupload.com/contributing
  2762. */
  2763. /**
  2764. @class moxie/core/utils/Mime
  2765. @public
  2766. @static
  2767. */
  2768. define("moxie/core/utils/Mime", [
  2769. "moxie/core/utils/Basic",
  2770. "moxie/core/I18n"
  2771. ], function(Basic, I18n) {
  2772. var mimeData = "" +
  2773. "application/msword,doc dot," +
  2774. "application/pdf,pdf," +
  2775. "application/pgp-signature,pgp," +
  2776. "application/postscript,ps ai eps," +
  2777. "application/rtf,rtf," +
  2778. "application/vnd.ms-excel,xls xlb xlt xla," +
  2779. "application/vnd.ms-powerpoint,ppt pps pot ppa," +
  2780. "application/zip,zip," +
  2781. "application/x-shockwave-flash,swf swfl," +
  2782. "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
  2783. "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
  2784. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
  2785. "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
  2786. "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
  2787. "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
  2788. "application/x-javascript,js," +
  2789. "application/json,json," +
  2790. "audio/mpeg,mp3 mpga mpega mp2," +
  2791. "audio/x-wav,wav," +
  2792. "audio/x-m4a,m4a," +
  2793. "audio/ogg,oga ogg," +
  2794. "audio/aiff,aiff aif," +
  2795. "audio/flac,flac," +
  2796. "audio/aac,aac," +
  2797. "audio/ac3,ac3," +
  2798. "audio/x-ms-wma,wma," +
  2799. "image/bmp,bmp," +
  2800. "image/gif,gif," +
  2801. "image/jpeg,jpg jpeg jpe," +
  2802. "image/photoshop,psd," +
  2803. "image/png,png," +
  2804. "image/svg+xml,svg svgz," +
  2805. "image/tiff,tiff tif," +
  2806. "text/plain,asc txt text diff log," +
  2807. "text/html,htm html xhtml," +
  2808. "text/css,css," +
  2809. "text/csv,csv," +
  2810. "text/rtf,rtf," +
  2811. "video/mpeg,mpeg mpg mpe m2v," +
  2812. "video/quicktime,qt mov," +
  2813. "video/mp4,mp4," +
  2814. "video/x-m4v,m4v," +
  2815. "video/x-flv,flv," +
  2816. "video/x-ms-wmv,wmv," +
  2817. "video/avi,avi," +
  2818. "video/webm,webm," +
  2819. "video/3gpp,3gpp 3gp," +
  2820. "video/3gpp2,3g2," +
  2821. "video/vnd.rn-realvideo,rv," +
  2822. "video/ogg,ogv," +
  2823. "video/x-matroska,mkv," +
  2824. "application/vnd.oasis.opendocument.formula-template,otf," +
  2825. "application/octet-stream,exe";
  2826. /**
  2827. * Map of mimes to extensions
  2828. *
  2829. * @property mimes
  2830. * @type {Object}
  2831. */
  2832. var mimes = {};
  2833. /**
  2834. * Map of extensions to mimes
  2835. *
  2836. * @property extensions
  2837. * @type {Object}
  2838. */
  2839. var extensions = {};
  2840. /**
  2841. * Parses mimeData string into a mimes and extensions lookup maps. String should have the
  2842. * following format:
  2843. *
  2844. * application/msword,doc dot,application/pdf,pdf, ...
  2845. *
  2846. * so mime-type followed by comma and followed by space-separated list of associated extensions,
  2847. * then comma again and then another mime-type, etc.
  2848. *
  2849. * If invoked externally will replace override internal lookup maps with user-provided data.
  2850. *
  2851. * @method addMimeType
  2852. * @param {String} mimeData
  2853. */
  2854. var addMimeType = function (mimeData) {
  2855. var items = mimeData.split(/,/), i, ii, ext;
  2856. for (i = 0; i < items.length; i += 2) {
  2857. ext = items[i + 1].split(/ /);
  2858. // extension to mime lookup
  2859. for (ii = 0; ii < ext.length; ii++) {
  2860. mimes[ext[ii]] = items[i];
  2861. }
  2862. // mime to extension lookup
  2863. extensions[items[i]] = ext;
  2864. }
  2865. };
  2866. var extList2mimes = function (filters, addMissingExtensions) {
  2867. var ext, i, ii, type, mimes = [];
  2868. // convert extensions to mime types list
  2869. for (i = 0; i < filters.length; i++) {
  2870. ext = filters[i].extensions.toLowerCase().split(/\s*,\s*/);
  2871. for (ii = 0; ii < ext.length; ii++) {
  2872. // if there's an asterisk in the list, then accept attribute is not required
  2873. if (ext[ii] === '*') {
  2874. return [];
  2875. }
  2876. type = mimes[ext[ii]];
  2877. // future browsers should filter by extension, finally
  2878. if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
  2879. mimes.push('.' + ext[ii]);
  2880. } else if (type && Basic.inArray(type, mimes) === -1) {
  2881. mimes.push(type);
  2882. } else if (!type) {
  2883. // if we have no type in our map, then accept all
  2884. return [];
  2885. }
  2886. }
  2887. }
  2888. return mimes;
  2889. };
  2890. var mimes2exts = function(mimes) {
  2891. var exts = [];
  2892. Basic.each(mimes, function(mime) {
  2893. mime = mime.toLowerCase();
  2894. if (mime === '*') {
  2895. exts = [];
  2896. return false;
  2897. }
  2898. // check if this thing looks like mime type
  2899. var m = mime.match(/^(\w+)\/(\*|\w+)$/);
  2900. if (m) {
  2901. if (m[2] === '*') {
  2902. // wildcard mime type detected
  2903. Basic.each(extensions, function(arr, mime) {
  2904. if ((new RegExp('^' + m[1] + '/')).test(mime)) {
  2905. [].push.apply(exts, extensions[mime]);
  2906. }
  2907. });
  2908. } else if (extensions[mime]) {
  2909. [].push.apply(exts, extensions[mime]);
  2910. }
  2911. }
  2912. });
  2913. return exts;
  2914. };
  2915. var mimes2extList = function(mimes) {
  2916. var accept = [], exts = [];
  2917. if (Basic.typeOf(mimes) === 'string') {
  2918. mimes = Basic.trim(mimes).split(/\s*,\s*/);
  2919. }
  2920. exts = mimes2exts(mimes);
  2921. accept.push({
  2922. title: I18n.translate('Files'),
  2923. extensions: exts.length ? exts.join(',') : '*'
  2924. });
  2925. return accept;
  2926. };
  2927. /**
  2928. * Extract extension from the given filename
  2929. *
  2930. * @method getFileExtension
  2931. * @param {String} fileName
  2932. * @return {String} File extension
  2933. */
  2934. var getFileExtension = function(fileName) {
  2935. var matches = fileName && fileName.match(/\.([^.]+)$/);
  2936. if (matches) {
  2937. return matches[1].toLowerCase();
  2938. }
  2939. return '';
  2940. };
  2941. /**
  2942. * Get file mime-type from it's filename - will try to match the extension
  2943. * against internal mime-type lookup map
  2944. *
  2945. * @method getFileMime
  2946. * @param {String} fileName
  2947. * @return File mime-type if found or an empty string if not
  2948. */
  2949. var getFileMime = function(fileName) {
  2950. return mimes[getFileExtension(fileName)] || '';
  2951. };
  2952. addMimeType(mimeData);
  2953. return {
  2954. mimes: mimes,
  2955. extensions: extensions,
  2956. addMimeType: addMimeType,
  2957. extList2mimes: extList2mimes,
  2958. mimes2exts: mimes2exts,
  2959. mimes2extList: mimes2extList,
  2960. getFileExtension: getFileExtension,
  2961. getFileMime: getFileMime
  2962. }
  2963. });
  2964. // Included from: src/javascript/file/FileInput.js
  2965. /**
  2966. * FileInput.js
  2967. *
  2968. * Copyright 2013, Moxiecode Systems AB
  2969. * Released under GPL License.
  2970. *
  2971. * License: http://www.plupload.com/license
  2972. * Contributing: http://www.plupload.com/contributing
  2973. */
  2974. define('moxie/file/FileInput', [
  2975. 'moxie/core/utils/Basic',
  2976. 'moxie/core/utils/Env',
  2977. 'moxie/core/utils/Mime',
  2978. 'moxie/core/utils/Dom',
  2979. 'moxie/core/Exceptions',
  2980. 'moxie/core/EventTarget',
  2981. 'moxie/core/I18n',
  2982. 'moxie/runtime/Runtime',
  2983. 'moxie/runtime/RuntimeClient'
  2984. ], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) {
  2985. /**
  2986. Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
  2987. converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
  2988. with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
  2989. @class moxie/file/FileInput
  2990. @constructor
  2991. @extends EventTarget
  2992. @uses RuntimeClient
  2993. @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
  2994. @param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
  2995. @param {Array} [options.accept] Array of mime types to accept. By default accepts all.
  2996. @param {Boolean} [options.multiple=false] Enable selection of multiple files.
  2997. @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
  2998. @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode
  2999. for _browse\_button_.
  3000. @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
  3001. @example
  3002. <div id="container">
  3003. <a id="file-picker" href="javascript:;">Browse...</a>
  3004. </div>
  3005. <script>
  3006. var fileInput = new moxie.file.FileInput({
  3007. browse_button: 'file-picker', // or document.getElementById('file-picker')
  3008. container: 'container',
  3009. accept: [
  3010. {title: "Image files", extensions: "jpg,gif,png"} // accept only images
  3011. ],
  3012. multiple: true // allow multiple file selection
  3013. });
  3014. fileInput.onchange = function(e) {
  3015. // do something to files array
  3016. console.info(e.target.files); // or this.files or fileInput.files
  3017. };
  3018. fileInput.init(); // initialize
  3019. </script>
  3020. */
  3021. var dispatches = [
  3022. /**
  3023. Dispatched when runtime is connected and file-picker is ready to be used.
  3024. @event ready
  3025. @param {Object} event
  3026. */
  3027. 'ready',
  3028. /**
  3029. Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked.
  3030. Check [corresponding documentation entry](#method_refresh) for more info.
  3031. @event refresh
  3032. @param {Object} event
  3033. */
  3034. /**
  3035. Dispatched when selection of files in the dialog is complete.
  3036. @event change
  3037. @param {Object} event
  3038. */
  3039. 'change',
  3040. 'cancel', // TODO: might be useful
  3041. /**
  3042. Dispatched when mouse cursor enters file-picker area. Can be used to style element
  3043. accordingly.
  3044. @event mouseenter
  3045. @param {Object} event
  3046. */
  3047. 'mouseenter',
  3048. /**
  3049. Dispatched when mouse cursor leaves file-picker area. Can be used to style element
  3050. accordingly.
  3051. @event mouseleave
  3052. @param {Object} event
  3053. */
  3054. 'mouseleave',
  3055. /**
  3056. Dispatched when functional mouse button is pressed on top of file-picker area.
  3057. @event mousedown
  3058. @param {Object} event
  3059. */
  3060. 'mousedown',
  3061. /**
  3062. Dispatched when functional mouse button is released on top of file-picker area.
  3063. @event mouseup
  3064. @param {Object} event
  3065. */
  3066. 'mouseup'
  3067. ];
  3068. function FileInput(options) {
  3069. if (MXI_DEBUG) {
  3070. Env.log("Instantiating FileInput...");
  3071. }
  3072. var container, browseButton, defaults;
  3073. // if flat argument passed it should be browse_button id
  3074. if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
  3075. options = { browse_button : options };
  3076. }
  3077. // this will help us to find proper default container
  3078. browseButton = Dom.get(options.browse_button);
  3079. if (!browseButton) {
  3080. // browse button is required
  3081. throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
  3082. }
  3083. // figure out the options
  3084. defaults = {
  3085. accept: [{
  3086. title: I18n.translate('All Files'),
  3087. extensions: '*'
  3088. }],
  3089. multiple: false,
  3090. required_caps: false,
  3091. container: browseButton.parentNode || document.body
  3092. };
  3093. options = Basic.extend({}, defaults, options);
  3094. // convert to object representation
  3095. if (typeof(options.required_caps) === 'string') {
  3096. options.required_caps = Runtime.parseCaps(options.required_caps);
  3097. }
  3098. // normalize accept option (could be list of mime types or array of title/extensions pairs)
  3099. if (typeof(options.accept) === 'string') {
  3100. options.accept = Mime.mimes2extList(options.accept);
  3101. }
  3102. container = Dom.get(options.container);
  3103. // make sure we have container
  3104. if (!container) {
  3105. container = document.body;
  3106. }
  3107. // make container relative, if it's not
  3108. if (Dom.getStyle(container, 'position') === 'static') {
  3109. container.style.position = 'relative';
  3110. }
  3111. container = browseButton = null; // IE
  3112. RuntimeClient.call(this);
  3113. Basic.extend(this, {
  3114. /**
  3115. Unique id of the component
  3116. @property uid
  3117. @protected
  3118. @readOnly
  3119. @type {String}
  3120. @default UID
  3121. */
  3122. uid: Basic.guid('uid_'),
  3123. /**
  3124. Unique id of the connected runtime, if any.
  3125. @property ruid
  3126. @protected
  3127. @type {String}
  3128. */
  3129. ruid: null,
  3130. /**
  3131. Unique id of the runtime container. Useful to get hold of it for various manipulations.
  3132. @property shimid
  3133. @protected
  3134. @type {String}
  3135. */
  3136. shimid: null,
  3137. /**
  3138. Array of selected moxie.file.File objects
  3139. @property files
  3140. @type {Array}
  3141. @default null
  3142. */
  3143. files: null,
  3144. /**
  3145. Initializes the file-picker, connects it to runtime and dispatches event ready when done.
  3146. @method init
  3147. */
  3148. init: function() {
  3149. var self = this;
  3150. self.bind('RuntimeInit', function(e, runtime) {
  3151. self.ruid = runtime.uid;
  3152. self.shimid = runtime.shimid;
  3153. self.bind("Ready", function() {
  3154. self.trigger("Refresh");
  3155. }, 999);
  3156. // re-position and resize shim container
  3157. self.bind('Refresh', function() {
  3158. var pos, size, browseButton, shimContainer, zIndex;
  3159. browseButton = Dom.get(options.browse_button);
  3160. shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
  3161. if (browseButton) {
  3162. pos = Dom.getPos(browseButton, Dom.get(options.container));
  3163. size = Dom.getSize(browseButton);
  3164. zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 0;
  3165. if (shimContainer) {
  3166. Basic.extend(shimContainer.style, {
  3167. top: pos.y + 'px',
  3168. left: pos.x + 'px',
  3169. width: size.w + 'px',
  3170. height: size.h + 'px',
  3171. zIndex: zIndex + 1
  3172. });
  3173. }
  3174. }
  3175. shimContainer = browseButton = null;
  3176. });
  3177. runtime.exec.call(self, 'FileInput', 'init', options);
  3178. });
  3179. // runtime needs: options.required_features, options.runtime_order and options.container
  3180. self.connectRuntime(Basic.extend({}, options, {
  3181. required_caps: {
  3182. select_file: true
  3183. }
  3184. }));
  3185. },
  3186. /**
  3187. * Get current option value by its name
  3188. *
  3189. * @method getOption
  3190. * @param name
  3191. * @return {Mixed}
  3192. */
  3193. getOption: function(name) {
  3194. return options[name];
  3195. },
  3196. /**
  3197. * Sets a new value for the option specified by name
  3198. *
  3199. * @method setOption
  3200. * @param name
  3201. * @param value
  3202. */
  3203. setOption: function(name, value) {
  3204. if (!options.hasOwnProperty(name)) {
  3205. return;
  3206. }
  3207. var oldValue = options[name];
  3208. switch (name) {
  3209. case 'accept':
  3210. if (typeof(value) === 'string') {
  3211. value = Mime.mimes2extList(value);
  3212. }
  3213. break;
  3214. case 'container':
  3215. case 'required_caps':
  3216. throw new x.FileException(x.FileException.NO_MODIFICATION_ALLOWED_ERR);
  3217. }
  3218. options[name] = value;
  3219. this.exec('FileInput', 'setOption', name, value);
  3220. this.trigger('OptionChanged', name, value, oldValue);
  3221. },
  3222. /**
  3223. Disables file-picker element, so that it doesn't react to mouse clicks.
  3224. @method disable
  3225. @param {Boolean} [state=true] Disable component if - true, enable if - false
  3226. */
  3227. disable: function(state) {
  3228. var runtime = this.getRuntime();
  3229. if (runtime) {
  3230. this.exec('FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
  3231. }
  3232. },
  3233. /**
  3234. Reposition and resize dialog trigger to match the position and size of browse_button element.
  3235. @method refresh
  3236. */
  3237. refresh: function() {
  3238. this.trigger("Refresh");
  3239. },
  3240. /**
  3241. Destroy component.
  3242. @method destroy
  3243. */
  3244. destroy: function() {
  3245. var runtime = this.getRuntime();
  3246. if (runtime) {
  3247. runtime.exec.call(this, 'FileInput', 'destroy');
  3248. this.disconnectRuntime();
  3249. }
  3250. if (Basic.typeOf(this.files) === 'array') {
  3251. // no sense in leaving associated files behind
  3252. Basic.each(this.files, function(file) {
  3253. file.destroy();
  3254. });
  3255. }
  3256. this.files = null;
  3257. this.unbindAll();
  3258. }
  3259. });
  3260. this.handleEventProps(dispatches);
  3261. }
  3262. FileInput.prototype = EventTarget.instance;
  3263. return FileInput;
  3264. });
  3265. // Included from: src/javascript/file/File.js
  3266. /**
  3267. * File.js
  3268. *
  3269. * Copyright 2013, Moxiecode Systems AB
  3270. * Released under GPL License.
  3271. *
  3272. * License: http://www.plupload.com/license
  3273. * Contributing: http://www.plupload.com/contributing
  3274. */
  3275. define('moxie/file/File', [
  3276. 'moxie/core/utils/Basic',
  3277. 'moxie/core/utils/Mime',
  3278. 'moxie/file/Blob'
  3279. ], function(Basic, Mime, Blob) {
  3280. /**
  3281. @class moxie/file/File
  3282. @extends Blob
  3283. @constructor
  3284. @param {String} ruid Unique id of the runtime, to which this blob belongs to
  3285. @param {Object} file Object "Native" file object, as it is represented in the runtime
  3286. */
  3287. function File(ruid, file) {
  3288. if (!file) { // avoid extra errors in case we overlooked something
  3289. file = {};
  3290. }
  3291. Blob.apply(this, arguments);
  3292. if (!this.type) {
  3293. this.type = Mime.getFileMime(file.name);
  3294. }
  3295. // sanitize file name or generate new one
  3296. var name;
  3297. if (file.name) {
  3298. name = file.name.replace(/\\/g, '/');
  3299. name = name.substr(name.lastIndexOf('/') + 1);
  3300. } else if (this.type) {
  3301. var prefix = this.type.split('/')[0];
  3302. name = Basic.guid((prefix !== '' ? prefix : 'file') + '_');
  3303. if (Mime.extensions[this.type]) {
  3304. name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible
  3305. }
  3306. }
  3307. Basic.extend(this, {
  3308. /**
  3309. File name
  3310. @property name
  3311. @type {String}
  3312. @default UID
  3313. */
  3314. name: name || Basic.guid('file_'),
  3315. /**
  3316. Relative path to the file inside a directory
  3317. @property relativePath
  3318. @type {String}
  3319. @default ''
  3320. */
  3321. relativePath: '',
  3322. /**
  3323. Date of last modification
  3324. @property lastModifiedDate
  3325. @type {String}
  3326. @default now
  3327. */
  3328. lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
  3329. });
  3330. }
  3331. File.prototype = Blob.prototype;
  3332. return File;
  3333. });
  3334. // Included from: src/javascript/file/FileDrop.js
  3335. /**
  3336. * FileDrop.js
  3337. *
  3338. * Copyright 2013, Moxiecode Systems AB
  3339. * Released under GPL License.
  3340. *
  3341. * License: http://www.plupload.com/license
  3342. * Contributing: http://www.plupload.com/contributing
  3343. */
  3344. define('moxie/file/FileDrop', [
  3345. 'moxie/core/I18n',
  3346. 'moxie/core/utils/Dom',
  3347. 'moxie/core/Exceptions',
  3348. 'moxie/core/utils/Basic',
  3349. 'moxie/core/utils/Env',
  3350. 'moxie/file/File',
  3351. 'moxie/runtime/RuntimeClient',
  3352. 'moxie/core/EventTarget',
  3353. 'moxie/core/utils/Mime'
  3354. ], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) {
  3355. /**
  3356. Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used
  3357. in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through
  3358. _XMLHttpRequest_.
  3359. @example
  3360. <div id="drop_zone">
  3361. Drop files here
  3362. </div>
  3363. <br />
  3364. <div id="filelist"></div>
  3365. <script type="text/javascript">
  3366. var fileDrop = new moxie.file.FileDrop('drop_zone'), fileList = moxie.utils.Dom.get('filelist');
  3367. fileDrop.ondrop = function() {
  3368. moxie.utils.Basic.each(this.files, function(file) {
  3369. fileList.innerHTML += '<div>' + file.name + '</div>';
  3370. });
  3371. };
  3372. fileDrop.init();
  3373. </script>
  3374. @class moxie/file/FileDrop
  3375. @constructor
  3376. @extends EventTarget
  3377. @uses RuntimeClient
  3378. @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone
  3379. @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone
  3380. @param {Array} [options.accept] Array of mime types to accept. By default accepts all
  3381. @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support
  3382. */
  3383. var dispatches = [
  3384. /**
  3385. Dispatched when runtime is connected and drop zone is ready to accept files.
  3386. @event ready
  3387. @param {Object} event
  3388. */
  3389. 'ready',
  3390. /**
  3391. Dispatched when dragging cursor enters the drop zone.
  3392. @event dragenter
  3393. @param {Object} event
  3394. */
  3395. 'dragenter',
  3396. /**
  3397. Dispatched when dragging cursor leaves the drop zone.
  3398. @event dragleave
  3399. @param {Object} event
  3400. */
  3401. 'dragleave',
  3402. /**
  3403. Dispatched when file is dropped onto the drop zone.
  3404. @event drop
  3405. @param {Object} event
  3406. */
  3407. 'drop',
  3408. /**
  3409. Dispatched if error occurs.
  3410. @event error
  3411. @param {Object} event
  3412. */
  3413. 'error'
  3414. ];
  3415. function FileDrop(options) {
  3416. if (MXI_DEBUG) {
  3417. Env.log("Instantiating FileDrop...");
  3418. }
  3419. var self = this, defaults;
  3420. // if flat argument passed it should be drop_zone id
  3421. if (typeof(options) === 'string') {
  3422. options = { drop_zone : options };
  3423. }
  3424. // figure out the options
  3425. defaults = {
  3426. accept: [{
  3427. title: I18n.translate('All Files'),
  3428. extensions: '*'
  3429. }],
  3430. required_caps: {
  3431. drag_and_drop: true
  3432. }
  3433. };
  3434. options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults;
  3435. // this will help us to find proper default container
  3436. options.container = Dom.get(options.drop_zone) || document.body;
  3437. // make container relative, if it is not
  3438. if (Dom.getStyle(options.container, 'position') === 'static') {
  3439. options.container.style.position = 'relative';
  3440. }
  3441. // normalize accept option (could be list of mime types or array of title/extensions pairs)
  3442. if (typeof(options.accept) === 'string') {
  3443. options.accept = Mime.mimes2extList(options.accept);
  3444. }
  3445. RuntimeClient.call(self);
  3446. Basic.extend(self, {
  3447. uid: Basic.guid('uid_'),
  3448. ruid: null,
  3449. files: null,
  3450. init: function() {
  3451. self.bind('RuntimeInit', function(e, runtime) {
  3452. self.ruid = runtime.uid;
  3453. runtime.exec.call(self, 'FileDrop', 'init', options);
  3454. self.dispatchEvent('ready');
  3455. });
  3456. // runtime needs: options.required_features, options.runtime_order and options.container
  3457. self.connectRuntime(options); // throws RuntimeError
  3458. },
  3459. destroy: function() {
  3460. var runtime = this.getRuntime();
  3461. if (runtime) {
  3462. runtime.exec.call(this, 'FileDrop', 'destroy');
  3463. this.disconnectRuntime();
  3464. }
  3465. this.files = null;
  3466. this.unbindAll();
  3467. }
  3468. });
  3469. this.handleEventProps(dispatches);
  3470. }
  3471. FileDrop.prototype = EventTarget.instance;
  3472. return FileDrop;
  3473. });
  3474. // Included from: src/javascript/file/FileReader.js
  3475. /**
  3476. * FileReader.js
  3477. *
  3478. * Copyright 2013, Moxiecode Systems AB
  3479. * Released under GPL License.
  3480. *
  3481. * License: http://www.plupload.com/license
  3482. * Contributing: http://www.plupload.com/contributing
  3483. */
  3484. define('moxie/file/FileReader', [
  3485. 'moxie/core/utils/Basic',
  3486. 'moxie/core/utils/Encode',
  3487. 'moxie/core/Exceptions',
  3488. 'moxie/core/EventTarget',
  3489. 'moxie/file/Blob',
  3490. 'moxie/runtime/RuntimeClient'
  3491. ], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) {
  3492. /**
  3493. Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader)
  3494. interface. Where possible uses native FileReader, where - not falls back to shims.
  3495. @class moxie/file/FileReader
  3496. @constructor FileReader
  3497. @extends EventTarget
  3498. @uses RuntimeClient
  3499. */
  3500. var dispatches = [
  3501. /**
  3502. Dispatched when the read starts.
  3503. @event loadstart
  3504. @param {Object} event
  3505. */
  3506. 'loadstart',
  3507. /**
  3508. Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total).
  3509. @event progress
  3510. @param {Object} event
  3511. */
  3512. 'progress',
  3513. /**
  3514. Dispatched when the read has successfully completed.
  3515. @event load
  3516. @param {Object} event
  3517. */
  3518. 'load',
  3519. /**
  3520. Dispatched when the read has been aborted. For instance, by invoking the abort() method.
  3521. @event abort
  3522. @param {Object} event
  3523. */
  3524. 'abort',
  3525. /**
  3526. Dispatched when the read has failed.
  3527. @event error
  3528. @param {Object} event
  3529. */
  3530. 'error',
  3531. /**
  3532. Dispatched when the request has completed (either in success or failure).
  3533. @event loadend
  3534. @param {Object} event
  3535. */
  3536. 'loadend'
  3537. ];
  3538. function FileReader() {
  3539. RuntimeClient.call(this);
  3540. Basic.extend(this, {
  3541. /**
  3542. UID of the component instance.
  3543. @property uid
  3544. @type {String}
  3545. */
  3546. uid: Basic.guid('uid_'),
  3547. /**
  3548. Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING
  3549. and FileReader.DONE.
  3550. @property readyState
  3551. @type {Number}
  3552. @default FileReader.EMPTY
  3553. */
  3554. readyState: FileReader.EMPTY,
  3555. /**
  3556. Result of the successful read operation.
  3557. @property result
  3558. @type {String}
  3559. */
  3560. result: null,
  3561. /**
  3562. Stores the error of failed asynchronous read operation.
  3563. @property error
  3564. @type {DOMError}
  3565. */
  3566. error: null,
  3567. /**
  3568. Initiates reading of File/Blob object contents to binary string.
  3569. @method readAsBinaryString
  3570. @param {Blob|File} blob Object to preload
  3571. */
  3572. readAsBinaryString: function(blob) {
  3573. _read.call(this, 'readAsBinaryString', blob);
  3574. },
  3575. /**
  3576. Initiates reading of File/Blob object contents to dataURL string.
  3577. @method readAsDataURL
  3578. @param {Blob|File} blob Object to preload
  3579. */
  3580. readAsDataURL: function(blob) {
  3581. _read.call(this, 'readAsDataURL', blob);
  3582. },
  3583. /**
  3584. Initiates reading of File/Blob object contents to string.
  3585. @method readAsText
  3586. @param {Blob|File} blob Object to preload
  3587. */
  3588. readAsText: function(blob) {
  3589. _read.call(this, 'readAsText', blob);
  3590. },
  3591. /**
  3592. Aborts preloading process.
  3593. @method abort
  3594. */
  3595. abort: function() {
  3596. this.result = null;
  3597. if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) {
  3598. return;
  3599. } else if (this.readyState === FileReader.LOADING) {
  3600. this.readyState = FileReader.DONE;
  3601. }
  3602. this.exec('FileReader', 'abort');
  3603. this.trigger('abort');
  3604. this.trigger('loadend');
  3605. },
  3606. /**
  3607. Destroy component and release resources.
  3608. @method destroy
  3609. */
  3610. destroy: function() {
  3611. this.abort();
  3612. this.exec('FileReader', 'destroy');
  3613. this.disconnectRuntime();
  3614. this.unbindAll();
  3615. }
  3616. });
  3617. // uid must already be assigned
  3618. this.handleEventProps(dispatches);
  3619. this.bind('Error', function(e, err) {
  3620. this.readyState = FileReader.DONE;
  3621. this.error = err;
  3622. }, 999);
  3623. this.bind('Load', function(e) {
  3624. this.readyState = FileReader.DONE;
  3625. }, 999);
  3626. function _read(op, blob) {
  3627. var self = this;
  3628. this.trigger('loadstart');
  3629. if (this.readyState === FileReader.LOADING) {
  3630. this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR));
  3631. this.trigger('loadend');
  3632. return;
  3633. }
  3634. // if source is not o.Blob/o.File
  3635. if (!(blob instanceof Blob)) {
  3636. this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR));
  3637. this.trigger('loadend');
  3638. return;
  3639. }
  3640. this.result = null;
  3641. this.readyState = FileReader.LOADING;
  3642. if (blob.isDetached()) {
  3643. var src = blob.getSource();
  3644. switch (op) {
  3645. case 'readAsText':
  3646. case 'readAsBinaryString':
  3647. this.result = src;
  3648. break;
  3649. case 'readAsDataURL':
  3650. this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src);
  3651. break;
  3652. }
  3653. this.readyState = FileReader.DONE;
  3654. this.trigger('load');
  3655. this.trigger('loadend');
  3656. } else {
  3657. this.connectRuntime(blob.ruid);
  3658. this.exec('FileReader', 'read', op, blob);
  3659. }
  3660. }
  3661. }
  3662. /**
  3663. Initial FileReader state
  3664. @property EMPTY
  3665. @type {Number}
  3666. @final
  3667. @static
  3668. @default 0
  3669. */
  3670. FileReader.EMPTY = 0;
  3671. /**
  3672. FileReader switches to this state when it is preloading the source
  3673. @property LOADING
  3674. @type {Number}
  3675. @final
  3676. @static
  3677. @default 1
  3678. */
  3679. FileReader.LOADING = 1;
  3680. /**
  3681. Preloading is complete, this is a final state
  3682. @property DONE
  3683. @type {Number}
  3684. @final
  3685. @static
  3686. @default 2
  3687. */
  3688. FileReader.DONE = 2;
  3689. FileReader.prototype = EventTarget.instance;
  3690. return FileReader;
  3691. });
  3692. // Included from: src/javascript/core/utils/Url.js
  3693. /**
  3694. * Url.js
  3695. *
  3696. * Copyright 2013, Moxiecode Systems AB
  3697. * Released under GPL License.
  3698. *
  3699. * License: http://www.plupload.com/license
  3700. * Contributing: http://www.plupload.com/contributing
  3701. */
  3702. /**
  3703. @class moxie/core/utils/Url
  3704. @public
  3705. @static
  3706. */
  3707. define('moxie/core/utils/Url', [
  3708. 'moxie/core/utils/Basic'
  3709. ], function(Basic) {
  3710. /**
  3711. Parse url into separate components and fill in absent parts with parts from current url,
  3712. based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js
  3713. @method parseUrl
  3714. @static
  3715. @param {String} url Url to parse (defaults to empty string if undefined)
  3716. @return {Object} Hash containing extracted uri components
  3717. */
  3718. var parseUrl = function(url, currentUrl) {
  3719. var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment']
  3720. , i = key.length
  3721. , ports = {
  3722. http: 80,
  3723. https: 443
  3724. }
  3725. , uri = {}
  3726. , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
  3727. , m = regex.exec(url || '')
  3728. , isRelative
  3729. , isSchemeLess = /^\/\/\w/.test(url)
  3730. ;
  3731. switch (Basic.typeOf(currentUrl)) {
  3732. case 'undefined':
  3733. currentUrl = parseUrl(document.location.href, false);
  3734. break;
  3735. case 'string':
  3736. currentUrl = parseUrl(currentUrl, false);
  3737. break;
  3738. }
  3739. while (i--) {
  3740. if (m[i]) {
  3741. uri[key[i]] = m[i];
  3742. }
  3743. }
  3744. isRelative = !isSchemeLess && !uri.scheme;
  3745. if (isSchemeLess || isRelative) {
  3746. uri.scheme = currentUrl.scheme;
  3747. }
  3748. // when url is relative, we set the origin and the path ourselves
  3749. if (isRelative) {
  3750. uri.host = currentUrl.host;
  3751. uri.port = currentUrl.port;
  3752. var path = '';
  3753. // for urls without trailing slash we need to figure out the path
  3754. if (/^[^\/]/.test(uri.path)) {
  3755. path = currentUrl.path;
  3756. // if path ends with a filename, strip it
  3757. if (/\/[^\/]*\.[^\/]*$/.test(path)) {
  3758. path = path.replace(/\/[^\/]+$/, '/');
  3759. } else {
  3760. // avoid double slash at the end (see #127)
  3761. path = path.replace(/\/?$/, '/');
  3762. }
  3763. }
  3764. uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
  3765. }
  3766. if (!uri.port) {
  3767. uri.port = ports[uri.scheme] || 80;
  3768. }
  3769. uri.port = parseInt(uri.port, 10);
  3770. if (!uri.path) {
  3771. uri.path = "/";
  3772. }
  3773. delete uri.source;
  3774. return uri;
  3775. };
  3776. /**
  3777. Resolve url - among other things will turn relative url to absolute
  3778. @method resolveUrl
  3779. @static
  3780. @param {String|Object} url Either absolute or relative, or a result of parseUrl call
  3781. @return {String} Resolved, absolute url
  3782. */
  3783. var resolveUrl = function(url) {
  3784. var ports = { // we ignore default ports
  3785. http: 80,
  3786. https: 443
  3787. }
  3788. , urlp = typeof(url) === 'object' ? url : parseUrl(url);
  3789. ;
  3790. return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : '');
  3791. };
  3792. /**
  3793. Check if specified url has the same origin as the current document
  3794. @method hasSameOrigin
  3795. @static
  3796. @param {String|Object} url
  3797. @return {Boolean}
  3798. */
  3799. var hasSameOrigin = function(url) {
  3800. function origin(url) {
  3801. return [url.scheme, url.host, url.port].join('/');
  3802. }
  3803. if (typeof url === 'string') {
  3804. url = parseUrl(url);
  3805. }
  3806. return origin(parseUrl()) === origin(url);
  3807. };
  3808. return {
  3809. parseUrl: parseUrl,
  3810. resolveUrl: resolveUrl,
  3811. hasSameOrigin: hasSameOrigin
  3812. };
  3813. });
  3814. // Included from: src/javascript/runtime/RuntimeTarget.js
  3815. /**
  3816. * RuntimeTarget.js
  3817. *
  3818. * Copyright 2013, Moxiecode Systems AB
  3819. * Released under GPL License.
  3820. *
  3821. * License: http://www.plupload.com/license
  3822. * Contributing: http://www.plupload.com/contributing
  3823. */
  3824. define('moxie/runtime/RuntimeTarget', [
  3825. 'moxie/core/utils/Basic',
  3826. 'moxie/runtime/RuntimeClient',
  3827. "moxie/core/EventTarget"
  3828. ], function(Basic, RuntimeClient, EventTarget) {
  3829. /**
  3830. Instance of this class can be used as a target for the events dispatched by shims,
  3831. when allowing them onto components is for either reason inappropriate
  3832. @class moxie/runtime/RuntimeTarget
  3833. @constructor
  3834. @protected
  3835. @extends EventTarget
  3836. */
  3837. function RuntimeTarget() {
  3838. this.uid = Basic.guid('uid_');
  3839. RuntimeClient.call(this);
  3840. this.destroy = function() {
  3841. this.disconnectRuntime();
  3842. this.unbindAll();
  3843. };
  3844. }
  3845. RuntimeTarget.prototype = EventTarget.instance;
  3846. return RuntimeTarget;
  3847. });
  3848. // Included from: src/javascript/file/FileReaderSync.js
  3849. /**
  3850. * FileReaderSync.js
  3851. *
  3852. * Copyright 2013, Moxiecode Systems AB
  3853. * Released under GPL License.
  3854. *
  3855. * License: http://www.plupload.com/license
  3856. * Contributing: http://www.plupload.com/contributing
  3857. */
  3858. define('moxie/file/FileReaderSync', [
  3859. 'moxie/core/utils/Basic',
  3860. 'moxie/runtime/RuntimeClient',
  3861. 'moxie/core/utils/Encode'
  3862. ], function(Basic, RuntimeClient, Encode) {
  3863. /**
  3864. Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here
  3865. it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be,
  3866. but probably < 1mb). Not meant to be used directly by user.
  3867. @class moxie/file/FileReaderSync
  3868. @private
  3869. @constructor
  3870. */
  3871. return function() {
  3872. RuntimeClient.call(this);
  3873. Basic.extend(this, {
  3874. uid: Basic.guid('uid_'),
  3875. readAsBinaryString: function(blob) {
  3876. return _read.call(this, 'readAsBinaryString', blob);
  3877. },
  3878. readAsDataURL: function(blob) {
  3879. return _read.call(this, 'readAsDataURL', blob);
  3880. },
  3881. /*readAsArrayBuffer: function(blob) {
  3882. return _read.call(this, 'readAsArrayBuffer', blob);
  3883. },*/
  3884. readAsText: function(blob) {
  3885. return _read.call(this, 'readAsText', blob);
  3886. }
  3887. });
  3888. function _read(op, blob) {
  3889. if (blob.isDetached()) {
  3890. var src = blob.getSource();
  3891. switch (op) {
  3892. case 'readAsBinaryString':
  3893. return src;
  3894. case 'readAsDataURL':
  3895. return 'data:' + blob.type + ';base64,' + Encode.btoa(src);
  3896. case 'readAsText':
  3897. var txt = '';
  3898. for (var i = 0, length = src.length; i < length; i++) {
  3899. txt += String.fromCharCode(src[i]);
  3900. }
  3901. return txt;
  3902. }
  3903. } else {
  3904. var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob);
  3905. this.disconnectRuntime();
  3906. return result;
  3907. }
  3908. }
  3909. };
  3910. });
  3911. // Included from: src/javascript/xhr/FormData.js
  3912. /**
  3913. * FormData.js
  3914. *
  3915. * Copyright 2013, Moxiecode Systems AB
  3916. * Released under GPL License.
  3917. *
  3918. * License: http://www.plupload.com/license
  3919. * Contributing: http://www.plupload.com/contributing
  3920. */
  3921. define("moxie/xhr/FormData", [
  3922. "moxie/core/Exceptions",
  3923. "moxie/core/utils/Basic",
  3924. "moxie/file/Blob"
  3925. ], function(x, Basic, Blob) {
  3926. /**
  3927. FormData
  3928. @class moxie/xhr/FormData
  3929. @constructor
  3930. */
  3931. function FormData() {
  3932. var _blob, _fields = [];
  3933. Basic.extend(this, {
  3934. /**
  3935. Append another key-value pair to the FormData object
  3936. @method append
  3937. @param {String} name Name for the new field
  3938. @param {String|Blob|Array|Object} value Value for the field
  3939. */
  3940. append: function(name, value) {
  3941. var self = this, valueType = Basic.typeOf(value);
  3942. // according to specs value might be either Blob or String
  3943. if (value instanceof Blob) {
  3944. _blob = {
  3945. name: name,
  3946. value: value // unfortunately we can only send single Blob in one FormData
  3947. };
  3948. } else if ('array' === valueType) {
  3949. name += '[]';
  3950. Basic.each(value, function(value) {
  3951. self.append(name, value);
  3952. });
  3953. } else if ('object' === valueType) {
  3954. Basic.each(value, function(value, key) {
  3955. self.append(name + '[' + key + ']', value);
  3956. });
  3957. } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) {
  3958. self.append(name, "false");
  3959. } else {
  3960. _fields.push({
  3961. name: name,
  3962. value: value.toString()
  3963. });
  3964. }
  3965. },
  3966. /**
  3967. Checks if FormData contains Blob.
  3968. @method hasBlob
  3969. @return {Boolean}
  3970. */
  3971. hasBlob: function() {
  3972. return !!this.getBlob();
  3973. },
  3974. /**
  3975. Retrieves blob.
  3976. @method getBlob
  3977. @return {Object} Either Blob if found or null
  3978. */
  3979. getBlob: function() {
  3980. return _blob && _blob.value || null;
  3981. },
  3982. /**
  3983. Retrieves blob field name.
  3984. @method getBlobName
  3985. @return {String} Either Blob field name or null
  3986. */
  3987. getBlobName: function() {
  3988. return _blob && _blob.name || null;
  3989. },
  3990. /**
  3991. Loop over the fields in FormData and invoke the callback for each of them.
  3992. @method each
  3993. @param {Function} cb Callback to call for each field
  3994. */
  3995. each: function(cb) {
  3996. Basic.each(_fields, function(field) {
  3997. cb(field.value, field.name);
  3998. });
  3999. if (_blob) {
  4000. cb(_blob.value, _blob.name);
  4001. }
  4002. },
  4003. destroy: function() {
  4004. _blob = null;
  4005. _fields = [];
  4006. }
  4007. });
  4008. }
  4009. return FormData;
  4010. });
  4011. // Included from: src/javascript/xhr/XMLHttpRequest.js
  4012. /**
  4013. * XMLHttpRequest.js
  4014. *
  4015. * Copyright 2013, Moxiecode Systems AB
  4016. * Released under GPL License.
  4017. *
  4018. * License: http://www.plupload.com/license
  4019. * Contributing: http://www.plupload.com/contributing
  4020. */
  4021. define("moxie/xhr/XMLHttpRequest", [
  4022. "moxie/core/utils/Basic",
  4023. "moxie/core/Exceptions",
  4024. "moxie/core/EventTarget",
  4025. "moxie/core/utils/Encode",
  4026. "moxie/core/utils/Url",
  4027. "moxie/runtime/Runtime",
  4028. "moxie/runtime/RuntimeTarget",
  4029. "moxie/file/Blob",
  4030. "moxie/file/FileReaderSync",
  4031. "moxie/xhr/FormData",
  4032. "moxie/core/utils/Env",
  4033. "moxie/core/utils/Mime"
  4034. ], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) {
  4035. var httpCode = {
  4036. 100: 'Continue',
  4037. 101: 'Switching Protocols',
  4038. 102: 'Processing',
  4039. 200: 'OK',
  4040. 201: 'Created',
  4041. 202: 'Accepted',
  4042. 203: 'Non-Authoritative Information',
  4043. 204: 'No Content',
  4044. 205: 'Reset Content',
  4045. 206: 'Partial Content',
  4046. 207: 'Multi-Status',
  4047. 226: 'IM Used',
  4048. 300: 'Multiple Choices',
  4049. 301: 'Moved Permanently',
  4050. 302: 'Found',
  4051. 303: 'See Other',
  4052. 304: 'Not Modified',
  4053. 305: 'Use Proxy',
  4054. 306: 'Reserved',
  4055. 307: 'Temporary Redirect',
  4056. 400: 'Bad Request',
  4057. 401: 'Unauthorized',
  4058. 402: 'Payment Required',
  4059. 403: 'Forbidden',
  4060. 404: 'Not Found',
  4061. 405: 'Method Not Allowed',
  4062. 406: 'Not Acceptable',
  4063. 407: 'Proxy Authentication Required',
  4064. 408: 'Request Timeout',
  4065. 409: 'Conflict',
  4066. 410: 'Gone',
  4067. 411: 'Length Required',
  4068. 412: 'Precondition Failed',
  4069. 413: 'Request Entity Too Large',
  4070. 414: 'Request-URI Too Long',
  4071. 415: 'Unsupported Media Type',
  4072. 416: 'Requested Range Not Satisfiable',
  4073. 417: 'Expectation Failed',
  4074. 422: 'Unprocessable Entity',
  4075. 423: 'Locked',
  4076. 424: 'Failed Dependency',
  4077. 426: 'Upgrade Required',
  4078. 500: 'Internal Server Error',
  4079. 501: 'Not Implemented',
  4080. 502: 'Bad Gateway',
  4081. 503: 'Service Unavailable',
  4082. 504: 'Gateway Timeout',
  4083. 505: 'HTTP Version Not Supported',
  4084. 506: 'Variant Also Negotiates',
  4085. 507: 'Insufficient Storage',
  4086. 510: 'Not Extended'
  4087. };
  4088. function XMLHttpRequestUpload() {
  4089. this.uid = Basic.guid('uid_');
  4090. }
  4091. XMLHttpRequestUpload.prototype = EventTarget.instance;
  4092. /**
  4093. Implementation of XMLHttpRequest
  4094. @class moxie/xhr/XMLHttpRequest
  4095. @constructor
  4096. @uses RuntimeClient
  4097. @extends EventTarget
  4098. */
  4099. var dispatches = [
  4100. 'loadstart',
  4101. 'progress',
  4102. 'abort',
  4103. 'error',
  4104. 'load',
  4105. 'timeout',
  4106. 'loadend'
  4107. // readystatechange (for historical reasons)
  4108. ];
  4109. var NATIVE = 1, RUNTIME = 2;
  4110. function XMLHttpRequest() {
  4111. var self = this,
  4112. // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible
  4113. props = {
  4114. /**
  4115. The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout.
  4116. @property timeout
  4117. @type Number
  4118. @default 0
  4119. */
  4120. timeout: 0,
  4121. /**
  4122. Current state, can take following values:
  4123. UNSENT (numeric value 0)
  4124. The object has been constructed.
  4125. OPENED (numeric value 1)
  4126. The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method.
  4127. HEADERS_RECEIVED (numeric value 2)
  4128. All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available.
  4129. LOADING (numeric value 3)
  4130. The response entity body is being received.
  4131. DONE (numeric value 4)
  4132. @property readyState
  4133. @type Number
  4134. @default 0 (UNSENT)
  4135. */
  4136. readyState: XMLHttpRequest.UNSENT,
  4137. /**
  4138. True when user credentials are to be included in a cross-origin request. False when they are to be excluded
  4139. in a cross-origin request and when cookies are to be ignored in its response. Initially false.
  4140. @property withCredentials
  4141. @type Boolean
  4142. @default false
  4143. */
  4144. withCredentials: false,
  4145. /**
  4146. Returns the HTTP status code.
  4147. @property status
  4148. @type Number
  4149. @default 0
  4150. */
  4151. status: 0,
  4152. /**
  4153. Returns the HTTP status text.
  4154. @property statusText
  4155. @type String
  4156. */
  4157. statusText: "",
  4158. /**
  4159. Returns the response type. Can be set to change the response type. Values are:
  4160. the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
  4161. @property responseType
  4162. @type String
  4163. */
  4164. responseType: "",
  4165. /**
  4166. Returns the document response entity body.
  4167. Throws an "InvalidStateError" exception if responseType is not the empty string or "document".
  4168. @property responseXML
  4169. @type Document
  4170. */
  4171. responseXML: null,
  4172. /**
  4173. Returns the text response entity body.
  4174. Throws an "InvalidStateError" exception if responseType is not the empty string or "text".
  4175. @property responseText
  4176. @type String
  4177. */
  4178. responseText: null,
  4179. /**
  4180. Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body).
  4181. Can become: ArrayBuffer, Blob, Document, JSON, Text
  4182. @property response
  4183. @type Mixed
  4184. */
  4185. response: null
  4186. },
  4187. _async = true,
  4188. _url,
  4189. _method,
  4190. _headers = {},
  4191. _user,
  4192. _password,
  4193. _encoding = null,
  4194. _mimeType = null,
  4195. // flags
  4196. _sync_flag = false,
  4197. _send_flag = false,
  4198. _upload_events_flag = false,
  4199. _upload_complete_flag = false,
  4200. _error_flag = false,
  4201. _same_origin_flag = false,
  4202. // times
  4203. _start_time,
  4204. _timeoutset_time,
  4205. _finalMime = null,
  4206. _finalCharset = null,
  4207. _options = {},
  4208. _xhr,
  4209. _responseHeaders = '',
  4210. _responseHeadersBag
  4211. ;
  4212. Basic.extend(this, props, {
  4213. /**
  4214. Unique id of the component
  4215. @property uid
  4216. @type String
  4217. */
  4218. uid: Basic.guid('uid_'),
  4219. /**
  4220. Target for Upload events
  4221. @property upload
  4222. @type XMLHttpRequestUpload
  4223. */
  4224. upload: new XMLHttpRequestUpload(),
  4225. /**
  4226. Sets the request method, request URL, synchronous flag, request username, and request password.
  4227. Throws a "SyntaxError" exception if one of the following is true:
  4228. method is not a valid HTTP method.
  4229. url cannot be resolved.
  4230. url contains the "user:password" format in the userinfo production.
  4231. Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK.
  4232. Throws an "InvalidAccessError" exception if one of the following is true:
  4233. Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin.
  4234. There is an associated XMLHttpRequest document and either the timeout attribute is not zero,
  4235. the withCredentials attribute is true, or the responseType attribute is not the empty string.
  4236. @method open
  4237. @param {String} method HTTP method to use on request
  4238. @param {String} url URL to request
  4239. @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default.
  4240. @param {String} [user] Username to use in HTTP authentication process on server-side
  4241. @param {String} [password] Password to use in HTTP authentication process on server-side
  4242. */
  4243. open: function(method, url, async, user, password) {
  4244. var urlp;
  4245. // first two arguments are required
  4246. if (!method || !url) {
  4247. throw new x.DOMException(x.DOMException.SYNTAX_ERR);
  4248. }
  4249. // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method
  4250. if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) {
  4251. throw new x.DOMException(x.DOMException.SYNTAX_ERR);
  4252. }
  4253. // 3
  4254. if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {
  4255. _method = method.toUpperCase();
  4256. }
  4257. // 4 - allowing these methods poses a security risk
  4258. if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {
  4259. throw new x.DOMException(x.DOMException.SECURITY_ERR);
  4260. }
  4261. // 5
  4262. url = Encode.utf8_encode(url);
  4263. // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError".
  4264. urlp = Url.parseUrl(url);
  4265. _same_origin_flag = Url.hasSameOrigin(urlp);
  4266. // 7 - manually build up absolute url
  4267. _url = Url.resolveUrl(url);
  4268. // 9-10, 12-13
  4269. if ((user || password) && !_same_origin_flag) {
  4270. throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
  4271. }
  4272. _user = user || urlp.user;
  4273. _password = password || urlp.pass;
  4274. // 11
  4275. _async = async || true;
  4276. if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {
  4277. throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
  4278. }
  4279. // 14 - terminate abort()
  4280. // 15 - terminate send()
  4281. // 18
  4282. _sync_flag = !_async;
  4283. _send_flag = false;
  4284. _headers = {};
  4285. _reset.call(this);
  4286. // 19
  4287. _p('readyState', XMLHttpRequest.OPENED);
  4288. // 20
  4289. this.dispatchEvent('readystatechange');
  4290. },
  4291. /**
  4292. Appends an header to the list of author request headers, or if header is already
  4293. in the list of author request headers, combines its value with value.
  4294. Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
  4295. Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value
  4296. is not a valid HTTP header field value.
  4297. @method setRequestHeader
  4298. @param {String} header
  4299. @param {String|Number} value
  4300. */
  4301. setRequestHeader: function(header, value) {
  4302. var uaHeaders = [ // these headers are controlled by the user agent
  4303. "accept-charset",
  4304. "accept-encoding",
  4305. "access-control-request-headers",
  4306. "access-control-request-method",
  4307. "connection",
  4308. "content-length",
  4309. "cookie",
  4310. "cookie2",
  4311. "content-transfer-encoding",
  4312. "date",
  4313. "expect",
  4314. "host",
  4315. "keep-alive",
  4316. "origin",
  4317. "referer",
  4318. "te",
  4319. "trailer",
  4320. "transfer-encoding",
  4321. "upgrade",
  4322. "user-agent",
  4323. "via"
  4324. ];
  4325. // 1-2
  4326. if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) {
  4327. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4328. }
  4329. // 3
  4330. if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) {
  4331. throw new x.DOMException(x.DOMException.SYNTAX_ERR);
  4332. }
  4333. // 4
  4334. /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values
  4335. if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {
  4336. throw new x.DOMException(x.DOMException.SYNTAX_ERR);
  4337. }*/
  4338. header = Basic.trim(header).toLowerCase();
  4339. // setting of proxy-* and sec-* headers is prohibited by spec
  4340. if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) {
  4341. return false;
  4342. }
  4343. // camelize
  4344. // browsers lowercase header names (at least for custom ones)
  4345. // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });
  4346. if (!_headers[header]) {
  4347. _headers[header] = value;
  4348. } else {
  4349. // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph)
  4350. _headers[header] += ', ' + value;
  4351. }
  4352. return true;
  4353. },
  4354. /**
  4355. * Test if the specified header is already set on this request.
  4356. * Returns a header value or boolean false if it's not yet set.
  4357. *
  4358. * @method hasRequestHeader
  4359. * @param {String} header Name of the header to test
  4360. * @return {Boolean|String}
  4361. */
  4362. hasRequestHeader: function(header) {
  4363. return header && _headers[header.toLowerCase()] || false;
  4364. },
  4365. /**
  4366. Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
  4367. @method getAllResponseHeaders
  4368. @return {String} reponse headers or empty string
  4369. */
  4370. getAllResponseHeaders: function() {
  4371. return _responseHeaders || '';
  4372. },
  4373. /**
  4374. Returns the header field value from the response of which the field name matches header,
  4375. unless the field name is Set-Cookie or Set-Cookie2.
  4376. @method getResponseHeader
  4377. @param {String} header
  4378. @return {String} value(s) for the specified header or null
  4379. */
  4380. getResponseHeader: function(header) {
  4381. header = header.toLowerCase();
  4382. if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) {
  4383. return null;
  4384. }
  4385. if (_responseHeaders && _responseHeaders !== '') {
  4386. // if we didn't parse response headers until now, do it and keep for later
  4387. if (!_responseHeadersBag) {
  4388. _responseHeadersBag = {};
  4389. Basic.each(_responseHeaders.split(/\r\n/), function(line) {
  4390. var pair = line.split(/:\s+/);
  4391. if (pair.length === 2) { // last line might be empty, omit
  4392. pair[0] = Basic.trim(pair[0]); // just in case
  4393. _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form
  4394. header: pair[0],
  4395. value: Basic.trim(pair[1])
  4396. };
  4397. }
  4398. });
  4399. }
  4400. if (_responseHeadersBag.hasOwnProperty(header)) {
  4401. return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value;
  4402. }
  4403. }
  4404. return null;
  4405. },
  4406. /**
  4407. Sets the Content-Type header for the response to mime.
  4408. Throws an "InvalidStateError" exception if the state is LOADING or DONE.
  4409. Throws a "SyntaxError" exception if mime is not a valid media type.
  4410. @method overrideMimeType
  4411. @param String mime Mime type to set
  4412. */
  4413. overrideMimeType: function(mime) {
  4414. var matches, charset;
  4415. // 1
  4416. if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
  4417. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4418. }
  4419. // 2
  4420. mime = Basic.trim(mime.toLowerCase());
  4421. if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) {
  4422. mime = matches[1];
  4423. if (matches[2]) {
  4424. charset = matches[2];
  4425. }
  4426. }
  4427. if (!Mime.mimes[mime]) {
  4428. throw new x.DOMException(x.DOMException.SYNTAX_ERR);
  4429. }
  4430. // 3-4
  4431. _finalMime = mime;
  4432. _finalCharset = charset;
  4433. },
  4434. /**
  4435. Initiates the request. The optional argument provides the request entity body.
  4436. The argument is ignored if request method is GET or HEAD.
  4437. Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
  4438. @method send
  4439. @param {Blob|Document|String|FormData} [data] Request entity body
  4440. @param {Object} [options] Set of requirements and pre-requisities for runtime initialization
  4441. */
  4442. send: function(data, options) {
  4443. if (Basic.typeOf(options) === 'string') {
  4444. _options = { ruid: options };
  4445. } else if (!options) {
  4446. _options = {};
  4447. } else {
  4448. _options = options;
  4449. }
  4450. // 1-2
  4451. if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) {
  4452. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4453. }
  4454. // 3
  4455. // sending Blob
  4456. if (data instanceof Blob) {
  4457. _options.ruid = data.ruid;
  4458. _mimeType = data.type || 'application/octet-stream';
  4459. }
  4460. // FormData
  4461. else if (data instanceof FormData) {
  4462. if (data.hasBlob()) {
  4463. var blob = data.getBlob();
  4464. _options.ruid = blob.ruid;
  4465. _mimeType = blob.type || 'application/octet-stream';
  4466. }
  4467. }
  4468. // DOMString
  4469. else if (typeof data === 'string') {
  4470. _encoding = 'UTF-8';
  4471. _mimeType = 'text/plain;charset=UTF-8';
  4472. // data should be converted to Unicode and encoded as UTF-8
  4473. data = Encode.utf8_encode(data);
  4474. }
  4475. // if withCredentials not set, but requested, set it automatically
  4476. if (!this.withCredentials) {
  4477. this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag;
  4478. }
  4479. // 4 - storage mutex
  4480. // 5
  4481. _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP
  4482. // 6
  4483. _error_flag = false;
  4484. // 7
  4485. _upload_complete_flag = !data;
  4486. // 8 - Asynchronous steps
  4487. if (!_sync_flag) {
  4488. // 8.1
  4489. _send_flag = true;
  4490. // 8.2
  4491. // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
  4492. // 8.3
  4493. //if (!_upload_complete_flag) {
  4494. // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
  4495. //}
  4496. }
  4497. // 8.5 - Return the send() method call, but continue running the steps in this algorithm.
  4498. _doXHR.call(this, data);
  4499. },
  4500. /**
  4501. Cancels any network activity.
  4502. @method abort
  4503. */
  4504. abort: function() {
  4505. _error_flag = true;
  4506. _sync_flag = false;
  4507. if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) {
  4508. _p('readyState', XMLHttpRequest.DONE);
  4509. _send_flag = false;
  4510. if (_xhr) {
  4511. _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag);
  4512. } else {
  4513. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4514. }
  4515. _upload_complete_flag = true;
  4516. } else {
  4517. _p('readyState', XMLHttpRequest.UNSENT);
  4518. }
  4519. },
  4520. destroy: function() {
  4521. if (_xhr) {
  4522. if (Basic.typeOf(_xhr.destroy) === 'function') {
  4523. _xhr.destroy();
  4524. }
  4525. _xhr = null;
  4526. }
  4527. this.unbindAll();
  4528. if (this.upload) {
  4529. this.upload.unbindAll();
  4530. this.upload = null;
  4531. }
  4532. }
  4533. });
  4534. this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons
  4535. this.upload.handleEventProps(dispatches);
  4536. /* this is nice, but maybe too lengthy
  4537. // if supported by JS version, set getters/setters for specific properties
  4538. o.defineProperty(this, 'readyState', {
  4539. configurable: false,
  4540. get: function() {
  4541. return _p('readyState');
  4542. }
  4543. });
  4544. o.defineProperty(this, 'timeout', {
  4545. configurable: false,
  4546. get: function() {
  4547. return _p('timeout');
  4548. },
  4549. set: function(value) {
  4550. if (_sync_flag) {
  4551. throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
  4552. }
  4553. // timeout still should be measured relative to the start time of request
  4554. _timeoutset_time = (new Date).getTime();
  4555. _p('timeout', value);
  4556. }
  4557. });
  4558. // the withCredentials attribute has no effect when fetching same-origin resources
  4559. o.defineProperty(this, 'withCredentials', {
  4560. configurable: false,
  4561. get: function() {
  4562. return _p('withCredentials');
  4563. },
  4564. set: function(value) {
  4565. // 1-2
  4566. if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) {
  4567. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4568. }
  4569. // 3-4
  4570. if (_anonymous_flag || _sync_flag) {
  4571. throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
  4572. }
  4573. // 5
  4574. _p('withCredentials', value);
  4575. }
  4576. });
  4577. o.defineProperty(this, 'status', {
  4578. configurable: false,
  4579. get: function() {
  4580. return _p('status');
  4581. }
  4582. });
  4583. o.defineProperty(this, 'statusText', {
  4584. configurable: false,
  4585. get: function() {
  4586. return _p('statusText');
  4587. }
  4588. });
  4589. o.defineProperty(this, 'responseType', {
  4590. configurable: false,
  4591. get: function() {
  4592. return _p('responseType');
  4593. },
  4594. set: function(value) {
  4595. // 1
  4596. if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
  4597. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4598. }
  4599. // 2
  4600. if (_sync_flag) {
  4601. throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
  4602. }
  4603. // 3
  4604. _p('responseType', value.toLowerCase());
  4605. }
  4606. });
  4607. o.defineProperty(this, 'responseText', {
  4608. configurable: false,
  4609. get: function() {
  4610. // 1
  4611. if (!~o.inArray(_p('responseType'), ['', 'text'])) {
  4612. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4613. }
  4614. // 2-3
  4615. if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
  4616. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4617. }
  4618. return _p('responseText');
  4619. }
  4620. });
  4621. o.defineProperty(this, 'responseXML', {
  4622. configurable: false,
  4623. get: function() {
  4624. // 1
  4625. if (!~o.inArray(_p('responseType'), ['', 'document'])) {
  4626. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4627. }
  4628. // 2-3
  4629. if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
  4630. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  4631. }
  4632. return _p('responseXML');
  4633. }
  4634. });
  4635. o.defineProperty(this, 'response', {
  4636. configurable: false,
  4637. get: function() {
  4638. if (!!~o.inArray(_p('responseType'), ['', 'text'])) {
  4639. if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
  4640. return '';
  4641. }
  4642. }
  4643. if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
  4644. return null;
  4645. }
  4646. return _p('response');
  4647. }
  4648. });
  4649. */
  4650. function _p(prop, value) {
  4651. if (!props.hasOwnProperty(prop)) {
  4652. return;
  4653. }
  4654. if (arguments.length === 1) { // get
  4655. return Env.can('define_property') ? props[prop] : self[prop];
  4656. } else { // set
  4657. if (Env.can('define_property')) {
  4658. props[prop] = value;
  4659. } else {
  4660. self[prop] = value;
  4661. }
  4662. }
  4663. }
  4664. /*
  4665. function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) {
  4666. // TODO: http://tools.ietf.org/html/rfc3490#section-4.1
  4667. return str.toLowerCase();
  4668. }
  4669. */
  4670. function _doXHR(data) {
  4671. var self = this;
  4672. _start_time = new Date().getTime();
  4673. _xhr = new RuntimeTarget();
  4674. function loadEnd() {
  4675. if (_xhr) { // it could have been destroyed by now
  4676. _xhr.destroy();
  4677. _xhr = null;
  4678. }
  4679. self.dispatchEvent('loadend');
  4680. self = null;
  4681. }
  4682. function exec(runtime) {
  4683. _xhr.bind('LoadStart', function(e) {
  4684. _p('readyState', XMLHttpRequest.LOADING);
  4685. self.dispatchEvent('readystatechange');
  4686. self.dispatchEvent(e);
  4687. if (_upload_events_flag) {
  4688. self.upload.dispatchEvent(e);
  4689. }
  4690. });
  4691. _xhr.bind('Progress', function(e) {
  4692. if (_p('readyState') !== XMLHttpRequest.LOADING) {
  4693. _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example)
  4694. self.dispatchEvent('readystatechange');
  4695. }
  4696. self.dispatchEvent(e);
  4697. });
  4698. _xhr.bind('UploadProgress', function(e) {
  4699. if (_upload_events_flag) {
  4700. self.upload.dispatchEvent({
  4701. type: 'progress',
  4702. lengthComputable: false,
  4703. total: e.total,
  4704. loaded: e.loaded
  4705. });
  4706. }
  4707. });
  4708. _xhr.bind('Load', function(e) {
  4709. _p('readyState', XMLHttpRequest.DONE);
  4710. _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0));
  4711. _p('statusText', httpCode[_p('status')] || "");
  4712. _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType')));
  4713. if (!!~Basic.inArray(_p('responseType'), ['text', ''])) {
  4714. _p('responseText', _p('response'));
  4715. } else if (_p('responseType') === 'document') {
  4716. _p('responseXML', _p('response'));
  4717. }
  4718. _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders');
  4719. self.dispatchEvent('readystatechange');
  4720. if (_p('status') > 0) { // status 0 usually means that server is unreachable
  4721. if (_upload_events_flag) {
  4722. self.upload.dispatchEvent(e);
  4723. }
  4724. self.dispatchEvent(e);
  4725. } else {
  4726. _error_flag = true;
  4727. self.dispatchEvent('error');
  4728. }
  4729. loadEnd();
  4730. });
  4731. _xhr.bind('Abort', function(e) {
  4732. self.dispatchEvent(e);
  4733. loadEnd();
  4734. });
  4735. _xhr.bind('Error', function(e) {
  4736. _error_flag = true;
  4737. _p('readyState', XMLHttpRequest.DONE);
  4738. self.dispatchEvent('readystatechange');
  4739. _upload_complete_flag = true;
  4740. self.dispatchEvent(e);
  4741. loadEnd();
  4742. });
  4743. runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', {
  4744. url: _url,
  4745. method: _method,
  4746. async: _async,
  4747. user: _user,
  4748. password: _password,
  4749. headers: _headers,
  4750. mimeType: _mimeType,
  4751. encoding: _encoding,
  4752. responseType: self.responseType,
  4753. withCredentials: self.withCredentials,
  4754. options: _options
  4755. }, data);
  4756. }
  4757. // clarify our requirements
  4758. if (typeof(_options.required_caps) === 'string') {
  4759. _options.required_caps = Runtime.parseCaps(_options.required_caps);
  4760. }
  4761. _options.required_caps = Basic.extend({}, _options.required_caps, {
  4762. return_response_type: self.responseType
  4763. });
  4764. if (data instanceof FormData) {
  4765. _options.required_caps.send_multipart = true;
  4766. }
  4767. if (!Basic.isEmptyObj(_headers)) {
  4768. _options.required_caps.send_custom_headers = true;
  4769. }
  4770. if (!_same_origin_flag) {
  4771. _options.required_caps.do_cors = true;
  4772. }
  4773. if (_options.ruid) { // we do not need to wait if we can connect directly
  4774. exec(_xhr.connectRuntime(_options));
  4775. } else {
  4776. _xhr.bind('RuntimeInit', function(e, runtime) {
  4777. exec(runtime);
  4778. });
  4779. _xhr.bind('RuntimeError', function(e, err) {
  4780. self.dispatchEvent('RuntimeError', err);
  4781. });
  4782. _xhr.connectRuntime(_options);
  4783. }
  4784. }
  4785. function _reset() {
  4786. _p('responseText', "");
  4787. _p('responseXML', null);
  4788. _p('response', null);
  4789. _p('status', 0);
  4790. _p('statusText', "");
  4791. _start_time = _timeoutset_time = null;
  4792. }
  4793. }
  4794. XMLHttpRequest.UNSENT = 0;
  4795. XMLHttpRequest.OPENED = 1;
  4796. XMLHttpRequest.HEADERS_RECEIVED = 2;
  4797. XMLHttpRequest.LOADING = 3;
  4798. XMLHttpRequest.DONE = 4;
  4799. XMLHttpRequest.prototype = EventTarget.instance;
  4800. return XMLHttpRequest;
  4801. });
  4802. // Included from: src/javascript/runtime/Transporter.js
  4803. /**
  4804. * Transporter.js
  4805. *
  4806. * Copyright 2013, Moxiecode Systems AB
  4807. * Released under GPL License.
  4808. *
  4809. * License: http://www.plupload.com/license
  4810. * Contributing: http://www.plupload.com/contributing
  4811. */
  4812. define("moxie/runtime/Transporter", [
  4813. "moxie/core/utils/Basic",
  4814. "moxie/core/utils/Encode",
  4815. "moxie/runtime/RuntimeClient",
  4816. "moxie/core/EventTarget"
  4817. ], function(Basic, Encode, RuntimeClient, EventTarget) {
  4818. /**
  4819. @class moxie/runtime/Transporter
  4820. @private
  4821. @constructor
  4822. */
  4823. function Transporter() {
  4824. var mod, _runtime, _data, _size, _pos, _chunk_size;
  4825. RuntimeClient.call(this);
  4826. Basic.extend(this, {
  4827. uid: Basic.guid('uid_'),
  4828. state: Transporter.IDLE,
  4829. result: null,
  4830. transport: function(data, type, options) {
  4831. var self = this;
  4832. options = Basic.extend({
  4833. chunk_size: 204798
  4834. }, options);
  4835. // should divide by three, base64 requires this
  4836. if ((mod = options.chunk_size % 3)) {
  4837. options.chunk_size += 3 - mod;
  4838. }
  4839. _chunk_size = options.chunk_size;
  4840. _reset.call(this);
  4841. _data = data;
  4842. _size = data.length;
  4843. if (Basic.typeOf(options) === 'string' || options.ruid) {
  4844. _run.call(self, type, this.connectRuntime(options));
  4845. } else {
  4846. // we require this to run only once
  4847. var cb = function(e, runtime) {
  4848. self.unbind("RuntimeInit", cb);
  4849. _run.call(self, type, runtime);
  4850. };
  4851. this.bind("RuntimeInit", cb);
  4852. this.connectRuntime(options);
  4853. }
  4854. },
  4855. abort: function() {
  4856. var self = this;
  4857. self.state = Transporter.IDLE;
  4858. if (_runtime) {
  4859. _runtime.exec.call(self, 'Transporter', 'clear');
  4860. self.trigger("TransportingAborted");
  4861. }
  4862. _reset.call(self);
  4863. },
  4864. destroy: function() {
  4865. this.unbindAll();
  4866. _runtime = null;
  4867. this.disconnectRuntime();
  4868. _reset.call(this);
  4869. }
  4870. });
  4871. function _reset() {
  4872. _size = _pos = 0;
  4873. _data = this.result = null;
  4874. }
  4875. function _run(type, runtime) {
  4876. var self = this;
  4877. _runtime = runtime;
  4878. //self.unbind("RuntimeInit");
  4879. self.bind("TransportingProgress", function(e) {
  4880. _pos = e.loaded;
  4881. if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) {
  4882. _transport.call(self);
  4883. }
  4884. }, 999);
  4885. self.bind("TransportingComplete", function() {
  4886. _pos = _size;
  4887. self.state = Transporter.DONE;
  4888. _data = null; // clean a bit
  4889. self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || '');
  4890. }, 999);
  4891. self.state = Transporter.BUSY;
  4892. self.trigger("TransportingStarted");
  4893. _transport.call(self);
  4894. }
  4895. function _transport() {
  4896. var self = this,
  4897. chunk,
  4898. bytesLeft = _size - _pos;
  4899. if (_chunk_size > bytesLeft) {
  4900. _chunk_size = bytesLeft;
  4901. }
  4902. chunk = Encode.btoa(_data.substr(_pos, _chunk_size));
  4903. _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size);
  4904. }
  4905. }
  4906. Transporter.IDLE = 0;
  4907. Transporter.BUSY = 1;
  4908. Transporter.DONE = 2;
  4909. Transporter.prototype = EventTarget.instance;
  4910. return Transporter;
  4911. });
  4912. // Included from: src/javascript/image/Image.js
  4913. /**
  4914. * Image.js
  4915. *
  4916. * Copyright 2013, Moxiecode Systems AB
  4917. * Released under GPL License.
  4918. *
  4919. * License: http://www.plupload.com/license
  4920. * Contributing: http://www.plupload.com/contributing
  4921. */
  4922. define("moxie/image/Image", [
  4923. "moxie/core/utils/Basic",
  4924. "moxie/core/utils/Dom",
  4925. "moxie/core/Exceptions",
  4926. "moxie/file/FileReaderSync",
  4927. "moxie/xhr/XMLHttpRequest",
  4928. "moxie/runtime/Runtime",
  4929. "moxie/runtime/RuntimeClient",
  4930. "moxie/runtime/Transporter",
  4931. "moxie/core/utils/Env",
  4932. "moxie/core/EventTarget",
  4933. "moxie/file/Blob",
  4934. "moxie/file/File",
  4935. "moxie/core/utils/Encode"
  4936. ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {
  4937. /**
  4938. Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
  4939. @class moxie/image/Image
  4940. @constructor
  4941. @extends EventTarget
  4942. */
  4943. var dispatches = [
  4944. 'progress',
  4945. /**
  4946. Dispatched when loading is complete.
  4947. @event load
  4948. @param {Object} event
  4949. */
  4950. 'load',
  4951. 'error',
  4952. /**
  4953. Dispatched when resize operation is complete.
  4954. @event resize
  4955. @param {Object} event
  4956. */
  4957. 'resize',
  4958. /**
  4959. Dispatched when visual representation of the image is successfully embedded
  4960. into the corresponsing container.
  4961. @event embedded
  4962. @param {Object} event
  4963. */
  4964. 'embedded'
  4965. ];
  4966. function Image() {
  4967. RuntimeClient.call(this);
  4968. Basic.extend(this, {
  4969. /**
  4970. Unique id of the component
  4971. @property uid
  4972. @type {String}
  4973. */
  4974. uid: Basic.guid('uid_'),
  4975. /**
  4976. Unique id of the connected runtime, if any.
  4977. @property ruid
  4978. @type {String}
  4979. */
  4980. ruid: null,
  4981. /**
  4982. Name of the file, that was used to create an image, if available. If not equals to empty string.
  4983. @property name
  4984. @type {String}
  4985. @default ""
  4986. */
  4987. name: "",
  4988. /**
  4989. Size of the image in bytes. Actual value is set only after image is preloaded.
  4990. @property size
  4991. @type {Number}
  4992. @default 0
  4993. */
  4994. size: 0,
  4995. /**
  4996. Width of the image. Actual value is set only after image is preloaded.
  4997. @property width
  4998. @type {Number}
  4999. @default 0
  5000. */
  5001. width: 0,
  5002. /**
  5003. Height of the image. Actual value is set only after image is preloaded.
  5004. @property height
  5005. @type {Number}
  5006. @default 0
  5007. */
  5008. height: 0,
  5009. /**
  5010. Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded.
  5011. @property type
  5012. @type {String}
  5013. @default ""
  5014. */
  5015. type: "",
  5016. /**
  5017. Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded.
  5018. @property meta
  5019. @type {Object}
  5020. @default {}
  5021. */
  5022. meta: {},
  5023. /**
  5024. Alias for load method, that takes another moxie.image.Image object as a source (see load).
  5025. @method clone
  5026. @param {Image} src Source for the image
  5027. @param {Boolean} [exact=false] Whether to activate in-depth clone mode
  5028. */
  5029. clone: function() {
  5030. this.load.apply(this, arguments);
  5031. },
  5032. /**
  5033. Loads image from various sources. Currently the source for new image can be: moxie.image.Image,
  5034. moxie.file.Blob/moxie.file.File, native Blob/File, dataUrl or URL. Depending on the type of the
  5035. source, arguments - differ. When source is URL, Image will be downloaded from remote destination
  5036. and loaded in memory.
  5037. @example
  5038. var img = new moxie.image.Image();
  5039. img.onload = function() {
  5040. var blob = img.getAsBlob();
  5041. var formData = new moxie.xhr.FormData();
  5042. formData.append('file', blob);
  5043. var xhr = new moxie.xhr.XMLHttpRequest();
  5044. xhr.onload = function() {
  5045. // upload complete
  5046. };
  5047. xhr.open('post', 'upload.php');
  5048. xhr.send(formData);
  5049. };
  5050. img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)
  5051. @method load
  5052. @param {Image|Blob|File|String} src Source for the image
  5053. @param {Boolean|Object} [mixed]
  5054. */
  5055. load: function() {
  5056. _load.apply(this, arguments);
  5057. },
  5058. /**
  5059. Resizes the image to fit the specified width/height. If crop is specified, image will also be
  5060. cropped to the exact dimensions.
  5061. @method resize
  5062. @since 3.0
  5063. @param {Object} options
  5064. @param {Number} options.width Resulting width
  5065. @param {Number} [options.height=width] Resulting height (optional, if not supplied will default to width)
  5066. @param {String} [options.type='image/jpeg'] MIME type of the resulting image
  5067. @param {Number} [options.quality=90] In the case of JPEG, controls the quality of resulting image
  5068. @param {Boolean} [options.crop='cc'] If not falsy, image will be cropped, by default from center
  5069. @param {Boolean} [options.fit=true] Whether to upscale the image to fit the exact dimensions
  5070. @param {Boolean} [options.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
  5071. @param {String} [options.resample='default'] Resampling algorithm to use during resize
  5072. @param {Boolean} [options.multipass=true] Whether to scale the image in steps (results in better quality)
  5073. */
  5074. resize: function(options) {
  5075. var self = this;
  5076. var orientation;
  5077. var scale;
  5078. var srcRect = {
  5079. x: 0,
  5080. y: 0,
  5081. width: self.width,
  5082. height: self.height
  5083. };
  5084. var opts = Basic.extendIf({
  5085. width: self.width,
  5086. height: self.height,
  5087. type: self.type || 'image/jpeg',
  5088. quality: 90,
  5089. crop: false,
  5090. fit: true,
  5091. preserveHeaders: true,
  5092. resample: 'default',
  5093. multipass: true
  5094. }, options);
  5095. try {
  5096. if (!self.size) { // only preloaded image objects can be used as source
  5097. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  5098. }
  5099. // no way to reliably intercept the crash due to high resolution, so we simply avoid it
  5100. if (self.width > Image.MAX_RESIZE_WIDTH || self.height > Image.MAX_RESIZE_HEIGHT) {
  5101. throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
  5102. }
  5103. // take into account orientation tag
  5104. orientation = (self.meta && self.meta.tiff && self.meta.tiff.Orientation) || 1;
  5105. if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
  5106. var tmp = opts.width;
  5107. opts.width = opts.height;
  5108. opts.height = tmp;
  5109. }
  5110. if (opts.crop) {
  5111. scale = Math.max(opts.width/self.width, opts.height/self.height);
  5112. if (options.fit) {
  5113. // first scale it up or down to fit the original image
  5114. srcRect.width = Math.min(Math.ceil(opts.width/scale), self.width);
  5115. srcRect.height = Math.min(Math.ceil(opts.height/scale), self.height);
  5116. // recalculate the scale for adapted dimensions
  5117. scale = opts.width/srcRect.width;
  5118. } else {
  5119. srcRect.width = Math.min(opts.width, self.width);
  5120. srcRect.height = Math.min(opts.height, self.height);
  5121. // now we do not need to scale it any further
  5122. scale = 1;
  5123. }
  5124. if (typeof(opts.crop) === 'boolean') {
  5125. opts.crop = 'cc';
  5126. }
  5127. switch (opts.crop.toLowerCase().replace(/_/, '-')) {
  5128. case 'rb':
  5129. case 'right-bottom':
  5130. srcRect.x = self.width - srcRect.width;
  5131. srcRect.y = self.height - srcRect.height;
  5132. break;
  5133. case 'cb':
  5134. case 'center-bottom':
  5135. srcRect.x = Math.floor((self.width - srcRect.width) / 2);
  5136. srcRect.y = self.height - srcRect.height;
  5137. break;
  5138. case 'lb':
  5139. case 'left-bottom':
  5140. srcRect.x = 0;
  5141. srcRect.y = self.height - srcRect.height;
  5142. break;
  5143. case 'lt':
  5144. case 'left-top':
  5145. srcRect.x = 0;
  5146. srcRect.y = 0;
  5147. break;
  5148. case 'ct':
  5149. case 'center-top':
  5150. srcRect.x = Math.floor((self.width - srcRect.width) / 2);
  5151. srcRect.y = 0;
  5152. break;
  5153. case 'rt':
  5154. case 'right-top':
  5155. srcRect.x = self.width - srcRect.width;
  5156. srcRect.y = 0;
  5157. break;
  5158. case 'rc':
  5159. case 'right-center':
  5160. case 'right-middle':
  5161. srcRect.x = self.width - srcRect.width;
  5162. srcRect.y = Math.floor((self.height - srcRect.height) / 2);
  5163. break;
  5164. case 'lc':
  5165. case 'left-center':
  5166. case 'left-middle':
  5167. srcRect.x = 0;
  5168. srcRect.y = Math.floor((self.height - srcRect.height) / 2);
  5169. break;
  5170. case 'cc':
  5171. case 'center-center':
  5172. case 'center-middle':
  5173. default:
  5174. srcRect.x = Math.floor((self.width - srcRect.width) / 2);
  5175. srcRect.y = Math.floor((self.height - srcRect.height) / 2);
  5176. }
  5177. // original image might be smaller than requested crop, so - avoid negative values
  5178. srcRect.x = Math.max(srcRect.x, 0);
  5179. srcRect.y = Math.max(srcRect.y, 0);
  5180. } else {
  5181. scale = Math.min(opts.width/self.width, opts.height/self.height);
  5182. // do not upscale if we were asked to not fit it
  5183. if (scale > 1 && !opts.fit) {
  5184. scale = 1;
  5185. }
  5186. }
  5187. this.exec('Image', 'resize', srcRect, scale, opts);
  5188. } catch(ex) {
  5189. // for now simply trigger error event
  5190. self.trigger('error', ex.code);
  5191. }
  5192. },
  5193. /**
  5194. Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
  5195. @method downsize
  5196. @deprecated use resize()
  5197. */
  5198. downsize: function(options) {
  5199. var defaults = {
  5200. width: this.width,
  5201. height: this.height,
  5202. type: this.type || 'image/jpeg',
  5203. quality: 90,
  5204. crop: false,
  5205. fit: false,
  5206. preserveHeaders: true,
  5207. resample: 'default'
  5208. }, opts;
  5209. if (typeof(options) === 'object') {
  5210. opts = Basic.extend(defaults, options);
  5211. } else {
  5212. // for backward compatibility
  5213. opts = Basic.extend(defaults, {
  5214. width: arguments[0],
  5215. height: arguments[1],
  5216. crop: arguments[2],
  5217. preserveHeaders: arguments[3]
  5218. });
  5219. }
  5220. this.resize(opts);
  5221. },
  5222. /**
  5223. Alias for downsize(width, height, true). (see downsize)
  5224. @method crop
  5225. @param {Number} width Resulting width
  5226. @param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
  5227. @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
  5228. */
  5229. crop: function(width, height, preserveHeaders) {
  5230. this.downsize(width, height, true, preserveHeaders);
  5231. },
  5232. getAsCanvas: function() {
  5233. if (!Env.can('create_canvas')) {
  5234. throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
  5235. }
  5236. return this.exec('Image', 'getAsCanvas');
  5237. },
  5238. /**
  5239. Retrieves image in it's current state as moxie.file.Blob object. Cannot be run on empty or image in progress (throws
  5240. DOMException.INVALID_STATE_ERR).
  5241. @method getAsBlob
  5242. @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
  5243. @param {Number} [quality=90] Applicable only together with mime type image/jpeg
  5244. @return {Blob} Image as Blob
  5245. */
  5246. getAsBlob: function(type, quality) {
  5247. if (!this.size) {
  5248. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  5249. }
  5250. return this.exec('Image', 'getAsBlob', type || 'image/jpeg', quality || 90);
  5251. },
  5252. /**
  5253. Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws
  5254. DOMException.INVALID_STATE_ERR).
  5255. @method getAsDataURL
  5256. @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
  5257. @param {Number} [quality=90] Applicable only together with mime type image/jpeg
  5258. @return {String} Image as dataURL string
  5259. */
  5260. getAsDataURL: function(type, quality) {
  5261. if (!this.size) {
  5262. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  5263. }
  5264. return this.exec('Image', 'getAsDataURL', type || 'image/jpeg', quality || 90);
  5265. },
  5266. /**
  5267. Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws
  5268. DOMException.INVALID_STATE_ERR).
  5269. @method getAsBinaryString
  5270. @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
  5271. @param {Number} [quality=90] Applicable only together with mime type image/jpeg
  5272. @return {String} Image as binary string
  5273. */
  5274. getAsBinaryString: function(type, quality) {
  5275. var dataUrl = this.getAsDataURL(type, quality);
  5276. return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7));
  5277. },
  5278. /**
  5279. Embeds a visual representation of the image into the specified node. Depending on the runtime,
  5280. it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare,
  5281. can be used in legacy browsers that do not have canvas or proper dataURI support).
  5282. @method embed
  5283. @param {DOMElement} el DOM element to insert the image object into
  5284. @param {Object} [options]
  5285. @param {Number} [options.width] The width of an embed (defaults to the image width)
  5286. @param {Number} [options.height] The height of an embed (defaults to the image height)
  5287. @param {String} [options.type="image/jpeg"] Mime type
  5288. @param {Number} [options.quality=90] Quality of an embed, if mime type is image/jpeg
  5289. @param {Boolean} [options.crop=false] Whether to crop an embed to the specified dimensions
  5290. @param {Boolean} [options.fit=true] By default thumbs will be up- or downscaled as necessary to fit the dimensions
  5291. */
  5292. embed: function(el, options) {
  5293. var self = this
  5294. , runtime // this has to be outside of all the closures to contain proper runtime
  5295. ;
  5296. var opts = Basic.extend({
  5297. width: this.width,
  5298. height: this.height,
  5299. type: this.type || 'image/jpeg',
  5300. quality: 90,
  5301. fit: true,
  5302. resample: 'nearest'
  5303. }, options);
  5304. function render(type, quality) {
  5305. var img = this;
  5306. // if possible, embed a canvas element directly
  5307. if (Env.can('create_canvas')) {
  5308. var canvas = img.getAsCanvas();
  5309. if (canvas) {
  5310. el.appendChild(canvas);
  5311. canvas = null;
  5312. img.destroy();
  5313. self.trigger('embedded');
  5314. return;
  5315. }
  5316. }
  5317. var dataUrl = img.getAsDataURL(type, quality);
  5318. if (!dataUrl) {
  5319. throw new x.ImageError(x.ImageError.WRONG_FORMAT);
  5320. }
  5321. if (Env.can('use_data_uri_of', dataUrl.length)) {
  5322. el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" alt="" />';
  5323. img.destroy();
  5324. self.trigger('embedded');
  5325. } else {
  5326. var tr = new Transporter();
  5327. tr.bind("TransportingComplete", function() {
  5328. runtime = self.connectRuntime(this.result.ruid);
  5329. self.bind("Embedded", function() {
  5330. // position and size properly
  5331. Basic.extend(runtime.getShimContainer().style, {
  5332. //position: 'relative',
  5333. top: '0px',
  5334. left: '0px',
  5335. width: img.width + 'px',
  5336. height: img.height + 'px'
  5337. });
  5338. // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's
  5339. // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and
  5340. // sometimes 8 and they do not have this problem, we can comment this for now
  5341. /*tr.bind("RuntimeInit", function(e, runtime) {
  5342. tr.destroy();
  5343. runtime.destroy();
  5344. onResize.call(self); // re-feed our image data
  5345. });*/
  5346. runtime = null; // release
  5347. }, 999);
  5348. runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);
  5349. img.destroy();
  5350. });
  5351. tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, {
  5352. required_caps: {
  5353. display_media: true
  5354. },
  5355. runtime_order: 'flash,silverlight',
  5356. container: el
  5357. });
  5358. }
  5359. }
  5360. try {
  5361. if (!(el = Dom.get(el))) {
  5362. throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);
  5363. }
  5364. if (!this.size) { // only preloaded image objects can be used as source
  5365. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  5366. }
  5367. // high-resolution images cannot be consistently handled across the runtimes
  5368. if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
  5369. //throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
  5370. }
  5371. var imgCopy = new Image();
  5372. imgCopy.bind("Resize", function() {
  5373. render.call(this, opts.type, opts.quality);
  5374. });
  5375. imgCopy.bind("Load", function() {
  5376. this.downsize(opts);
  5377. });
  5378. // if embedded thumb data is available and dimensions are big enough, use it
  5379. if (this.meta.thumb && this.meta.thumb.width >= opts.width && this.meta.thumb.height >= opts.height) {
  5380. imgCopy.load(this.meta.thumb.data);
  5381. } else {
  5382. imgCopy.clone(this, false);
  5383. }
  5384. return imgCopy;
  5385. } catch(ex) {
  5386. // for now simply trigger error event
  5387. this.trigger('error', ex.code);
  5388. }
  5389. },
  5390. /**
  5391. Properly destroys the image and frees resources in use. If any. Recommended way to dispose
  5392. moxie.image.Image object.
  5393. @method destroy
  5394. */
  5395. destroy: function() {
  5396. if (this.ruid) {
  5397. this.getRuntime().exec.call(this, 'Image', 'destroy');
  5398. this.disconnectRuntime();
  5399. }
  5400. if (this.meta && this.meta.thumb) {
  5401. // thumb is blob, make sure we destroy it first
  5402. this.meta.thumb.data.destroy();
  5403. }
  5404. this.unbindAll();
  5405. }
  5406. });
  5407. // this is here, because in order to bind properly, we need uid, which is created above
  5408. this.handleEventProps(dispatches);
  5409. this.bind('Load Resize', function() {
  5410. return _updateInfo.call(this); // if operation fails (e.g. image is neither PNG nor JPEG) cancel all pending events
  5411. }, 999);
  5412. function _updateInfo(info) {
  5413. try {
  5414. if (!info) {
  5415. info = this.exec('Image', 'getInfo');
  5416. }
  5417. this.size = info.size;
  5418. this.width = info.width;
  5419. this.height = info.height;
  5420. this.type = info.type;
  5421. this.meta = info.meta;
  5422. // update file name, only if empty
  5423. if (this.name === '') {
  5424. this.name = info.name;
  5425. }
  5426. return true;
  5427. } catch(ex) {
  5428. this.trigger('error', ex.code);
  5429. return false;
  5430. }
  5431. }
  5432. function _load(src) {
  5433. var srcType = Basic.typeOf(src);
  5434. try {
  5435. // if source is Image
  5436. if (src instanceof Image) {
  5437. if (!src.size) { // only preloaded image objects can be used as source
  5438. throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
  5439. }
  5440. _loadFromImage.apply(this, arguments);
  5441. }
  5442. // if source is o.Blob/o.File
  5443. else if (src instanceof Blob) {
  5444. if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) {
  5445. throw new x.ImageError(x.ImageError.WRONG_FORMAT);
  5446. }
  5447. _loadFromBlob.apply(this, arguments);
  5448. }
  5449. // if native blob/file
  5450. else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) {
  5451. _load.call(this, new File(null, src), arguments[1]);
  5452. }
  5453. // if String
  5454. else if (srcType === 'string') {
  5455. // if dataUrl String
  5456. if (src.substr(0, 5) === 'data:') {
  5457. _load.call(this, new Blob(null, { data: src }), arguments[1]);
  5458. }
  5459. // else assume Url, either relative or absolute
  5460. else {
  5461. _loadFromUrl.apply(this, arguments);
  5462. }
  5463. }
  5464. // if source seems to be an img node
  5465. else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') {
  5466. _load.call(this, src.src, arguments[1]);
  5467. }
  5468. else {
  5469. throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR);
  5470. }
  5471. } catch(ex) {
  5472. // for now simply trigger error event
  5473. this.trigger('error', ex.code);
  5474. }
  5475. }
  5476. function _loadFromImage(img, exact) {
  5477. var runtime = this.connectRuntime(img.ruid);
  5478. this.ruid = runtime.uid;
  5479. runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact));
  5480. }
  5481. function _loadFromBlob(blob, options) {
  5482. var self = this;
  5483. self.name = blob.name || '';
  5484. function exec(runtime) {
  5485. self.ruid = runtime.uid;
  5486. runtime.exec.call(self, 'Image', 'loadFromBlob', blob);
  5487. }
  5488. if (blob.isDetached()) {
  5489. this.bind('RuntimeInit', function(e, runtime) {
  5490. exec(runtime);
  5491. });
  5492. // convert to object representation
  5493. if (options && typeof(options.required_caps) === 'string') {
  5494. options.required_caps = Runtime.parseCaps(options.required_caps);
  5495. }
  5496. this.connectRuntime(Basic.extend({
  5497. required_caps: {
  5498. access_image_binary: true,
  5499. resize_image: true
  5500. }
  5501. }, options));
  5502. } else {
  5503. exec(this.connectRuntime(blob.ruid));
  5504. }
  5505. }
  5506. function _loadFromUrl(url, options) {
  5507. var self = this, xhr;
  5508. xhr = new XMLHttpRequest();
  5509. xhr.open('get', url);
  5510. xhr.responseType = 'blob';
  5511. xhr.onprogress = function(e) {
  5512. self.trigger(e);
  5513. };
  5514. xhr.onload = function() {
  5515. _loadFromBlob.call(self, xhr.response, true);
  5516. };
  5517. xhr.onerror = function(e) {
  5518. self.trigger(e);
  5519. };
  5520. xhr.onloadend = function() {
  5521. xhr.destroy();
  5522. };
  5523. xhr.bind('RuntimeError', function(e, err) {
  5524. self.trigger('RuntimeError', err);
  5525. });
  5526. xhr.send(null, options);
  5527. }
  5528. }
  5529. // virtual world will crash on you if image has a resolution higher than this:
  5530. Image.MAX_RESIZE_WIDTH = 8192;
  5531. Image.MAX_RESIZE_HEIGHT = 8192;
  5532. Image.prototype = EventTarget.instance;
  5533. return Image;
  5534. });
  5535. // Included from: src/javascript/runtime/html5/Runtime.js
  5536. /**
  5537. * Runtime.js
  5538. *
  5539. * Copyright 2013, Moxiecode Systems AB
  5540. * Released under GPL License.
  5541. *
  5542. * License: http://www.plupload.com/license
  5543. * Contributing: http://www.plupload.com/contributing
  5544. */
  5545. /*global File:true */
  5546. /**
  5547. Defines constructor for HTML5 runtime.
  5548. @class moxie/runtime/html5/Runtime
  5549. @private
  5550. */
  5551. define("moxie/runtime/html5/Runtime", [
  5552. "moxie/core/utils/Basic",
  5553. "moxie/core/Exceptions",
  5554. "moxie/runtime/Runtime",
  5555. "moxie/core/utils/Env"
  5556. ], function(Basic, x, Runtime, Env) {
  5557. var type = "html5", extensions = {};
  5558. function Html5Runtime(options) {
  5559. var I = this
  5560. , Test = Runtime.capTest
  5561. , True = Runtime.capTrue
  5562. ;
  5563. var caps = Basic.extend({
  5564. access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL),
  5565. access_image_binary: function() {
  5566. return I.can('access_binary') && !!extensions.Image;
  5567. },
  5568. display_media: Test(
  5569. (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) &&
  5570. defined('moxie/image/Image')
  5571. ),
  5572. do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()),
  5573. drag_and_drop: Test(function() {
  5574. // this comes directly from Modernizr: http://www.modernizr.com/
  5575. var div = document.createElement('div');
  5576. // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop
  5577. return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) &&
  5578. (Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>'));
  5579. }()),
  5580. filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
  5581. return !(
  5582. (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) ||
  5583. (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) ||
  5584. (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) ||
  5585. (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<'))
  5586. );
  5587. }()),
  5588. return_response_headers: True,
  5589. return_response_type: function(responseType) {
  5590. if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported
  5591. return true;
  5592. }
  5593. return Env.can('return_response_type', responseType);
  5594. },
  5595. return_status_code: True,
  5596. report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload),
  5597. resize_image: function() {
  5598. return I.can('access_binary') && Env.can('create_canvas');
  5599. },
  5600. select_file: function() {
  5601. return Env.can('use_fileinput') && window.File;
  5602. },
  5603. select_folder: function() {
  5604. return I.can('select_file') && (
  5605. Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=') ||
  5606. Env.browser === 'Firefox' && Env.verComp(Env.version, 42, '>=') // https://developer.mozilla.org/en-US/Firefox/Releases/42
  5607. );
  5608. },
  5609. select_multiple: function() {
  5610. // it is buggy on Safari Windows and iOS
  5611. return I.can('select_file') &&
  5612. !(Env.browser === 'Safari' && Env.os === 'Windows') &&
  5613. !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.0", '>') && Env.verComp(Env.osVersion, "8.0.0", '<'));
  5614. },
  5615. send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))),
  5616. send_custom_headers: Test(window.XMLHttpRequest),
  5617. send_multipart: function() {
  5618. return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string');
  5619. },
  5620. slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)),
  5621. stream_upload: function(){
  5622. return I.can('slice_blob') && I.can('send_multipart');
  5623. },
  5624. summon_file_dialog: function() { // yeah... some dirty sniffing here...
  5625. return I.can('select_file') && !(
  5626. (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) ||
  5627. (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) ||
  5628. (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<'))
  5629. );
  5630. },
  5631. upload_filesize: True,
  5632. use_http_method: True
  5633. },
  5634. arguments[2]
  5635. );
  5636. Runtime.call(this, options, (arguments[1] || type), caps);
  5637. Basic.extend(this, {
  5638. init : function() {
  5639. this.trigger("Init");
  5640. },
  5641. destroy: (function(destroy) { // extend default destroy method
  5642. return function() {
  5643. destroy.call(I);
  5644. destroy = I = null;
  5645. };
  5646. }(this.destroy))
  5647. });
  5648. Basic.extend(this.getShim(), extensions);
  5649. }
  5650. Runtime.addConstructor(type, Html5Runtime);
  5651. return extensions;
  5652. });
  5653. // Included from: src/javascript/runtime/html5/file/Blob.js
  5654. /**
  5655. * Blob.js
  5656. *
  5657. * Copyright 2013, Moxiecode Systems AB
  5658. * Released under GPL License.
  5659. *
  5660. * License: http://www.plupload.com/license
  5661. * Contributing: http://www.plupload.com/contributing
  5662. */
  5663. /**
  5664. @class moxie/runtime/html5/file/Blob
  5665. @private
  5666. */
  5667. define("moxie/runtime/html5/file/Blob", [
  5668. "moxie/runtime/html5/Runtime",
  5669. "moxie/file/Blob"
  5670. ], function(extensions, Blob) {
  5671. function HTML5Blob() {
  5672. function w3cBlobSlice(blob, start, end) {
  5673. var blobSlice;
  5674. if (window.File.prototype.slice) {
  5675. try {
  5676. blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception
  5677. return blob.slice(start, end);
  5678. } catch (e) {
  5679. // depricated slice method
  5680. return blob.slice(start, end - start);
  5681. }
  5682. // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
  5683. } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) {
  5684. return blobSlice.call(blob, start, end);
  5685. } else {
  5686. return null; // or throw some exception
  5687. }
  5688. }
  5689. this.slice = function() {
  5690. return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments));
  5691. };
  5692. this.destroy = function() {
  5693. this.getRuntime().getShim().removeInstance(this.uid);
  5694. };
  5695. }
  5696. return (extensions.Blob = HTML5Blob);
  5697. });
  5698. // Included from: src/javascript/core/utils/Events.js
  5699. /**
  5700. * Events.js
  5701. *
  5702. * Copyright 2013, Moxiecode Systems AB
  5703. * Released under GPL License.
  5704. *
  5705. * License: http://www.plupload.com/license
  5706. * Contributing: http://www.plupload.com/contributing
  5707. */
  5708. /**
  5709. @class moxie/core/utils/Events
  5710. @public
  5711. @static
  5712. */
  5713. define('moxie/core/utils/Events', [
  5714. 'moxie/core/utils/Basic'
  5715. ], function(Basic) {
  5716. var eventhash = {}, uid = 'moxie_' + Basic.guid();
  5717. // IE W3C like event funcs
  5718. function preventDefault() {
  5719. this.returnValue = false;
  5720. }
  5721. function stopPropagation() {
  5722. this.cancelBubble = true;
  5723. }
  5724. /**
  5725. Adds an event handler to the specified object and store reference to the handler
  5726. in objects internal Plupload registry (@see removeEvent).
  5727. @method addEvent
  5728. @static
  5729. @param {Object} obj DOM element like object to add handler to.
  5730. @param {String} name Name to add event listener to.
  5731. @param {Function} callback Function to call when event occurs.
  5732. @param {String} [key] that might be used to add specifity to the event record.
  5733. */
  5734. var addEvent = function(obj, name, callback, key) {
  5735. var func, events;
  5736. name = name.toLowerCase();
  5737. // Add event listener
  5738. if (obj.addEventListener) {
  5739. func = callback;
  5740. obj.addEventListener(name, func, false);
  5741. } else if (obj.attachEvent) {
  5742. func = function() {
  5743. var evt = window.event;
  5744. if (!evt.target) {
  5745. evt.target = evt.srcElement;
  5746. }
  5747. evt.preventDefault = preventDefault;
  5748. evt.stopPropagation = stopPropagation;
  5749. callback(evt);
  5750. };
  5751. obj.attachEvent('on' + name, func);
  5752. }
  5753. // Log event handler to objects internal mOxie registry
  5754. if (!obj[uid]) {
  5755. obj[uid] = Basic.guid();
  5756. }
  5757. if (!eventhash.hasOwnProperty(obj[uid])) {
  5758. eventhash[obj[uid]] = {};
  5759. }
  5760. events = eventhash[obj[uid]];
  5761. if (!events.hasOwnProperty(name)) {
  5762. events[name] = [];
  5763. }
  5764. events[name].push({
  5765. func: func,
  5766. orig: callback, // store original callback for IE
  5767. key: key
  5768. });
  5769. };
  5770. /**
  5771. Remove event handler from the specified object. If third argument (callback)
  5772. is not specified remove all events with the specified name.
  5773. @method removeEvent
  5774. @static
  5775. @param {Object} obj DOM element to remove event listener(s) from.
  5776. @param {String} name Name of event listener to remove.
  5777. @param {Function|String} [callback] might be a callback or unique key to match.
  5778. */
  5779. var removeEvent = function(obj, name, callback) {
  5780. var type, undef;
  5781. name = name.toLowerCase();
  5782. if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) {
  5783. type = eventhash[obj[uid]][name];
  5784. } else {
  5785. return;
  5786. }
  5787. for (var i = type.length - 1; i >= 0; i--) {
  5788. // undefined or not, key should match
  5789. if (type[i].orig === callback || type[i].key === callback) {
  5790. if (obj.removeEventListener) {
  5791. obj.removeEventListener(name, type[i].func, false);
  5792. } else if (obj.detachEvent) {
  5793. obj.detachEvent('on'+name, type[i].func);
  5794. }
  5795. type[i].orig = null;
  5796. type[i].func = null;
  5797. type.splice(i, 1);
  5798. // If callback was passed we are done here, otherwise proceed
  5799. if (callback !== undef) {
  5800. break;
  5801. }
  5802. }
  5803. }
  5804. // If event array got empty, remove it
  5805. if (!type.length) {
  5806. delete eventhash[obj[uid]][name];
  5807. }
  5808. // If mOxie registry has become empty, remove it
  5809. if (Basic.isEmptyObj(eventhash[obj[uid]])) {
  5810. delete eventhash[obj[uid]];
  5811. // IE doesn't let you remove DOM object property with - delete
  5812. try {
  5813. delete obj[uid];
  5814. } catch(e) {
  5815. obj[uid] = undef;
  5816. }
  5817. }
  5818. };
  5819. /**
  5820. Remove all kind of events from the specified object
  5821. @method removeAllEvents
  5822. @static
  5823. @param {Object} obj DOM element to remove event listeners from.
  5824. @param {String} [key] unique key to match, when removing events.
  5825. */
  5826. var removeAllEvents = function(obj, key) {
  5827. if (!obj || !obj[uid]) {
  5828. return;
  5829. }
  5830. Basic.each(eventhash[obj[uid]], function(events, name) {
  5831. removeEvent(obj, name, key);
  5832. });
  5833. };
  5834. return {
  5835. addEvent: addEvent,
  5836. removeEvent: removeEvent,
  5837. removeAllEvents: removeAllEvents
  5838. };
  5839. });
  5840. // Included from: src/javascript/runtime/html5/file/FileInput.js
  5841. /**
  5842. * FileInput.js
  5843. *
  5844. * Copyright 2013, Moxiecode Systems AB
  5845. * Released under GPL License.
  5846. *
  5847. * License: http://www.plupload.com/license
  5848. * Contributing: http://www.plupload.com/contributing
  5849. */
  5850. /**
  5851. @class moxie/runtime/html5/file/FileInput
  5852. @private
  5853. */
  5854. define("moxie/runtime/html5/file/FileInput", [
  5855. "moxie/runtime/html5/Runtime",
  5856. "moxie/file/File",
  5857. "moxie/core/utils/Basic",
  5858. "moxie/core/utils/Dom",
  5859. "moxie/core/utils/Events",
  5860. "moxie/core/utils/Mime",
  5861. "moxie/core/utils/Env"
  5862. ], function(extensions, File, Basic, Dom, Events, Mime, Env) {
  5863. function FileInput() {
  5864. var _options, _browseBtnZIndex; // save original z-index
  5865. Basic.extend(this, {
  5866. init: function(options) {
  5867. var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top;
  5868. _options = options;
  5869. // figure out accept string
  5870. mimes = Mime.extList2mimes(_options.accept, I.can('filter_by_extension'));
  5871. shimContainer = I.getShimContainer();
  5872. shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' +
  5873. (_options.multiple && I.can('select_multiple') ? 'multiple' : '') +
  5874. (_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+
  5875. (mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />';
  5876. input = Dom.get(I.uid);
  5877. // prepare file input to be placed underneath the browse_button element
  5878. Basic.extend(input.style, {
  5879. position: 'absolute',
  5880. top: 0,
  5881. left: 0,
  5882. width: '100%',
  5883. height: '100%'
  5884. });
  5885. browseButton = Dom.get(_options.browse_button);
  5886. _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto';
  5887. // Route click event to the input[type=file] element for browsers that support such behavior
  5888. if (I.can('summon_file_dialog')) {
  5889. if (Dom.getStyle(browseButton, 'position') === 'static') {
  5890. browseButton.style.position = 'relative';
  5891. }
  5892. Events.addEvent(browseButton, 'click', function(e) {
  5893. var input = Dom.get(I.uid);
  5894. if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
  5895. input.click();
  5896. }
  5897. e.preventDefault();
  5898. }, comp.uid);
  5899. comp.bind('Refresh', function() {
  5900. zIndex = parseInt(_browseBtnZIndex, 10) || 1;
  5901. Dom.get(_options.browse_button).style.zIndex = zIndex;
  5902. this.getRuntime().getShimContainer().style.zIndex = zIndex - 1;
  5903. });
  5904. }
  5905. /* Since we have to place input[type=file] on top of the browse_button for some browsers,
  5906. browse_button loses interactivity, so we restore it here */
  5907. top = I.can('summon_file_dialog') ? browseButton : shimContainer;
  5908. Events.addEvent(top, 'mouseover', function() {
  5909. comp.trigger('mouseenter');
  5910. }, comp.uid);
  5911. Events.addEvent(top, 'mouseout', function() {
  5912. comp.trigger('mouseleave');
  5913. }, comp.uid);
  5914. Events.addEvent(top, 'mousedown', function() {
  5915. comp.trigger('mousedown');
  5916. }, comp.uid);
  5917. Events.addEvent(Dom.get(_options.container), 'mouseup', function() {
  5918. comp.trigger('mouseup');
  5919. }, comp.uid);
  5920. // it shouldn't be possible to tab into the hidden element
  5921. (I.can('summon_file_dialog') ? input : browseButton).setAttribute('tabindex', -1);
  5922. input.onchange = function onChange() { // there should be only one handler for this
  5923. comp.files = [];
  5924. Basic.each(this.files, function(file) {
  5925. var relativePath = '';
  5926. if (_options.directory) {
  5927. // folders are represented by dots, filter them out (Chrome 11+)
  5928. if (file.name == ".") {
  5929. // if it looks like a folder...
  5930. return true;
  5931. }
  5932. }
  5933. if (file.webkitRelativePath) {
  5934. relativePath = '/' + file.webkitRelativePath.replace(/^\//, '');
  5935. }
  5936. file = new File(I.uid, file);
  5937. file.relativePath = relativePath;
  5938. comp.files.push(file);
  5939. });
  5940. // clearing the value enables the user to select the same file again if they want to
  5941. if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') {
  5942. this.value = '';
  5943. } else {
  5944. // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it
  5945. var clone = this.cloneNode(true);
  5946. this.parentNode.replaceChild(clone, this);
  5947. clone.onchange = onChange;
  5948. }
  5949. if (comp.files.length) {
  5950. comp.trigger('change');
  5951. }
  5952. };
  5953. // ready event is perfectly asynchronous
  5954. comp.trigger({
  5955. type: 'ready',
  5956. async: true
  5957. });
  5958. shimContainer = null;
  5959. },
  5960. setOption: function(name, value) {
  5961. var I = this.getRuntime();
  5962. var input = Dom.get(I.uid);
  5963. switch (name) {
  5964. case 'accept':
  5965. if (value) {
  5966. var mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension'));
  5967. input.setAttribute('accept', mimes.join(','));
  5968. } else {
  5969. input.removeAttribute('accept');
  5970. }
  5971. break;
  5972. case 'directory':
  5973. if (value && I.can('select_folder')) {
  5974. input.setAttribute('directory', '');
  5975. input.setAttribute('webkitdirectory', '');
  5976. } else {
  5977. input.removeAttribute('directory');
  5978. input.removeAttribute('webkitdirectory');
  5979. }
  5980. break;
  5981. case 'multiple':
  5982. if (value && I.can('select_multiple')) {
  5983. input.setAttribute('multiple', '');
  5984. } else {
  5985. input.removeAttribute('multiple');
  5986. }
  5987. }
  5988. },
  5989. disable: function(state) {
  5990. var I = this.getRuntime(), input;
  5991. if ((input = Dom.get(I.uid))) {
  5992. input.disabled = !!state;
  5993. }
  5994. },
  5995. destroy: function() {
  5996. var I = this.getRuntime()
  5997. , shim = I.getShim()
  5998. , shimContainer = I.getShimContainer()
  5999. , container = _options && Dom.get(_options.container)
  6000. , browseButton = _options && Dom.get(_options.browse_button)
  6001. ;
  6002. if (container) {
  6003. Events.removeAllEvents(container, this.uid);
  6004. }
  6005. if (browseButton) {
  6006. Events.removeAllEvents(browseButton, this.uid);
  6007. browseButton.style.zIndex = _browseBtnZIndex; // reset to original value
  6008. }
  6009. if (shimContainer) {
  6010. Events.removeAllEvents(shimContainer, this.uid);
  6011. shimContainer.innerHTML = '';
  6012. }
  6013. shim.removeInstance(this.uid);
  6014. _options = shimContainer = container = browseButton = shim = null;
  6015. }
  6016. });
  6017. }
  6018. return (extensions.FileInput = FileInput);
  6019. });
  6020. // Included from: src/javascript/runtime/html5/file/FileDrop.js
  6021. /**
  6022. * FileDrop.js
  6023. *
  6024. * Copyright 2013, Moxiecode Systems AB
  6025. * Released under GPL License.
  6026. *
  6027. * License: http://www.plupload.com/license
  6028. * Contributing: http://www.plupload.com/contributing
  6029. */
  6030. /**
  6031. @class moxie/runtime/html5/file/FileDrop
  6032. @private
  6033. */
  6034. define("moxie/runtime/html5/file/FileDrop", [
  6035. "moxie/runtime/html5/Runtime",
  6036. 'moxie/file/File',
  6037. "moxie/core/utils/Basic",
  6038. "moxie/core/utils/Dom",
  6039. "moxie/core/utils/Events",
  6040. "moxie/core/utils/Mime"
  6041. ], function(extensions, File, Basic, Dom, Events, Mime) {
  6042. function FileDrop() {
  6043. var _files = [], _allowedExts = [], _options, _ruid;
  6044. Basic.extend(this, {
  6045. init: function(options) {
  6046. var comp = this, dropZone;
  6047. _options = options;
  6048. _ruid = comp.ruid; // every dropped-in file should have a reference to the runtime
  6049. _allowedExts = _extractExts(_options.accept);
  6050. dropZone = _options.container;
  6051. Events.addEvent(dropZone, 'dragover', function(e) {
  6052. if (!_hasFiles(e)) {
  6053. return;
  6054. }
  6055. e.preventDefault();
  6056. e.dataTransfer.dropEffect = 'copy';
  6057. }, comp.uid);
  6058. Events.addEvent(dropZone, 'drop', function(e) {
  6059. if (!_hasFiles(e)) {
  6060. return;
  6061. }
  6062. e.preventDefault();
  6063. _files = [];
  6064. // Chrome 21+ accepts folders via Drag'n'Drop
  6065. if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) {
  6066. _readItems(e.dataTransfer.items, function() {
  6067. comp.files = _files;
  6068. comp.trigger("drop");
  6069. });
  6070. } else {
  6071. Basic.each(e.dataTransfer.files, function(file) {
  6072. _addFile(file);
  6073. });
  6074. comp.files = _files;
  6075. comp.trigger("drop");
  6076. }
  6077. }, comp.uid);
  6078. Events.addEvent(dropZone, 'dragenter', function(e) {
  6079. comp.trigger("dragenter");
  6080. }, comp.uid);
  6081. Events.addEvent(dropZone, 'dragleave', function(e) {
  6082. comp.trigger("dragleave");
  6083. }, comp.uid);
  6084. },
  6085. destroy: function() {
  6086. Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
  6087. _ruid = _files = _allowedExts = _options = null;
  6088. this.getRuntime().getShim().removeInstance(this.uid);
  6089. }
  6090. });
  6091. function _hasFiles(e) {
  6092. if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover
  6093. return false;
  6094. }
  6095. var types = Basic.toArray(e.dataTransfer.types || []);
  6096. return Basic.inArray("Files", types) !== -1 ||
  6097. Basic.inArray("public.file-url", types) !== -1 || // Safari < 5
  6098. Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6)
  6099. ;
  6100. }
  6101. function _addFile(file, relativePath) {
  6102. if (_isAcceptable(file)) {
  6103. var fileObj = new File(_ruid, file);
  6104. fileObj.relativePath = relativePath || '';
  6105. _files.push(fileObj);
  6106. }
  6107. }
  6108. function _extractExts(accept) {
  6109. var exts = [];
  6110. for (var i = 0; i < accept.length; i++) {
  6111. [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/));
  6112. }
  6113. return Basic.inArray('*', exts) === -1 ? exts : [];
  6114. }
  6115. function _isAcceptable(file) {
  6116. if (!_allowedExts.length) {
  6117. return true;
  6118. }
  6119. var ext = Mime.getFileExtension(file.name);
  6120. return !ext || Basic.inArray(ext, _allowedExts) !== -1;
  6121. }
  6122. function _readItems(items, cb) {
  6123. var entries = [];
  6124. Basic.each(items, function(item) {
  6125. var entry = item.webkitGetAsEntry();
  6126. // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579)
  6127. if (entry) {
  6128. // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61
  6129. if (entry.isFile) {
  6130. _addFile(item.getAsFile(), entry.fullPath);
  6131. } else {
  6132. entries.push(entry);
  6133. }
  6134. }
  6135. });
  6136. if (entries.length) {
  6137. _readEntries(entries, cb);
  6138. } else {
  6139. cb();
  6140. }
  6141. }
  6142. function _readEntries(entries, cb) {
  6143. var queue = [];
  6144. Basic.each(entries, function(entry) {
  6145. queue.push(function(cbcb) {
  6146. _readEntry(entry, cbcb);
  6147. });
  6148. });
  6149. Basic.inSeries(queue, function() {
  6150. cb();
  6151. });
  6152. }
  6153. function _readEntry(entry, cb) {
  6154. if (entry.isFile) {
  6155. entry.file(function(file) {
  6156. _addFile(file, entry.fullPath);
  6157. cb();
  6158. }, function() {
  6159. // fire an error event maybe
  6160. cb();
  6161. });
  6162. } else if (entry.isDirectory) {
  6163. _readDirEntry(entry, cb);
  6164. } else {
  6165. cb(); // not file, not directory? what then?..
  6166. }
  6167. }
  6168. function _readDirEntry(dirEntry, cb) {
  6169. var entries = [], dirReader = dirEntry.createReader();
  6170. // keep quering recursively till no more entries
  6171. function getEntries(cbcb) {
  6172. dirReader.readEntries(function(moreEntries) {
  6173. if (moreEntries.length) {
  6174. [].push.apply(entries, moreEntries);
  6175. getEntries(cbcb);
  6176. } else {
  6177. cbcb();
  6178. }
  6179. }, cbcb);
  6180. }
  6181. // ...and you thought FileReader was crazy...
  6182. getEntries(function() {
  6183. _readEntries(entries, cb);
  6184. });
  6185. }
  6186. }
  6187. return (extensions.FileDrop = FileDrop);
  6188. });
  6189. // Included from: src/javascript/runtime/html5/file/FileReader.js
  6190. /**
  6191. * FileReader.js
  6192. *
  6193. * Copyright 2013, Moxiecode Systems AB
  6194. * Released under GPL License.
  6195. *
  6196. * License: http://www.plupload.com/license
  6197. * Contributing: http://www.plupload.com/contributing
  6198. */
  6199. /**
  6200. @class moxie/runtime/html5/file/FileReader
  6201. @private
  6202. */
  6203. define("moxie/runtime/html5/file/FileReader", [
  6204. "moxie/runtime/html5/Runtime",
  6205. "moxie/core/utils/Encode",
  6206. "moxie/core/utils/Basic"
  6207. ], function(extensions, Encode, Basic) {
  6208. function FileReader() {
  6209. var _fr, _convertToBinary = false;
  6210. Basic.extend(this, {
  6211. read: function(op, blob) {
  6212. var comp = this;
  6213. comp.result = '';
  6214. _fr = new window.FileReader();
  6215. _fr.addEventListener('progress', function(e) {
  6216. comp.trigger(e);
  6217. });
  6218. _fr.addEventListener('load', function(e) {
  6219. comp.result = _convertToBinary ? _toBinary(_fr.result) : _fr.result;
  6220. comp.trigger(e);
  6221. });
  6222. _fr.addEventListener('error', function(e) {
  6223. comp.trigger(e, _fr.error);
  6224. });
  6225. _fr.addEventListener('loadend', function(e) {
  6226. _fr = null;
  6227. comp.trigger(e);
  6228. });
  6229. if (Basic.typeOf(_fr[op]) === 'function') {
  6230. _convertToBinary = false;
  6231. _fr[op](blob.getSource());
  6232. } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+
  6233. _convertToBinary = true;
  6234. _fr.readAsDataURL(blob.getSource());
  6235. }
  6236. },
  6237. abort: function() {
  6238. if (_fr) {
  6239. _fr.abort();
  6240. }
  6241. },
  6242. destroy: function() {
  6243. _fr = null;
  6244. this.getRuntime().getShim().removeInstance(this.uid);
  6245. }
  6246. });
  6247. function _toBinary(str) {
  6248. return Encode.atob(str.substring(str.indexOf('base64,') + 7));
  6249. }
  6250. }
  6251. return (extensions.FileReader = FileReader);
  6252. });
  6253. // Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js
  6254. /**
  6255. * XMLHttpRequest.js
  6256. *
  6257. * Copyright 2013, Moxiecode Systems AB
  6258. * Released under GPL License.
  6259. *
  6260. * License: http://www.plupload.com/license
  6261. * Contributing: http://www.plupload.com/contributing
  6262. */
  6263. /*global ActiveXObject:true */
  6264. /**
  6265. @class moxie/runtime/html5/xhr/XMLHttpRequest
  6266. @private
  6267. */
  6268. define("moxie/runtime/html5/xhr/XMLHttpRequest", [
  6269. "moxie/runtime/html5/Runtime",
  6270. "moxie/core/utils/Basic",
  6271. "moxie/core/utils/Mime",
  6272. "moxie/core/utils/Url",
  6273. "moxie/file/File",
  6274. "moxie/file/Blob",
  6275. "moxie/xhr/FormData",
  6276. "moxie/core/Exceptions",
  6277. "moxie/core/utils/Env"
  6278. ], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {
  6279. function XMLHttpRequest() {
  6280. var self = this
  6281. , _xhr
  6282. , _filename
  6283. ;
  6284. Basic.extend(this, {
  6285. send: function(meta, data) {
  6286. var target = this
  6287. , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<'))
  6288. , isAndroidBrowser = Env.browser === 'Android Browser'
  6289. , mustSendAsBinary = false
  6290. ;
  6291. // extract file name
  6292. _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase();
  6293. _xhr = _getNativeXHR();
  6294. _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);
  6295. // prepare data to be sent
  6296. if (data instanceof Blob) {
  6297. if (data.isDetached()) {
  6298. mustSendAsBinary = true;
  6299. }
  6300. data = data.getSource();
  6301. } else if (data instanceof FormData) {
  6302. if (data.hasBlob()) {
  6303. if (data.getBlob().isDetached()) {
  6304. data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state
  6305. mustSendAsBinary = true;
  6306. } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) {
  6307. // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
  6308. // Android browsers (default one and Dolphin) seem to have the same issue, see: #613
  6309. _preloadAndSend.call(target, meta, data);
  6310. return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D
  6311. }
  6312. }
  6313. // transfer fields to real FormData
  6314. if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart()
  6315. var fd = new window.FormData();
  6316. data.each(function(value, name) {
  6317. if (value instanceof Blob) {
  6318. fd.append(name, value.getSource());
  6319. } else {
  6320. fd.append(name, value);
  6321. }
  6322. });
  6323. data = fd;
  6324. }
  6325. }
  6326. // if XHR L2
  6327. if (_xhr.upload) {
  6328. if (meta.withCredentials) {
  6329. _xhr.withCredentials = true;
  6330. }
  6331. _xhr.addEventListener('load', function(e) {
  6332. target.trigger(e);
  6333. });
  6334. _xhr.addEventListener('error', function(e) {
  6335. target.trigger(e);
  6336. });
  6337. // additionally listen to progress events
  6338. _xhr.addEventListener('progress', function(e) {
  6339. target.trigger(e);
  6340. });
  6341. _xhr.upload.addEventListener('progress', function(e) {
  6342. target.trigger({
  6343. type: 'UploadProgress',
  6344. loaded: e.loaded,
  6345. total: e.total
  6346. });
  6347. });
  6348. // ... otherwise simulate XHR L2
  6349. } else {
  6350. _xhr.onreadystatechange = function onReadyStateChange() {
  6351. // fake Level 2 events
  6352. switch (_xhr.readyState) {
  6353. case 1: // XMLHttpRequest.OPENED
  6354. // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu
  6355. break;
  6356. // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu
  6357. case 2: // XMLHttpRequest.HEADERS_RECEIVED
  6358. break;
  6359. case 3: // XMLHttpRequest.LOADING
  6360. // try to fire progress event for not XHR L2
  6361. var total, loaded;
  6362. try {
  6363. if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers
  6364. total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here
  6365. }
  6366. if (_xhr.responseText) { // responseText was introduced in IE7
  6367. loaded = _xhr.responseText.length;
  6368. }
  6369. } catch(ex) {
  6370. total = loaded = 0;
  6371. }
  6372. target.trigger({
  6373. type: 'progress',
  6374. lengthComputable: !!total,
  6375. total: parseInt(total, 10),
  6376. loaded: loaded
  6377. });
  6378. break;
  6379. case 4: // XMLHttpRequest.DONE
  6380. // release readystatechange handler (mostly for IE)
  6381. _xhr.onreadystatechange = function() {};
  6382. // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout
  6383. try {
  6384. if (_xhr.status >= 200 && _xhr.status < 400) {
  6385. target.trigger('load');
  6386. break;
  6387. }
  6388. } catch(ex) {}
  6389. target.trigger('error');
  6390. break;
  6391. }
  6392. };
  6393. }
  6394. // set request headers
  6395. if (!Basic.isEmptyObj(meta.headers)) {
  6396. Basic.each(meta.headers, function(value, header) {
  6397. _xhr.setRequestHeader(header, value);
  6398. });
  6399. }
  6400. // request response type
  6401. if ("" !== meta.responseType && 'responseType' in _xhr) {
  6402. if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one
  6403. _xhr.responseType = 'text';
  6404. } else {
  6405. _xhr.responseType = meta.responseType;
  6406. }
  6407. }
  6408. // send ...
  6409. if (!mustSendAsBinary) {
  6410. _xhr.send(data);
  6411. } else {
  6412. if (_xhr.sendAsBinary) { // Gecko
  6413. _xhr.sendAsBinary(data);
  6414. } else { // other browsers having support for typed arrays
  6415. (function() {
  6416. // mimic Gecko's sendAsBinary
  6417. var ui8a = new Uint8Array(data.length);
  6418. for (var i = 0; i < data.length; i++) {
  6419. ui8a[i] = (data.charCodeAt(i) & 0xff);
  6420. }
  6421. _xhr.send(ui8a.buffer);
  6422. }());
  6423. }
  6424. }
  6425. target.trigger('loadstart');
  6426. },
  6427. getStatus: function() {
  6428. // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception
  6429. try {
  6430. if (_xhr) {
  6431. return _xhr.status;
  6432. }
  6433. } catch(ex) {}
  6434. return 0;
  6435. },
  6436. getResponse: function(responseType) {
  6437. var I = this.getRuntime();
  6438. try {
  6439. switch (responseType) {
  6440. case 'blob':
  6441. var file = new File(I.uid, _xhr.response);
  6442. // try to extract file name from content-disposition if possible (might be - not, if CORS for example)
  6443. var disposition = _xhr.getResponseHeader('Content-Disposition');
  6444. if (disposition) {
  6445. // extract filename from response header if available
  6446. var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);
  6447. if (match) {
  6448. _filename = match[2];
  6449. }
  6450. }
  6451. file.name = _filename;
  6452. // pre-webkit Opera doesn't set type property on the blob response
  6453. if (!file.type) {
  6454. file.type = Mime.getFileMime(_filename);
  6455. }
  6456. return file;
  6457. case 'json':
  6458. if (!Env.can('return_response_type', 'json')) {
  6459. return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
  6460. }
  6461. return _xhr.response;
  6462. case 'document':
  6463. return _getDocument(_xhr);
  6464. default:
  6465. return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
  6466. }
  6467. } catch(ex) {
  6468. return null;
  6469. }
  6470. },
  6471. getAllResponseHeaders: function() {
  6472. try {
  6473. return _xhr.getAllResponseHeaders();
  6474. } catch(ex) {}
  6475. return '';
  6476. },
  6477. abort: function() {
  6478. if (_xhr) {
  6479. _xhr.abort();
  6480. }
  6481. },
  6482. destroy: function() {
  6483. self = _filename = null;
  6484. this.getRuntime().getShim().removeInstance(this.uid);
  6485. }
  6486. });
  6487. // here we go... ugly fix for ugly bug
  6488. function _preloadAndSend(meta, data) {
  6489. var target = this, blob, fr;
  6490. // get original blob
  6491. blob = data.getBlob().getSource();
  6492. // preload blob in memory to be sent as binary string
  6493. fr = new window.FileReader();
  6494. fr.onload = function() {
  6495. // overwrite original blob
  6496. data.append(data.getBlobName(), new Blob(null, {
  6497. type: blob.type,
  6498. data: fr.result
  6499. }));
  6500. // invoke send operation again
  6501. self.send.call(target, meta, data);
  6502. };
  6503. fr.readAsBinaryString(blob);
  6504. }
  6505. function _getNativeXHR() {
  6506. if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy
  6507. return new window.XMLHttpRequest();
  6508. } else {
  6509. return (function() {
  6510. var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0
  6511. for (var i = 0; i < progIDs.length; i++) {
  6512. try {
  6513. return new ActiveXObject(progIDs[i]);
  6514. } catch (ex) {}
  6515. }
  6516. })();
  6517. }
  6518. }
  6519. // @credits Sergey Ilinsky (http://www.ilinsky.com/)
  6520. function _getDocument(xhr) {
  6521. var rXML = xhr.responseXML;
  6522. var rText = xhr.responseText;
  6523. // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)
  6524. if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {
  6525. rXML = new window.ActiveXObject("Microsoft.XMLDOM");
  6526. rXML.async = false;
  6527. rXML.validateOnParse = false;
  6528. rXML.loadXML(rText);
  6529. }
  6530. // Check if there is no error in document
  6531. if (rXML) {
  6532. if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
  6533. return null;
  6534. }
  6535. }
  6536. return rXML;
  6537. }
  6538. function _prepareMultipart(fd) {
  6539. var boundary = '----moxieboundary' + new Date().getTime()
  6540. , dashdash = '--'
  6541. , crlf = '\r\n'
  6542. , multipart = ''
  6543. , I = this.getRuntime()
  6544. ;
  6545. if (!I.can('send_binary_string')) {
  6546. throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
  6547. }
  6548. _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
  6549. // append multipart parameters
  6550. fd.each(function(value, name) {
  6551. // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(),
  6552. // so we try it here ourselves with: unescape(encodeURIComponent(value))
  6553. if (value instanceof Blob) {
  6554. // Build RFC2388 blob
  6555. multipart += dashdash + boundary + crlf +
  6556. 'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
  6557. 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
  6558. value.getSource() + crlf;
  6559. } else {
  6560. multipart += dashdash + boundary + crlf +
  6561. 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
  6562. unescape(encodeURIComponent(value)) + crlf;
  6563. }
  6564. });
  6565. multipart += dashdash + boundary + dashdash + crlf;
  6566. return multipart;
  6567. }
  6568. }
  6569. return (extensions.XMLHttpRequest = XMLHttpRequest);
  6570. });
  6571. // Included from: src/javascript/runtime/html5/utils/BinaryReader.js
  6572. /**
  6573. * BinaryReader.js
  6574. *
  6575. * Copyright 2013, Moxiecode Systems AB
  6576. * Released under GPL License.
  6577. *
  6578. * License: http://www.plupload.com/license
  6579. * Contributing: http://www.plupload.com/contributing
  6580. */
  6581. /**
  6582. @class moxie/runtime/html5/utils/BinaryReader
  6583. @private
  6584. */
  6585. define("moxie/runtime/html5/utils/BinaryReader", [
  6586. "moxie/core/utils/Basic"
  6587. ], function(Basic) {
  6588. function BinaryReader(data) {
  6589. if (data instanceof ArrayBuffer) {
  6590. ArrayBufferReader.apply(this, arguments);
  6591. } else {
  6592. UTF16StringReader.apply(this, arguments);
  6593. }
  6594. }
  6595. Basic.extend(BinaryReader.prototype, {
  6596. littleEndian: false,
  6597. read: function(idx, size) {
  6598. var sum, mv, i;
  6599. if (idx + size > this.length()) {
  6600. throw new Error("You are trying to read outside the source boundaries.");
  6601. }
  6602. mv = this.littleEndian
  6603. ? 0
  6604. : -8 * (size - 1)
  6605. ;
  6606. for (i = 0, sum = 0; i < size; i++) {
  6607. sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8));
  6608. }
  6609. return sum;
  6610. },
  6611. write: function(idx, num, size) {
  6612. var mv, i, str = '';
  6613. if (idx > this.length()) {
  6614. throw new Error("You are trying to write outside the source boundaries.");
  6615. }
  6616. mv = this.littleEndian
  6617. ? 0
  6618. : -8 * (size - 1)
  6619. ;
  6620. for (i = 0; i < size; i++) {
  6621. this.writeByteAt(idx + i, (num >> Math.abs(mv + i*8)) & 255);
  6622. }
  6623. },
  6624. BYTE: function(idx) {
  6625. return this.read(idx, 1);
  6626. },
  6627. SHORT: function(idx) {
  6628. return this.read(idx, 2);
  6629. },
  6630. LONG: function(idx) {
  6631. return this.read(idx, 4);
  6632. },
  6633. SLONG: function(idx) { // 2's complement notation
  6634. var num = this.read(idx, 4);
  6635. return (num > 2147483647 ? num - 4294967296 : num);
  6636. },
  6637. CHAR: function(idx) {
  6638. return String.fromCharCode(this.read(idx, 1));
  6639. },
  6640. STRING: function(idx, count) {
  6641. return this.asArray('CHAR', idx, count).join('');
  6642. },
  6643. asArray: function(type, idx, count) {
  6644. var values = [];
  6645. for (var i = 0; i < count; i++) {
  6646. values[i] = this[type](idx + i);
  6647. }
  6648. return values;
  6649. }
  6650. });
  6651. function ArrayBufferReader(data) {
  6652. var _dv = new DataView(data);
  6653. Basic.extend(this, {
  6654. readByteAt: function(idx) {
  6655. return _dv.getUint8(idx);
  6656. },
  6657. writeByteAt: function(idx, value) {
  6658. _dv.setUint8(idx, value);
  6659. },
  6660. SEGMENT: function(idx, size, value) {
  6661. switch (arguments.length) {
  6662. case 2:
  6663. return data.slice(idx, idx + size);
  6664. case 1:
  6665. return data.slice(idx);
  6666. case 3:
  6667. if (value === null) {
  6668. value = new ArrayBuffer();
  6669. }
  6670. if (value instanceof ArrayBuffer) {
  6671. var arr = new Uint8Array(this.length() - size + value.byteLength);
  6672. if (idx > 0) {
  6673. arr.set(new Uint8Array(data.slice(0, idx)), 0);
  6674. }
  6675. arr.set(new Uint8Array(value), idx);
  6676. arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength);
  6677. this.clear();
  6678. data = arr.buffer;
  6679. _dv = new DataView(data);
  6680. break;
  6681. }
  6682. default: return data;
  6683. }
  6684. },
  6685. length: function() {
  6686. return data ? data.byteLength : 0;
  6687. },
  6688. clear: function() {
  6689. _dv = data = null;
  6690. }
  6691. });
  6692. }
  6693. function UTF16StringReader(data) {
  6694. Basic.extend(this, {
  6695. readByteAt: function(idx) {
  6696. return data.charCodeAt(idx);
  6697. },
  6698. writeByteAt: function(idx, value) {
  6699. putstr(String.fromCharCode(value), idx, 1);
  6700. },
  6701. SEGMENT: function(idx, length, segment) {
  6702. switch (arguments.length) {
  6703. case 1:
  6704. return data.substr(idx);
  6705. case 2:
  6706. return data.substr(idx, length);
  6707. case 3:
  6708. putstr(segment !== null ? segment : '', idx, length);
  6709. break;
  6710. default: return data;
  6711. }
  6712. },
  6713. length: function() {
  6714. return data ? data.length : 0;
  6715. },
  6716. clear: function() {
  6717. data = null;
  6718. }
  6719. });
  6720. function putstr(segment, idx, length) {
  6721. length = arguments.length === 3 ? length : data.length - idx - 1;
  6722. data = data.substr(0, idx) + segment + data.substr(length + idx);
  6723. }
  6724. }
  6725. return BinaryReader;
  6726. });
  6727. // Included from: src/javascript/runtime/html5/image/JPEGHeaders.js
  6728. /**
  6729. * JPEGHeaders.js
  6730. *
  6731. * Copyright 2013, Moxiecode Systems AB
  6732. * Released under GPL License.
  6733. *
  6734. * License: http://www.plupload.com/license
  6735. * Contributing: http://www.plupload.com/contributing
  6736. */
  6737. /**
  6738. @class moxie/runtime/html5/image/JPEGHeaders
  6739. @private
  6740. */
  6741. define("moxie/runtime/html5/image/JPEGHeaders", [
  6742. "moxie/runtime/html5/utils/BinaryReader",
  6743. "moxie/core/Exceptions"
  6744. ], function(BinaryReader, x) {
  6745. return function JPEGHeaders(data) {
  6746. var headers = [], _br, idx, marker, length = 0;
  6747. _br = new BinaryReader(data);
  6748. // Check if data is jpeg
  6749. if (_br.SHORT(0) !== 0xFFD8) {
  6750. _br.clear();
  6751. throw new x.ImageError(x.ImageError.WRONG_FORMAT);
  6752. }
  6753. idx = 2;
  6754. while (idx <= _br.length()) {
  6755. marker = _br.SHORT(idx);
  6756. // omit RST (restart) markers
  6757. if (marker >= 0xFFD0 && marker <= 0xFFD7) {
  6758. idx += 2;
  6759. continue;
  6760. }
  6761. // no headers allowed after SOS marker
  6762. if (marker === 0xFFDA || marker === 0xFFD9) {
  6763. break;
  6764. }
  6765. length = _br.SHORT(idx + 2) + 2;
  6766. // APPn marker detected
  6767. if (marker >= 0xFFE1 && marker <= 0xFFEF) {
  6768. headers.push({
  6769. hex: marker,
  6770. name: 'APP' + (marker & 0x000F),
  6771. start: idx,
  6772. length: length,
  6773. segment: _br.SEGMENT(idx, length)
  6774. });
  6775. }
  6776. idx += length;
  6777. }
  6778. _br.clear();
  6779. return {
  6780. headers: headers,
  6781. restore: function(data) {
  6782. var max, i, br;
  6783. br = new BinaryReader(data);
  6784. idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2;
  6785. for (i = 0, max = headers.length; i < max; i++) {
  6786. br.SEGMENT(idx, 0, headers[i].segment);
  6787. idx += headers[i].length;
  6788. }
  6789. data = br.SEGMENT();
  6790. br.clear();
  6791. return data;
  6792. },
  6793. strip: function(data) {
  6794. var br, headers, jpegHeaders, i;
  6795. jpegHeaders = new JPEGHeaders(data);
  6796. headers = jpegHeaders.headers;
  6797. jpegHeaders.purge();
  6798. br = new BinaryReader(data);
  6799. i = headers.length;
  6800. while (i--) {
  6801. br.SEGMENT(headers[i].start, headers[i].length, '');
  6802. }
  6803. data = br.SEGMENT();
  6804. br.clear();
  6805. return data;
  6806. },
  6807. get: function(name) {
  6808. var array = [];
  6809. for (var i = 0, max = headers.length; i < max; i++) {
  6810. if (headers[i].name === name.toUpperCase()) {
  6811. array.push(headers[i].segment);
  6812. }
  6813. }
  6814. return array;
  6815. },
  6816. set: function(name, segment) {
  6817. var array = [], i, ii, max;
  6818. if (typeof(segment) === 'string') {
  6819. array.push(segment);
  6820. } else {
  6821. array = segment;
  6822. }
  6823. for (i = ii = 0, max = headers.length; i < max; i++) {
  6824. if (headers[i].name === name.toUpperCase()) {
  6825. headers[i].segment = array[ii];
  6826. headers[i].length = array[ii].length;
  6827. ii++;
  6828. }
  6829. if (ii >= array.length) {
  6830. break;
  6831. }
  6832. }
  6833. },
  6834. purge: function() {
  6835. this.headers = headers = [];
  6836. }
  6837. };
  6838. };
  6839. });
  6840. // Included from: src/javascript/runtime/html5/image/ExifParser.js
  6841. /**
  6842. * ExifParser.js
  6843. *
  6844. * Copyright 2013, Moxiecode Systems AB
  6845. * Released under GPL License.
  6846. *
  6847. * License: http://www.plupload.com/license
  6848. * Contributing: http://www.plupload.com/contributing
  6849. */
  6850. /**
  6851. @class moxie/runtime/html5/image/ExifParser
  6852. @private
  6853. */
  6854. define("moxie/runtime/html5/image/ExifParser", [
  6855. "moxie/core/utils/Basic",
  6856. "moxie/runtime/html5/utils/BinaryReader",
  6857. "moxie/core/Exceptions"
  6858. ], function(Basic, BinaryReader, x) {
  6859. function ExifParser(data) {
  6860. var __super__, tags, tagDescs, offsets, idx, Tiff;
  6861. BinaryReader.call(this, data);
  6862. tags = {
  6863. tiff: {
  6864. /*
  6865. The image orientation viewed in terms of rows and columns.
  6866. 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
  6867. 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
  6868. 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
  6869. 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
  6870. 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
  6871. 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
  6872. 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
  6873. 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
  6874. */
  6875. 0x0112: 'Orientation',
  6876. 0x010E: 'ImageDescription',
  6877. 0x010F: 'Make',
  6878. 0x0110: 'Model',
  6879. 0x0131: 'Software',
  6880. 0x8769: 'ExifIFDPointer',
  6881. 0x8825: 'GPSInfoIFDPointer'
  6882. },
  6883. exif: {
  6884. 0x9000: 'ExifVersion',
  6885. 0xA001: 'ColorSpace',
  6886. 0xA002: 'PixelXDimension',
  6887. 0xA003: 'PixelYDimension',
  6888. 0x9003: 'DateTimeOriginal',
  6889. 0x829A: 'ExposureTime',
  6890. 0x829D: 'FNumber',
  6891. 0x8827: 'ISOSpeedRatings',
  6892. 0x9201: 'ShutterSpeedValue',
  6893. 0x9202: 'ApertureValue' ,
  6894. 0x9207: 'MeteringMode',
  6895. 0x9208: 'LightSource',
  6896. 0x9209: 'Flash',
  6897. 0x920A: 'FocalLength',
  6898. 0xA402: 'ExposureMode',
  6899. 0xA403: 'WhiteBalance',
  6900. 0xA406: 'SceneCaptureType',
  6901. 0xA404: 'DigitalZoomRatio',
  6902. 0xA408: 'Contrast',
  6903. 0xA409: 'Saturation',
  6904. 0xA40A: 'Sharpness'
  6905. },
  6906. gps: {
  6907. 0x0000: 'GPSVersionID',
  6908. 0x0001: 'GPSLatitudeRef',
  6909. 0x0002: 'GPSLatitude',
  6910. 0x0003: 'GPSLongitudeRef',
  6911. 0x0004: 'GPSLongitude'
  6912. },
  6913. thumb: {
  6914. 0x0201: 'JPEGInterchangeFormat',
  6915. 0x0202: 'JPEGInterchangeFormatLength'
  6916. }
  6917. };
  6918. tagDescs = {
  6919. 'ColorSpace': {
  6920. 1: 'sRGB',
  6921. 0: 'Uncalibrated'
  6922. },
  6923. 'MeteringMode': {
  6924. 0: 'Unknown',
  6925. 1: 'Average',
  6926. 2: 'CenterWeightedAverage',
  6927. 3: 'Spot',
  6928. 4: 'MultiSpot',
  6929. 5: 'Pattern',
  6930. 6: 'Partial',
  6931. 255: 'Other'
  6932. },
  6933. 'LightSource': {
  6934. 1: 'Daylight',
  6935. 2: 'Fliorescent',
  6936. 3: 'Tungsten',
  6937. 4: 'Flash',
  6938. 9: 'Fine weather',
  6939. 10: 'Cloudy weather',
  6940. 11: 'Shade',
  6941. 12: 'Daylight fluorescent (D 5700 - 7100K)',
  6942. 13: 'Day white fluorescent (N 4600 -5400K)',
  6943. 14: 'Cool white fluorescent (W 3900 - 4500K)',
  6944. 15: 'White fluorescent (WW 3200 - 3700K)',
  6945. 17: 'Standard light A',
  6946. 18: 'Standard light B',
  6947. 19: 'Standard light C',
  6948. 20: 'D55',
  6949. 21: 'D65',
  6950. 22: 'D75',
  6951. 23: 'D50',
  6952. 24: 'ISO studio tungsten',
  6953. 255: 'Other'
  6954. },
  6955. 'Flash': {
  6956. 0x0000: 'Flash did not fire',
  6957. 0x0001: 'Flash fired',
  6958. 0x0005: 'Strobe return light not detected',
  6959. 0x0007: 'Strobe return light detected',
  6960. 0x0009: 'Flash fired, compulsory flash mode',
  6961. 0x000D: 'Flash fired, compulsory flash mode, return light not detected',
  6962. 0x000F: 'Flash fired, compulsory flash mode, return light detected',
  6963. 0x0010: 'Flash did not fire, compulsory flash mode',
  6964. 0x0018: 'Flash did not fire, auto mode',
  6965. 0x0019: 'Flash fired, auto mode',
  6966. 0x001D: 'Flash fired, auto mode, return light not detected',
  6967. 0x001F: 'Flash fired, auto mode, return light detected',
  6968. 0x0020: 'No flash function',
  6969. 0x0041: 'Flash fired, red-eye reduction mode',
  6970. 0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
  6971. 0x0047: 'Flash fired, red-eye reduction mode, return light detected',
  6972. 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
  6973. 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
  6974. 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
  6975. 0x0059: 'Flash fired, auto mode, red-eye reduction mode',
  6976. 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
  6977. 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
  6978. },
  6979. 'ExposureMode': {
  6980. 0: 'Auto exposure',
  6981. 1: 'Manual exposure',
  6982. 2: 'Auto bracket'
  6983. },
  6984. 'WhiteBalance': {
  6985. 0: 'Auto white balance',
  6986. 1: 'Manual white balance'
  6987. },
  6988. 'SceneCaptureType': {
  6989. 0: 'Standard',
  6990. 1: 'Landscape',
  6991. 2: 'Portrait',
  6992. 3: 'Night scene'
  6993. },
  6994. 'Contrast': {
  6995. 0: 'Normal',
  6996. 1: 'Soft',
  6997. 2: 'Hard'
  6998. },
  6999. 'Saturation': {
  7000. 0: 'Normal',
  7001. 1: 'Low saturation',
  7002. 2: 'High saturation'
  7003. },
  7004. 'Sharpness': {
  7005. 0: 'Normal',
  7006. 1: 'Soft',
  7007. 2: 'Hard'
  7008. },
  7009. // GPS related
  7010. 'GPSLatitudeRef': {
  7011. N: 'North latitude',
  7012. S: 'South latitude'
  7013. },
  7014. 'GPSLongitudeRef': {
  7015. E: 'East longitude',
  7016. W: 'West longitude'
  7017. }
  7018. };
  7019. offsets = {
  7020. tiffHeader: 10
  7021. };
  7022. idx = offsets.tiffHeader;
  7023. __super__ = {
  7024. clear: this.clear
  7025. };
  7026. // Public functions
  7027. Basic.extend(this, {
  7028. read: function() {
  7029. try {
  7030. return ExifParser.prototype.read.apply(this, arguments);
  7031. } catch (ex) {
  7032. throw new x.ImageError(x.ImageError.INVALID_META_ERR);
  7033. }
  7034. },
  7035. write: function() {
  7036. try {
  7037. return ExifParser.prototype.write.apply(this, arguments);
  7038. } catch (ex) {
  7039. throw new x.ImageError(x.ImageError.INVALID_META_ERR);
  7040. }
  7041. },
  7042. UNDEFINED: function() {
  7043. return this.BYTE.apply(this, arguments);
  7044. },
  7045. RATIONAL: function(idx) {
  7046. return this.LONG(idx) / this.LONG(idx + 4)
  7047. },
  7048. SRATIONAL: function(idx) {
  7049. return this.SLONG(idx) / this.SLONG(idx + 4)
  7050. },
  7051. ASCII: function(idx) {
  7052. return this.CHAR(idx);
  7053. },
  7054. TIFF: function() {
  7055. return Tiff || null;
  7056. },
  7057. EXIF: function() {
  7058. var Exif = null;
  7059. if (offsets.exifIFD) {
  7060. try {
  7061. Exif = extractTags.call(this, offsets.exifIFD, tags.exif);
  7062. } catch(ex) {
  7063. return null;
  7064. }
  7065. // Fix formatting of some tags
  7066. if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') {
  7067. for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) {
  7068. exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
  7069. }
  7070. Exif.ExifVersion = exifVersion;
  7071. }
  7072. }
  7073. return Exif;
  7074. },
  7075. GPS: function() {
  7076. var GPS = null;
  7077. if (offsets.gpsIFD) {
  7078. try {
  7079. GPS = extractTags.call(this, offsets.gpsIFD, tags.gps);
  7080. } catch (ex) {
  7081. return null;
  7082. }
  7083. // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
  7084. if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') {
  7085. GPS.GPSVersionID = GPS.GPSVersionID.join('.');
  7086. }
  7087. }
  7088. return GPS;
  7089. },
  7090. thumb: function() {
  7091. if (offsets.IFD1) {
  7092. try {
  7093. var IFD1Tags = extractTags.call(this, offsets.IFD1, tags.thumb);
  7094. if ('JPEGInterchangeFormat' in IFD1Tags) {
  7095. return this.SEGMENT(offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength);
  7096. }
  7097. } catch (ex) {}
  7098. }
  7099. return null;
  7100. },
  7101. setExif: function(tag, value) {
  7102. // Right now only setting of width/height is possible
  7103. if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; }
  7104. return setTag.call(this, 'exif', tag, value);
  7105. },
  7106. clear: function() {
  7107. __super__.clear();
  7108. data = tags = tagDescs = Tiff = offsets = __super__ = null;
  7109. }
  7110. });
  7111. // Check if that's APP1 and that it has EXIF
  7112. if (this.SHORT(0) !== 0xFFE1 || this.STRING(4, 5).toUpperCase() !== "EXIF\0") {
  7113. throw new x.ImageError(x.ImageError.INVALID_META_ERR);
  7114. }
  7115. // Set read order of multi-byte data
  7116. this.littleEndian = (this.SHORT(idx) == 0x4949);
  7117. // Check if always present bytes are indeed present
  7118. if (this.SHORT(idx+=2) !== 0x002A) {
  7119. throw new x.ImageError(x.ImageError.INVALID_META_ERR);
  7120. }
  7121. offsets.IFD0 = offsets.tiffHeader + this.LONG(idx += 2);
  7122. Tiff = extractTags.call(this, offsets.IFD0, tags.tiff);
  7123. if ('ExifIFDPointer' in Tiff) {
  7124. offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
  7125. delete Tiff.ExifIFDPointer;
  7126. }
  7127. if ('GPSInfoIFDPointer' in Tiff) {
  7128. offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer;
  7129. delete Tiff.GPSInfoIFDPointer;
  7130. }
  7131. if (Basic.isEmptyObj(Tiff)) {
  7132. Tiff = null;
  7133. }
  7134. // check if we have a thumb as well
  7135. var IFD1Offset = this.LONG(offsets.IFD0 + this.SHORT(offsets.IFD0) * 12 + 2);
  7136. if (IFD1Offset) {
  7137. offsets.IFD1 = offsets.tiffHeader + IFD1Offset;
  7138. }
  7139. function extractTags(IFD_offset, tags2extract) {
  7140. var data = this;
  7141. var length, i, tag, type, count, size, offset, value, values = [], hash = {};
  7142. var types = {
  7143. 1 : 'BYTE',
  7144. 7 : 'UNDEFINED',
  7145. 2 : 'ASCII',
  7146. 3 : 'SHORT',
  7147. 4 : 'LONG',
  7148. 5 : 'RATIONAL',
  7149. 9 : 'SLONG',
  7150. 10: 'SRATIONAL'
  7151. };
  7152. var sizes = {
  7153. 'BYTE' : 1,
  7154. 'UNDEFINED' : 1,
  7155. 'ASCII' : 1,
  7156. 'SHORT' : 2,
  7157. 'LONG' : 4,
  7158. 'RATIONAL' : 8,
  7159. 'SLONG' : 4,
  7160. 'SRATIONAL' : 8
  7161. };
  7162. length = data.SHORT(IFD_offset);
  7163. // The size of APP1 including all these elements shall not exceed the 64 Kbytes specified in the JPEG standard.
  7164. for (i = 0; i < length; i++) {
  7165. values = [];
  7166. // Set binary reader pointer to beginning of the next tag
  7167. offset = IFD_offset + 2 + i*12;
  7168. tag = tags2extract[data.SHORT(offset)];
  7169. if (tag === undefined) {
  7170. continue; // Not the tag we requested
  7171. }
  7172. type = types[data.SHORT(offset+=2)];
  7173. count = data.LONG(offset+=2);
  7174. size = sizes[type];
  7175. if (!size) {
  7176. throw new x.ImageError(x.ImageError.INVALID_META_ERR);
  7177. }
  7178. offset += 4;
  7179. // tag can only fit 4 bytes of data, if data is larger we should look outside
  7180. if (size * count > 4) {
  7181. // instead of data tag contains an offset of the data
  7182. offset = data.LONG(offset) + offsets.tiffHeader;
  7183. }
  7184. // in case we left the boundaries of data throw an early exception
  7185. if (offset + size * count >= this.length()) {
  7186. throw new x.ImageError(x.ImageError.INVALID_META_ERR);
  7187. }
  7188. // special care for the string
  7189. if (type === 'ASCII') {
  7190. hash[tag] = Basic.trim(data.STRING(offset, count).replace(/\0$/, '')); // strip trailing NULL
  7191. continue;
  7192. } else {
  7193. values = data.asArray(type, offset, count);
  7194. value = (count == 1 ? values[0] : values);
  7195. if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
  7196. hash[tag] = tagDescs[tag][value];
  7197. } else {
  7198. hash[tag] = value;
  7199. }
  7200. }
  7201. }
  7202. return hash;
  7203. }
  7204. // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
  7205. function setTag(ifd, tag, value) {
  7206. var offset, length, tagOffset, valueOffset = 0;
  7207. // If tag name passed translate into hex key
  7208. if (typeof(tag) === 'string') {
  7209. var tmpTags = tags[ifd.toLowerCase()];
  7210. for (var hex in tmpTags) {
  7211. if (tmpTags[hex] === tag) {
  7212. tag = hex;
  7213. break;
  7214. }
  7215. }
  7216. }
  7217. offset = offsets[ifd.toLowerCase() + 'IFD'];
  7218. length = this.SHORT(offset);
  7219. for (var i = 0; i < length; i++) {
  7220. tagOffset = offset + 12 * i + 2;
  7221. if (this.SHORT(tagOffset) == tag) {
  7222. valueOffset = tagOffset + 8;
  7223. break;
  7224. }
  7225. }
  7226. if (!valueOffset) {
  7227. return false;
  7228. }
  7229. try {
  7230. this.write(valueOffset, value, 4);
  7231. } catch(ex) {
  7232. return false;
  7233. }
  7234. return true;
  7235. }
  7236. }
  7237. ExifParser.prototype = BinaryReader.prototype;
  7238. return ExifParser;
  7239. });
  7240. // Included from: src/javascript/runtime/html5/image/JPEG.js
  7241. /**
  7242. * JPEG.js
  7243. *
  7244. * Copyright 2013, Moxiecode Systems AB
  7245. * Released under GPL License.
  7246. *
  7247. * License: http://www.plupload.com/license
  7248. * Contributing: http://www.plupload.com/contributing
  7249. */
  7250. /**
  7251. @class moxie/runtime/html5/image/JPEG
  7252. @private
  7253. */
  7254. define("moxie/runtime/html5/image/JPEG", [
  7255. "moxie/core/utils/Basic",
  7256. "moxie/core/Exceptions",
  7257. "moxie/runtime/html5/image/JPEGHeaders",
  7258. "moxie/runtime/html5/utils/BinaryReader",
  7259. "moxie/runtime/html5/image/ExifParser"
  7260. ], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) {
  7261. function JPEG(data) {
  7262. var _br, _hm, _ep, _info;
  7263. _br = new BinaryReader(data);
  7264. // check if it is jpeg
  7265. if (_br.SHORT(0) !== 0xFFD8) {
  7266. throw new x.ImageError(x.ImageError.WRONG_FORMAT);
  7267. }
  7268. // backup headers
  7269. _hm = new JPEGHeaders(data);
  7270. // extract exif info
  7271. try {
  7272. _ep = new ExifParser(_hm.get('app1')[0]);
  7273. } catch(ex) {}
  7274. // get dimensions
  7275. _info = _getDimensions.call(this);
  7276. Basic.extend(this, {
  7277. type: 'image/jpeg',
  7278. size: _br.length(),
  7279. width: _info && _info.width || 0,
  7280. height: _info && _info.height || 0,
  7281. setExif: function(tag, value) {
  7282. if (!_ep) {
  7283. return false; // or throw an exception
  7284. }
  7285. if (Basic.typeOf(tag) === 'object') {
  7286. Basic.each(tag, function(value, tag) {
  7287. _ep.setExif(tag, value);
  7288. });
  7289. } else {
  7290. _ep.setExif(tag, value);
  7291. }
  7292. // update internal headers
  7293. _hm.set('app1', _ep.SEGMENT());
  7294. },
  7295. writeHeaders: function() {
  7296. if (!arguments.length) {
  7297. // if no arguments passed, update headers internally
  7298. return _hm.restore(data);
  7299. }
  7300. return _hm.restore(arguments[0]);
  7301. },
  7302. stripHeaders: function(data) {
  7303. return _hm.strip(data);
  7304. },
  7305. purge: function() {
  7306. _purge.call(this);
  7307. }
  7308. });
  7309. if (_ep) {
  7310. this.meta = {
  7311. tiff: _ep.TIFF(),
  7312. exif: _ep.EXIF(),
  7313. gps: _ep.GPS(),
  7314. thumb: _getThumb()
  7315. };
  7316. }
  7317. function _getDimensions(br) {
  7318. var idx = 0
  7319. , marker
  7320. , length
  7321. ;
  7322. if (!br) {
  7323. br = _br;
  7324. }
  7325. // examine all through the end, since some images might have very large APP segments
  7326. while (idx <= br.length()) {
  7327. marker = br.SHORT(idx += 2);
  7328. if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn
  7329. idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte)
  7330. return {
  7331. height: br.SHORT(idx),
  7332. width: br.SHORT(idx += 2)
  7333. };
  7334. }
  7335. length = br.SHORT(idx += 2);
  7336. idx += length - 2;
  7337. }
  7338. return null;
  7339. }
  7340. function _getThumb() {
  7341. var data = _ep.thumb()
  7342. , br
  7343. , info
  7344. ;
  7345. if (data) {
  7346. br = new BinaryReader(data);
  7347. info = _getDimensions(br);
  7348. br.clear();
  7349. if (info) {
  7350. info.data = data;
  7351. return info;
  7352. }
  7353. }
  7354. return null;
  7355. }
  7356. function _purge() {
  7357. if (!_ep || !_hm || !_br) {
  7358. return; // ignore any repeating purge requests
  7359. }
  7360. _ep.clear();
  7361. _hm.purge();
  7362. _br.clear();
  7363. _info = _hm = _ep = _br = null;
  7364. }
  7365. }
  7366. return JPEG;
  7367. });
  7368. // Included from: src/javascript/runtime/html5/image/PNG.js
  7369. /**
  7370. * PNG.js
  7371. *
  7372. * Copyright 2013, Moxiecode Systems AB
  7373. * Released under GPL License.
  7374. *
  7375. * License: http://www.plupload.com/license
  7376. * Contributing: http://www.plupload.com/contributing
  7377. */
  7378. /**
  7379. @class moxie/runtime/html5/image/PNG
  7380. @private
  7381. */
  7382. define("moxie/runtime/html5/image/PNG", [
  7383. "moxie/core/Exceptions",
  7384. "moxie/core/utils/Basic",
  7385. "moxie/runtime/html5/utils/BinaryReader"
  7386. ], function(x, Basic, BinaryReader) {
  7387. function PNG(data) {
  7388. var _br, _hm, _ep, _info;
  7389. _br = new BinaryReader(data);
  7390. // check if it's png
  7391. (function() {
  7392. var idx = 0, i = 0
  7393. , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A]
  7394. ;
  7395. for (i = 0; i < signature.length; i++, idx += 2) {
  7396. if (signature[i] != _br.SHORT(idx)) {
  7397. throw new x.ImageError(x.ImageError.WRONG_FORMAT);
  7398. }
  7399. }
  7400. }());
  7401. function _getDimensions() {
  7402. var chunk, idx;
  7403. chunk = _getChunkAt.call(this, 8);
  7404. if (chunk.type == 'IHDR') {
  7405. idx = chunk.start;
  7406. return {
  7407. width: _br.LONG(idx),
  7408. height: _br.LONG(idx += 4)
  7409. };
  7410. }
  7411. return null;
  7412. }
  7413. function _purge() {
  7414. if (!_br) {
  7415. return; // ignore any repeating purge requests
  7416. }
  7417. _br.clear();
  7418. data = _info = _hm = _ep = _br = null;
  7419. }
  7420. _info = _getDimensions.call(this);
  7421. Basic.extend(this, {
  7422. type: 'image/png',
  7423. size: _br.length(),
  7424. width: _info.width,
  7425. height: _info.height,
  7426. purge: function() {
  7427. _purge.call(this);
  7428. }
  7429. });
  7430. // for PNG we can safely trigger purge automatically, as we do not keep any data for later
  7431. _purge.call(this);
  7432. function _getChunkAt(idx) {
  7433. var length, type, start, CRC;
  7434. length = _br.LONG(idx);
  7435. type = _br.STRING(idx += 4, 4);
  7436. start = idx += 4;
  7437. CRC = _br.LONG(idx + length);
  7438. return {
  7439. length: length,
  7440. type: type,
  7441. start: start,
  7442. CRC: CRC
  7443. };
  7444. }
  7445. }
  7446. return PNG;
  7447. });
  7448. // Included from: src/javascript/runtime/html5/image/ImageInfo.js
  7449. /**
  7450. * ImageInfo.js
  7451. *
  7452. * Copyright 2013, Moxiecode Systems AB
  7453. * Released under GPL License.
  7454. *
  7455. * License: http://www.plupload.com/license
  7456. * Contributing: http://www.plupload.com/contributing
  7457. */
  7458. /**
  7459. Optional image investigation tool for HTML5 runtime. Provides the following features:
  7460. - ability to distinguish image type (JPEG or PNG) by signature
  7461. - ability to extract image width/height directly from it's internals, without preloading in memory (fast)
  7462. - ability to extract APP headers from JPEGs (Exif, GPS, etc)
  7463. - ability to replace width/height tags in extracted JPEG headers
  7464. - ability to restore APP headers, that were for example stripped during image manipulation
  7465. @class moxie/runtime/html5/image/ImageInfo
  7466. @private
  7467. @param {String} data Image source as binary string
  7468. */
  7469. define("moxie/runtime/html5/image/ImageInfo", [
  7470. "moxie/core/utils/Basic",
  7471. "moxie/core/Exceptions",
  7472. "moxie/runtime/html5/image/JPEG",
  7473. "moxie/runtime/html5/image/PNG"
  7474. ], function(Basic, x, JPEG, PNG) {
  7475. return function(data) {
  7476. var _cs = [JPEG, PNG], _img;
  7477. // figure out the format, throw: ImageError.WRONG_FORMAT if not supported
  7478. _img = (function() {
  7479. for (var i = 0; i < _cs.length; i++) {
  7480. try {
  7481. return new _cs[i](data);
  7482. } catch (ex) {
  7483. // console.info(ex);
  7484. }
  7485. }
  7486. throw new x.ImageError(x.ImageError.WRONG_FORMAT);
  7487. }());
  7488. Basic.extend(this, {
  7489. /**
  7490. Image Mime Type extracted from it's depths
  7491. @property type
  7492. @type {String}
  7493. @default ''
  7494. */
  7495. type: '',
  7496. /**
  7497. Image size in bytes
  7498. @property size
  7499. @type {Number}
  7500. @default 0
  7501. */
  7502. size: 0,
  7503. /**
  7504. Image width extracted from image source
  7505. @property width
  7506. @type {Number}
  7507. @default 0
  7508. */
  7509. width: 0,
  7510. /**
  7511. Image height extracted from image source
  7512. @property height
  7513. @type {Number}
  7514. @default 0
  7515. */
  7516. height: 0,
  7517. /**
  7518. Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs.
  7519. @method setExif
  7520. @param {String} tag Tag to set
  7521. @param {Mixed} value Value to assign to the tag
  7522. */
  7523. setExif: function() {},
  7524. /**
  7525. Restores headers to the source.
  7526. @method writeHeaders
  7527. @param {String} data Image source as binary string
  7528. @return {String} Updated binary string
  7529. */
  7530. writeHeaders: function(data) {
  7531. return data;
  7532. },
  7533. /**
  7534. Strip all headers from the source.
  7535. @method stripHeaders
  7536. @param {String} data Image source as binary string
  7537. @return {String} Updated binary string
  7538. */
  7539. stripHeaders: function(data) {
  7540. return data;
  7541. },
  7542. /**
  7543. Dispose resources.
  7544. @method purge
  7545. */
  7546. purge: function() {
  7547. data = null;
  7548. }
  7549. });
  7550. Basic.extend(this, _img);
  7551. this.purge = function() {
  7552. _img.purge();
  7553. _img = null;
  7554. };
  7555. };
  7556. });
  7557. // Included from: src/javascript/runtime/html5/image/ResizerCanvas.js
  7558. /**
  7559. * ResizerCanvas.js
  7560. *
  7561. * Copyright 2013, Moxiecode Systems AB
  7562. * Released under GPL License.
  7563. *
  7564. * License: http://www.plupload.com/license
  7565. * Contributing: http://www.plupload.com/contributing
  7566. */
  7567. /**
  7568. * Resizes image/canvas using canvas
  7569. */
  7570. define("moxie/runtime/html5/image/ResizerCanvas", [], function() {
  7571. function scale(image, ratio, resample) {
  7572. var sD = image.width > image.height ? 'width' : 'height'; // take the largest side
  7573. var dD = Math.round(image[sD] * ratio);
  7574. var scaleCapped = false;
  7575. if (resample !== 'nearest' && (ratio < 0.5 || ratio > 2)) {
  7576. ratio = ratio < 0.5 ? 0.5 : 2;
  7577. scaleCapped = true;
  7578. }
  7579. var tCanvas = _scale(image, ratio);
  7580. if (scaleCapped) {
  7581. return scale(tCanvas, dD / tCanvas[sD], resample);
  7582. } else {
  7583. return tCanvas;
  7584. }
  7585. }
  7586. function _scale(image, ratio) {
  7587. var sW = image.width;
  7588. var sH = image.height;
  7589. var dW = Math.round(sW * ratio);
  7590. var dH = Math.round(sH * ratio);
  7591. var canvas = document.createElement('canvas');
  7592. canvas.width = dW;
  7593. canvas.height = dH;
  7594. canvas.getContext("2d").drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH);
  7595. image = null; // just in case
  7596. return canvas;
  7597. }
  7598. return {
  7599. scale: scale
  7600. };
  7601. });
  7602. // Included from: src/javascript/runtime/html5/image/Image.js
  7603. /**
  7604. * Image.js
  7605. *
  7606. * Copyright 2013, Moxiecode Systems AB
  7607. * Released under GPL License.
  7608. *
  7609. * License: http://www.plupload.com/license
  7610. * Contributing: http://www.plupload.com/contributing
  7611. */
  7612. /**
  7613. @class moxie/runtime/html5/image/Image
  7614. @private
  7615. */
  7616. define("moxie/runtime/html5/image/Image", [
  7617. "moxie/runtime/html5/Runtime",
  7618. "moxie/core/utils/Basic",
  7619. "moxie/core/Exceptions",
  7620. "moxie/core/utils/Encode",
  7621. "moxie/file/Blob",
  7622. "moxie/file/File",
  7623. "moxie/runtime/html5/image/ImageInfo",
  7624. "moxie/runtime/html5/image/ResizerCanvas",
  7625. "moxie/core/utils/Mime",
  7626. "moxie/core/utils/Env"
  7627. ], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) {
  7628. function HTML5Image() {
  7629. var me = this
  7630. , _img, _imgInfo, _canvas, _binStr, _blob
  7631. , _modified = false // is set true whenever image is modified
  7632. , _preserveHeaders = true
  7633. ;
  7634. Basic.extend(this, {
  7635. loadFromBlob: function(blob) {
  7636. var I = this.getRuntime()
  7637. , asBinary = arguments.length > 1 ? arguments[1] : true
  7638. ;
  7639. if (!I.can('access_binary')) {
  7640. throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
  7641. }
  7642. _blob = blob;
  7643. if (blob.isDetached()) {
  7644. _binStr = blob.getSource();
  7645. _preload.call(this, _binStr);
  7646. return;
  7647. } else {
  7648. _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
  7649. if (asBinary) {
  7650. _binStr = _toBinary(dataUrl);
  7651. }
  7652. _preload.call(this, dataUrl);
  7653. });
  7654. }
  7655. },
  7656. loadFromImage: function(img, exact) {
  7657. this.meta = img.meta;
  7658. _blob = new File(null, {
  7659. name: img.name,
  7660. size: img.size,
  7661. type: img.type
  7662. });
  7663. _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
  7664. },
  7665. getInfo: function() {
  7666. var I = this.getRuntime(), info;
  7667. if (!_imgInfo && _binStr && I.can('access_image_binary')) {
  7668. _imgInfo = new ImageInfo(_binStr);
  7669. }
  7670. // this stuff below is definitely having fun with itself
  7671. info = {
  7672. width: _getImg().width || 0,
  7673. height: _getImg().height || 0,
  7674. type: _blob.type || Mime.getFileMime(_blob.name),
  7675. size: _binStr && _binStr.length || _blob.size || 0,
  7676. name: _blob.name || '',
  7677. meta: null
  7678. };
  7679. if (_preserveHeaders) {
  7680. info.meta = _imgInfo && _imgInfo.meta || this.meta || {};
  7681. // if data was taken from ImageInfo it will be a binary string, so we convert it to blob
  7682. if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
  7683. info.meta.thumb.data = new Blob(null, {
  7684. type: 'image/jpeg',
  7685. data: info.meta.thumb.data
  7686. });
  7687. }
  7688. }
  7689. return info;
  7690. },
  7691. resize: function(rect, ratio, options) {
  7692. var canvas = document.createElement('canvas');
  7693. canvas.width = rect.width;
  7694. canvas.height = rect.height;
  7695. canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height);
  7696. _canvas = ResizerCanvas.scale(canvas, ratio);
  7697. _preserveHeaders = options.preserveHeaders;
  7698. // rotate if required, according to orientation tag
  7699. if (!_preserveHeaders) {
  7700. var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
  7701. _canvas = _rotateToOrientaion(_canvas, orientation);
  7702. }
  7703. this.width = _canvas.width;
  7704. this.height = _canvas.height;
  7705. _modified = true;
  7706. this.trigger('Resize');
  7707. },
  7708. getAsCanvas: function() {
  7709. if (!_canvas) {
  7710. _canvas = _getCanvas();
  7711. }
  7712. _canvas.id = this.uid + '_canvas';
  7713. return _canvas;
  7714. },
  7715. getAsBlob: function(type, quality) {
  7716. if (type !== this.type) {
  7717. _modified = true; // reconsider the state
  7718. return new File(null, {
  7719. name: _blob.name || '',
  7720. type: type,
  7721. data: me.getAsDataURL(type, quality)
  7722. });
  7723. }
  7724. return new File(null, {
  7725. name: _blob.name || '',
  7726. type: type,
  7727. data: me.getAsBinaryString(type, quality)
  7728. });
  7729. },
  7730. getAsDataURL: function(type) {
  7731. var quality = arguments[1] || 90;
  7732. // if image has not been modified, return the source right away
  7733. if (!_modified) {
  7734. return _img.src;
  7735. }
  7736. // make sure we have a canvas to work with
  7737. _getCanvas();
  7738. if ('image/jpeg' !== type) {
  7739. return _canvas.toDataURL('image/png');
  7740. } else {
  7741. try {
  7742. // older Geckos used to result in an exception on quality argument
  7743. return _canvas.toDataURL('image/jpeg', quality/100);
  7744. } catch (ex) {
  7745. return _canvas.toDataURL('image/jpeg');
  7746. }
  7747. }
  7748. },
  7749. getAsBinaryString: function(type, quality) {
  7750. // if image has not been modified, return the source right away
  7751. if (!_modified) {
  7752. // if image was not loaded from binary string
  7753. if (!_binStr) {
  7754. _binStr = _toBinary(me.getAsDataURL(type, quality));
  7755. }
  7756. return _binStr;
  7757. }
  7758. if ('image/jpeg' !== type) {
  7759. _binStr = _toBinary(me.getAsDataURL(type, quality));
  7760. } else {
  7761. var dataUrl;
  7762. // if jpeg
  7763. if (!quality) {
  7764. quality = 90;
  7765. }
  7766. // make sure we have a canvas to work with
  7767. _getCanvas();
  7768. try {
  7769. // older Geckos used to result in an exception on quality argument
  7770. dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
  7771. } catch (ex) {
  7772. dataUrl = _canvas.toDataURL('image/jpeg');
  7773. }
  7774. _binStr = _toBinary(dataUrl);
  7775. if (_imgInfo) {
  7776. _binStr = _imgInfo.stripHeaders(_binStr);
  7777. if (_preserveHeaders) {
  7778. // update dimensions info in exif
  7779. if (_imgInfo.meta && _imgInfo.meta.exif) {
  7780. _imgInfo.setExif({
  7781. PixelXDimension: this.width,
  7782. PixelYDimension: this.height
  7783. });
  7784. }
  7785. // re-inject the headers
  7786. _binStr = _imgInfo.writeHeaders(_binStr);
  7787. }
  7788. // will be re-created from fresh on next getInfo call
  7789. _imgInfo.purge();
  7790. _imgInfo = null;
  7791. }
  7792. }
  7793. _modified = false;
  7794. return _binStr;
  7795. },
  7796. destroy: function() {
  7797. me = null;
  7798. _purge.call(this);
  7799. this.getRuntime().getShim().removeInstance(this.uid);
  7800. }
  7801. });
  7802. function _getImg() {
  7803. if (!_canvas && !_img) {
  7804. throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
  7805. }
  7806. return _canvas || _img;
  7807. }
  7808. function _getCanvas() {
  7809. var canvas = _getImg();
  7810. if (canvas.nodeName.toLowerCase() == 'canvas') {
  7811. return canvas;
  7812. }
  7813. _canvas = document.createElement('canvas');
  7814. _canvas.width = canvas.width;
  7815. _canvas.height = canvas.height;
  7816. _canvas.getContext("2d").drawImage(canvas, 0, 0);
  7817. return _canvas;
  7818. }
  7819. function _toBinary(str) {
  7820. return Encode.atob(str.substring(str.indexOf('base64,') + 7));
  7821. }
  7822. function _toDataUrl(str, type) {
  7823. return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
  7824. }
  7825. function _preload(str) {
  7826. var comp = this;
  7827. _img = new Image();
  7828. _img.onerror = function() {
  7829. _purge.call(this);
  7830. comp.trigger('error', x.ImageError.WRONG_FORMAT);
  7831. };
  7832. _img.onload = function() {
  7833. comp.trigger('load');
  7834. };
  7835. _img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
  7836. }
  7837. function _readAsDataUrl(file, callback) {
  7838. var comp = this, fr;
  7839. // use FileReader if it's available
  7840. if (window.FileReader) {
  7841. fr = new FileReader();
  7842. fr.onload = function() {
  7843. callback.call(comp, this.result);
  7844. };
  7845. fr.onerror = function() {
  7846. comp.trigger('error', x.ImageError.WRONG_FORMAT);
  7847. };
  7848. fr.readAsDataURL(file);
  7849. } else {
  7850. return callback.call(this, file.getAsDataURL());
  7851. }
  7852. }
  7853. /**
  7854. * Transform canvas coordination according to specified frame size and orientation
  7855. * Orientation value is from EXIF tag
  7856. * @author Shinichi Tomita <shinichi.tomita@gmail.com>
  7857. */
  7858. function _rotateToOrientaion(img, orientation) {
  7859. var RADIANS = Math.PI/180;
  7860. var canvas = document.createElement('canvas');
  7861. var ctx = canvas.getContext('2d');
  7862. var width = img.width;
  7863. var height = img.height;
  7864. if (Basic.inArray(orientation, [5,6,7,8]) > -1) {
  7865. canvas.width = height;
  7866. canvas.height = width;
  7867. } else {
  7868. canvas.width = width;
  7869. canvas.height = height;
  7870. }
  7871. /**
  7872. 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
  7873. 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
  7874. 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
  7875. 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
  7876. 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
  7877. 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
  7878. 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
  7879. 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
  7880. */
  7881. switch (orientation) {
  7882. case 2:
  7883. // horizontal flip
  7884. ctx.translate(width, 0);
  7885. ctx.scale(-1, 1);
  7886. break;
  7887. case 3:
  7888. // 180 rotate left
  7889. ctx.translate(width, height);
  7890. ctx.rotate(180 * RADIANS);
  7891. break;
  7892. case 4:
  7893. // vertical flip
  7894. ctx.translate(0, height);
  7895. ctx.scale(1, -1);
  7896. break;
  7897. case 5:
  7898. // vertical flip + 90 rotate right
  7899. ctx.rotate(90 * RADIANS);
  7900. ctx.scale(1, -1);
  7901. break;
  7902. case 6:
  7903. // 90 rotate right
  7904. ctx.rotate(90 * RADIANS);
  7905. ctx.translate(0, -height);
  7906. break;
  7907. case 7:
  7908. // horizontal flip + 90 rotate right
  7909. ctx.rotate(90 * RADIANS);
  7910. ctx.translate(width, -height);
  7911. ctx.scale(-1, 1);
  7912. break;
  7913. case 8:
  7914. // 90 rotate left
  7915. ctx.rotate(-90 * RADIANS);
  7916. ctx.translate(-width, 0);
  7917. break;
  7918. }
  7919. ctx.drawImage(img, 0, 0, width, height);
  7920. return canvas;
  7921. }
  7922. function _purge() {
  7923. if (_imgInfo) {
  7924. _imgInfo.purge();
  7925. _imgInfo = null;
  7926. }
  7927. _binStr = _img = _canvas = _blob = null;
  7928. _modified = false;
  7929. }
  7930. }
  7931. return (extensions.Image = HTML5Image);
  7932. });
  7933. // Included from: src/javascript/runtime/flash/Runtime.js
  7934. /**
  7935. * Runtime.js
  7936. *
  7937. * Copyright 2013, Moxiecode Systems AB
  7938. * Released under GPL License.
  7939. *
  7940. * License: http://www.plupload.com/license
  7941. * Contributing: http://www.plupload.com/contributing
  7942. */
  7943. /*global ActiveXObject:true */
  7944. /**
  7945. Defines constructor for Flash runtime.
  7946. @class moxie/runtime/flash/Runtime
  7947. @private
  7948. */
  7949. define("moxie/runtime/flash/Runtime", [
  7950. "moxie/core/utils/Basic",
  7951. "moxie/core/utils/Env",
  7952. "moxie/core/utils/Dom",
  7953. "moxie/core/Exceptions",
  7954. "moxie/runtime/Runtime"
  7955. ], function(Basic, Env, Dom, x, Runtime) {
  7956. var type = 'flash', extensions = {};
  7957. /**
  7958. Get the version of the Flash Player
  7959. @method getShimVersion
  7960. @private
  7961. @return {Number} Flash Player version
  7962. */
  7963. function getShimVersion() {
  7964. var version;
  7965. try {
  7966. version = navigator.plugins['Shockwave Flash'];
  7967. version = version.description;
  7968. } catch (e1) {
  7969. try {
  7970. version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
  7971. } catch (e2) {
  7972. version = '0.0';
  7973. }
  7974. }
  7975. version = version.match(/\d+/g);
  7976. return parseFloat(version[0] + '.' + version[1]);
  7977. }
  7978. /**
  7979. Cross-browser SWF removal
  7980. - Especially needed to safely and completely remove a SWF in Internet Explorer
  7981. Originated from SWFObject v2.2 <http://code.google.com/p/swfobject/>
  7982. */
  7983. function removeSWF(id) {
  7984. var obj = Dom.get(id);
  7985. if (obj && obj.nodeName == "OBJECT") {
  7986. if (Env.browser === 'IE') {
  7987. obj.style.display = "none";
  7988. (function onInit(){
  7989. // http://msdn.microsoft.com/en-us/library/ie/ms534360(v=vs.85).aspx
  7990. if (obj.readyState == 4) {
  7991. removeObjectInIE(id);
  7992. }
  7993. else {
  7994. setTimeout(onInit, 10);
  7995. }
  7996. })();
  7997. }
  7998. else {
  7999. obj.parentNode.removeChild(obj);
  8000. }
  8001. }
  8002. }
  8003. function removeObjectInIE(id) {
  8004. var obj = Dom.get(id);
  8005. if (obj) {
  8006. for (var i in obj) {
  8007. if (typeof obj[i] == "function") {
  8008. obj[i] = null;
  8009. }
  8010. }
  8011. obj.parentNode.removeChild(obj);
  8012. }
  8013. }
  8014. /**
  8015. Constructor for the Flash Runtime
  8016. */
  8017. function FlashRuntime(options) {
  8018. var I = this, initTimer;
  8019. options = Basic.extend({ swf_url: Env.swf_url }, options);
  8020. Runtime.call(this, options, type, {
  8021. access_binary: function(value) {
  8022. return value && I.mode === 'browser';
  8023. },
  8024. access_image_binary: function(value) {
  8025. return value && I.mode === 'browser';
  8026. },
  8027. display_media: Runtime.capTest(defined('moxie/image/Image')),
  8028. do_cors: Runtime.capTrue,
  8029. drag_and_drop: false,
  8030. report_upload_progress: function() {
  8031. return I.mode === 'client';
  8032. },
  8033. resize_image: Runtime.capTrue,
  8034. return_response_headers: false,
  8035. return_response_type: function(responseType) {
  8036. if (responseType === 'json' && !!window.JSON) {
  8037. return true;
  8038. }
  8039. return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser';
  8040. },
  8041. return_status_code: function(code) {
  8042. return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]);
  8043. },
  8044. select_file: Runtime.capTrue,
  8045. select_multiple: Runtime.capTrue,
  8046. send_binary_string: function(value) {
  8047. return value && I.mode === 'browser';
  8048. },
  8049. send_browser_cookies: function(value) {
  8050. return value && I.mode === 'browser';
  8051. },
  8052. send_custom_headers: function(value) {
  8053. return value && I.mode === 'browser';
  8054. },
  8055. send_multipart: Runtime.capTrue,
  8056. slice_blob: function(value) {
  8057. return value && I.mode === 'browser';
  8058. },
  8059. stream_upload: function(value) {
  8060. return value && I.mode === 'browser';
  8061. },
  8062. summon_file_dialog: false,
  8063. upload_filesize: function(size) {
  8064. return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client';
  8065. },
  8066. use_http_method: function(methods) {
  8067. return !Basic.arrayDiff(methods, ['GET', 'POST']);
  8068. }
  8069. }, {
  8070. // capabilities that require specific mode
  8071. access_binary: function(value) {
  8072. return value ? 'browser' : 'client';
  8073. },
  8074. access_image_binary: function(value) {
  8075. return value ? 'browser' : 'client';
  8076. },
  8077. report_upload_progress: function(value) {
  8078. return value ? 'browser' : 'client';
  8079. },
  8080. return_response_type: function(responseType) {
  8081. return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser'];
  8082. },
  8083. return_status_code: function(code) {
  8084. return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser'];
  8085. },
  8086. send_binary_string: function(value) {
  8087. return value ? 'browser' : 'client';
  8088. },
  8089. send_browser_cookies: function(value) {
  8090. return value ? 'browser' : 'client';
  8091. },
  8092. send_custom_headers: function(value) {
  8093. return value ? 'browser' : 'client';
  8094. },
  8095. slice_blob: function(value) {
  8096. return value ? 'browser' : 'client';
  8097. },
  8098. stream_upload: function(value) {
  8099. return value ? 'client' : 'browser';
  8100. },
  8101. upload_filesize: function(size) {
  8102. return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser';
  8103. }
  8104. }, 'client');
  8105. // minimal requirement for Flash Player version
  8106. if (getShimVersion() < 11.3) {
  8107. if (MXI_DEBUG && Env.debug.runtime) {
  8108. Env.log("\tFlash didn't meet minimal version requirement (11.3).");
  8109. }
  8110. this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before
  8111. }
  8112. Basic.extend(this, {
  8113. getShim: function() {
  8114. return Dom.get(this.uid);
  8115. },
  8116. shimExec: function(component, action) {
  8117. var args = [].slice.call(arguments, 2);
  8118. return I.getShim().exec(this.uid, component, action, args);
  8119. },
  8120. init: function() {
  8121. var html, el, container;
  8122. container = this.getShimContainer();
  8123. // if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)
  8124. Basic.extend(container.style, {
  8125. position: 'absolute',
  8126. top: '-8px',
  8127. left: '-8px',
  8128. width: '9px',
  8129. height: '9px',
  8130. overflow: 'hidden'
  8131. });
  8132. // insert flash object
  8133. html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' + options.swf_url + '" ';
  8134. if (Env.browser === 'IE') {
  8135. html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
  8136. }
  8137. html += 'width="100%" height="100%" style="outline:0">' +
  8138. '<param name="movie" value="' + options.swf_url + '" />' +
  8139. '<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Runtime.getGlobalEventTarget() + '" />' +
  8140. '<param name="wmode" value="transparent" />' +
  8141. '<param name="allowscriptaccess" value="always" />' +
  8142. '</object>';
  8143. if (Env.browser === 'IE') {
  8144. el = document.createElement('div');
  8145. container.appendChild(el);
  8146. el.outerHTML = html;
  8147. el = container = null; // just in case
  8148. } else {
  8149. container.innerHTML = html;
  8150. }
  8151. // Init is dispatched by the shim
  8152. initTimer = setTimeout(function() {
  8153. if (I && !I.initialized) { // runtime might be already destroyed by this moment
  8154. I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
  8155. if (MXI_DEBUG && Env.debug.runtime) {
  8156. Env.log("\tFlash failed to initialize within a specified period of time (typically 5s).");
  8157. }
  8158. }
  8159. }, 5000);
  8160. },
  8161. destroy: (function(destroy) { // extend default destroy method
  8162. return function() {
  8163. removeSWF(I.uid); // SWF removal requires special care in IE
  8164. destroy.call(I);
  8165. clearTimeout(initTimer); // initialization check might be still onwait
  8166. options = initTimer = destroy = I = null;
  8167. };
  8168. }(this.destroy))
  8169. }, extensions);
  8170. }
  8171. Runtime.addConstructor(type, FlashRuntime);
  8172. return extensions;
  8173. });
  8174. // Included from: src/javascript/runtime/flash/file/Blob.js
  8175. /**
  8176. * Blob.js
  8177. *
  8178. * Copyright 2013, Moxiecode Systems AB
  8179. * Released under GPL License.
  8180. *
  8181. * License: http://www.plupload.com/license
  8182. * Contributing: http://www.plupload.com/contributing
  8183. */
  8184. /**
  8185. @class moxie/runtime/flash/file/Blob
  8186. @private
  8187. */
  8188. define("moxie/runtime/flash/file/Blob", [
  8189. "moxie/runtime/flash/Runtime",
  8190. "moxie/file/Blob"
  8191. ], function(extensions, Blob) {
  8192. var FlashBlob = {
  8193. slice: function(blob, start, end, type) {
  8194. var self = this.getRuntime();
  8195. if (start < 0) {
  8196. start = Math.max(blob.size + start, 0);
  8197. } else if (start > 0) {
  8198. start = Math.min(start, blob.size);
  8199. }
  8200. if (end < 0) {
  8201. end = Math.max(blob.size + end, 0);
  8202. } else if (end > 0) {
  8203. end = Math.min(end, blob.size);
  8204. }
  8205. blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || '');
  8206. if (blob) {
  8207. blob = new Blob(self.uid, blob);
  8208. }
  8209. return blob;
  8210. }
  8211. };
  8212. return (extensions.Blob = FlashBlob);
  8213. });
  8214. // Included from: src/javascript/runtime/flash/file/FileInput.js
  8215. /**
  8216. * FileInput.js
  8217. *
  8218. * Copyright 2013, Moxiecode Systems AB
  8219. * Released under GPL License.
  8220. *
  8221. * License: http://www.plupload.com/license
  8222. * Contributing: http://www.plupload.com/contributing
  8223. */
  8224. /**
  8225. @class moxie/runtime/flash/file/FileInput
  8226. @private
  8227. */
  8228. define("moxie/runtime/flash/file/FileInput", [
  8229. "moxie/runtime/flash/Runtime",
  8230. "moxie/file/File",
  8231. "moxie/core/utils/Dom",
  8232. "moxie/core/utils/Basic"
  8233. ], function(extensions, File, Dom, Basic) {
  8234. var FileInput = {
  8235. init: function(options) {
  8236. var comp = this, I = this.getRuntime();
  8237. var browseButton = Dom.get(options.browse_button);
  8238. if (browseButton) {
  8239. browseButton.setAttribute('tabindex', -1);
  8240. browseButton = null;
  8241. }
  8242. this.bind("Change", function() {
  8243. var files = I.shimExec.call(comp, 'FileInput', 'getFiles');
  8244. comp.files = [];
  8245. Basic.each(files, function(file) {
  8246. comp.files.push(new File(I.uid, file));
  8247. });
  8248. }, 999);
  8249. this.getRuntime().shimExec.call(this, 'FileInput', 'init', {
  8250. accept: options.accept,
  8251. multiple: options.multiple
  8252. });
  8253. this.trigger('ready');
  8254. }
  8255. };
  8256. return (extensions.FileInput = FileInput);
  8257. });
  8258. // Included from: src/javascript/runtime/flash/file/FileReader.js
  8259. /**
  8260. * FileReader.js
  8261. *
  8262. * Copyright 2013, Moxiecode Systems AB
  8263. * Released under GPL License.
  8264. *
  8265. * License: http://www.plupload.com/license
  8266. * Contributing: http://www.plupload.com/contributing
  8267. */
  8268. /**
  8269. @class moxie/runtime/flash/file/FileReader
  8270. @private
  8271. */
  8272. define("moxie/runtime/flash/file/FileReader", [
  8273. "moxie/runtime/flash/Runtime",
  8274. "moxie/core/utils/Encode"
  8275. ], function(extensions, Encode) {
  8276. function _formatData(data, op) {
  8277. switch (op) {
  8278. case 'readAsText':
  8279. return Encode.atob(data, 'utf8');
  8280. case 'readAsBinaryString':
  8281. return Encode.atob(data);
  8282. case 'readAsDataURL':
  8283. return data;
  8284. }
  8285. return null;
  8286. }
  8287. var FileReader = {
  8288. read: function(op, blob) {
  8289. var comp = this;
  8290. comp.result = '';
  8291. // special prefix for DataURL read mode
  8292. if (op === 'readAsDataURL') {
  8293. comp.result = 'data:' + (blob.type || '') + ';base64,';
  8294. }
  8295. comp.bind('Progress', function(e, data) {
  8296. if (data) {
  8297. comp.result += _formatData(data, op);
  8298. }
  8299. }, 999);
  8300. return comp.getRuntime().shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid);
  8301. }
  8302. };
  8303. return (extensions.FileReader = FileReader);
  8304. });
  8305. // Included from: src/javascript/runtime/flash/file/FileReaderSync.js
  8306. /**
  8307. * FileReaderSync.js
  8308. *
  8309. * Copyright 2013, Moxiecode Systems AB
  8310. * Released under GPL License.
  8311. *
  8312. * License: http://www.plupload.com/license
  8313. * Contributing: http://www.plupload.com/contributing
  8314. */
  8315. /**
  8316. @class moxie/runtime/flash/file/FileReaderSync
  8317. @private
  8318. */
  8319. define("moxie/runtime/flash/file/FileReaderSync", [
  8320. "moxie/runtime/flash/Runtime",
  8321. "moxie/core/utils/Encode"
  8322. ], function(extensions, Encode) {
  8323. function _formatData(data, op) {
  8324. switch (op) {
  8325. case 'readAsText':
  8326. return Encode.atob(data, 'utf8');
  8327. case 'readAsBinaryString':
  8328. return Encode.atob(data);
  8329. case 'readAsDataURL':
  8330. return data;
  8331. }
  8332. return null;
  8333. }
  8334. var FileReaderSync = {
  8335. read: function(op, blob) {
  8336. var result, self = this.getRuntime();
  8337. result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid);
  8338. if (!result) {
  8339. return null; // or throw ex
  8340. }
  8341. // special prefix for DataURL read mode
  8342. if (op === 'readAsDataURL') {
  8343. result = 'data:' + (blob.type || '') + ';base64,' + result;
  8344. }
  8345. return _formatData(result, op, blob.type);
  8346. }
  8347. };
  8348. return (extensions.FileReaderSync = FileReaderSync);
  8349. });
  8350. // Included from: src/javascript/runtime/flash/runtime/Transporter.js
  8351. /**
  8352. * Transporter.js
  8353. *
  8354. * Copyright 2013, Moxiecode Systems AB
  8355. * Released under GPL License.
  8356. *
  8357. * License: http://www.plupload.com/license
  8358. * Contributing: http://www.plupload.com/contributing
  8359. */
  8360. /**
  8361. @class moxie/runtime/flash/runtime/Transporter
  8362. @private
  8363. */
  8364. define("moxie/runtime/flash/runtime/Transporter", [
  8365. "moxie/runtime/flash/Runtime",
  8366. "moxie/file/Blob"
  8367. ], function(extensions, Blob) {
  8368. var Transporter = {
  8369. getAsBlob: function(type) {
  8370. var self = this.getRuntime()
  8371. , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type)
  8372. ;
  8373. if (blob) {
  8374. return new Blob(self.uid, blob);
  8375. }
  8376. return null;
  8377. }
  8378. };
  8379. return (extensions.Transporter = Transporter);
  8380. });
  8381. // Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js
  8382. /**
  8383. * XMLHttpRequest.js
  8384. *
  8385. * Copyright 2013, Moxiecode Systems AB
  8386. * Released under GPL License.
  8387. *
  8388. * License: http://www.plupload.com/license
  8389. * Contributing: http://www.plupload.com/contributing
  8390. */
  8391. /**
  8392. @class moxie/runtime/flash/xhr/XMLHttpRequest
  8393. @private
  8394. */
  8395. define("moxie/runtime/flash/xhr/XMLHttpRequest", [
  8396. "moxie/runtime/flash/Runtime",
  8397. "moxie/core/utils/Basic",
  8398. "moxie/file/Blob",
  8399. "moxie/file/File",
  8400. "moxie/file/FileReaderSync",
  8401. "moxie/runtime/flash/file/FileReaderSync",
  8402. "moxie/xhr/FormData",
  8403. "moxie/runtime/Transporter",
  8404. "moxie/runtime/flash/runtime/Transporter"
  8405. ], function(extensions, Basic, Blob, File, FileReaderSync, FileReaderSyncFlash, FormData, Transporter, TransporterFlash) {
  8406. var XMLHttpRequest = {
  8407. send: function(meta, data) {
  8408. var target = this, self = target.getRuntime();
  8409. function send() {
  8410. meta.transport = self.mode;
  8411. self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data);
  8412. }
  8413. function appendBlob(name, blob) {
  8414. self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid);
  8415. data = null;
  8416. send();
  8417. }
  8418. function attachBlob(blob, cb) {
  8419. var tr = new Transporter();
  8420. tr.bind("TransportingComplete", function() {
  8421. cb(this.result);
  8422. });
  8423. tr.transport(blob.getSource(), blob.type, {
  8424. ruid: self.uid
  8425. });
  8426. }
  8427. // copy over the headers if any
  8428. if (!Basic.isEmptyObj(meta.headers)) {
  8429. Basic.each(meta.headers, function(value, header) {
  8430. self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object
  8431. });
  8432. }
  8433. // transfer over multipart params and blob itself
  8434. if (data instanceof FormData) {
  8435. var blobField;
  8436. data.each(function(value, name) {
  8437. if (value instanceof Blob) {
  8438. blobField = name;
  8439. } else {
  8440. self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value);
  8441. }
  8442. });
  8443. if (!data.hasBlob()) {
  8444. data = null;
  8445. send();
  8446. } else {
  8447. var blob = data.getBlob();
  8448. if (blob.isDetached()) {
  8449. attachBlob(blob, function(attachedBlob) {
  8450. blob.destroy();
  8451. appendBlob(blobField, attachedBlob);
  8452. });
  8453. } else {
  8454. appendBlob(blobField, blob);
  8455. }
  8456. }
  8457. } else if (data instanceof Blob) {
  8458. if (data.isDetached()) {
  8459. attachBlob(data, function(attachedBlob) {
  8460. data.destroy();
  8461. data = attachedBlob.uid;
  8462. send();
  8463. });
  8464. } else {
  8465. data = data.uid;
  8466. send();
  8467. }
  8468. } else {
  8469. send();
  8470. }
  8471. },
  8472. getResponse: function(responseType) {
  8473. var frs, blob, self = this.getRuntime();
  8474. blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob');
  8475. if (blob) {
  8476. blob = new File(self.uid, blob);
  8477. if ('blob' === responseType) {
  8478. return blob;
  8479. }
  8480. try {
  8481. frs = new FileReaderSync();
  8482. if (!!~Basic.inArray(responseType, ["", "text"])) {
  8483. return frs.readAsText(blob);
  8484. } else if ('json' === responseType && !!window.JSON) {
  8485. return JSON.parse(frs.readAsText(blob));
  8486. }
  8487. } finally {
  8488. blob.destroy();
  8489. }
  8490. }
  8491. return null;
  8492. },
  8493. abort: function(upload_complete_flag) {
  8494. var self = this.getRuntime();
  8495. self.shimExec.call(this, 'XMLHttpRequest', 'abort');
  8496. this.dispatchEvent('readystatechange');
  8497. // this.dispatchEvent('progress');
  8498. this.dispatchEvent('abort');
  8499. //if (!upload_complete_flag) {
  8500. // this.dispatchEvent('uploadprogress');
  8501. //}
  8502. }
  8503. };
  8504. return (extensions.XMLHttpRequest = XMLHttpRequest);
  8505. });
  8506. // Included from: src/javascript/runtime/flash/image/Image.js
  8507. /**
  8508. * Image.js
  8509. *
  8510. * Copyright 2013, Moxiecode Systems AB
  8511. * Released under GPL License.
  8512. *
  8513. * License: http://www.plupload.com/license
  8514. * Contributing: http://www.plupload.com/contributing
  8515. */
  8516. /**
  8517. @class moxie/runtime/flash/image/Image
  8518. @private
  8519. */
  8520. define("moxie/runtime/flash/image/Image", [
  8521. "moxie/runtime/flash/Runtime",
  8522. "moxie/core/utils/Basic",
  8523. "moxie/runtime/Transporter",
  8524. "moxie/file/Blob",
  8525. "moxie/file/FileReaderSync"
  8526. ], function(extensions, Basic, Transporter, Blob, FileReaderSync) {
  8527. var Image = {
  8528. loadFromBlob: function(blob) {
  8529. var comp = this, self = comp.getRuntime();
  8530. function exec(srcBlob) {
  8531. self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid);
  8532. comp = self = null;
  8533. }
  8534. if (blob.isDetached()) { // binary string
  8535. var tr = new Transporter();
  8536. tr.bind("TransportingComplete", function() {
  8537. exec(tr.result.getSource());
  8538. });
  8539. tr.transport(blob.getSource(), blob.type, { ruid: self.uid });
  8540. } else {
  8541. exec(blob.getSource());
  8542. }
  8543. },
  8544. loadFromImage: function(img) {
  8545. var self = this.getRuntime();
  8546. return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid);
  8547. },
  8548. getInfo: function() {
  8549. var self = this.getRuntime()
  8550. , info = self.shimExec.call(this, 'Image', 'getInfo')
  8551. ;
  8552. if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) {
  8553. info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data);
  8554. }
  8555. return info;
  8556. },
  8557. getAsBlob: function(type, quality) {
  8558. var self = this.getRuntime()
  8559. , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality)
  8560. ;
  8561. if (blob) {
  8562. return new Blob(self.uid, blob);
  8563. }
  8564. return null;
  8565. },
  8566. getAsDataURL: function() {
  8567. var self = this.getRuntime()
  8568. , blob = self.Image.getAsBlob.apply(this, arguments)
  8569. , frs
  8570. ;
  8571. if (!blob) {
  8572. return null;
  8573. }
  8574. frs = new FileReaderSync();
  8575. return frs.readAsDataURL(blob);
  8576. }
  8577. };
  8578. return (extensions.Image = Image);
  8579. });
  8580. // Included from: src/javascript/runtime/silverlight/Runtime.js
  8581. /**
  8582. * RunTime.js
  8583. *
  8584. * Copyright 2013, Moxiecode Systems AB
  8585. * Released under GPL License.
  8586. *
  8587. * License: http://www.plupload.com/license
  8588. * Contributing: http://www.plupload.com/contributing
  8589. */
  8590. /*global ActiveXObject:true */
  8591. /**
  8592. Defines constructor for Silverlight runtime.
  8593. @class moxie/runtime/silverlight/Runtime
  8594. @private
  8595. */
  8596. define("moxie/runtime/silverlight/Runtime", [
  8597. "moxie/core/utils/Basic",
  8598. "moxie/core/utils/Env",
  8599. "moxie/core/utils/Dom",
  8600. "moxie/core/Exceptions",
  8601. "moxie/runtime/Runtime"
  8602. ], function(Basic, Env, Dom, x, Runtime) {
  8603. var type = "silverlight", extensions = {};
  8604. function isInstalled(version) {
  8605. var isVersionSupported = false, control = null, actualVer,
  8606. actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0;
  8607. try {
  8608. try {
  8609. control = new ActiveXObject('AgControl.AgControl');
  8610. if (control.IsVersionSupported(version)) {
  8611. isVersionSupported = true;
  8612. }
  8613. control = null;
  8614. } catch (e) {
  8615. var plugin = navigator.plugins["Silverlight Plug-In"];
  8616. if (plugin) {
  8617. actualVer = plugin.description;
  8618. if (actualVer === "1.0.30226.2") {
  8619. actualVer = "2.0.30226.2";
  8620. }
  8621. actualVerArray = actualVer.split(".");
  8622. while (actualVerArray.length > 3) {
  8623. actualVerArray.pop();
  8624. }
  8625. while ( actualVerArray.length < 4) {
  8626. actualVerArray.push(0);
  8627. }
  8628. reqVerArray = version.split(".");
  8629. while (reqVerArray.length > 4) {
  8630. reqVerArray.pop();
  8631. }
  8632. do {
  8633. requiredVersionPart = parseInt(reqVerArray[index], 10);
  8634. actualVersionPart = parseInt(actualVerArray[index], 10);
  8635. index++;
  8636. } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);
  8637. if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) {
  8638. isVersionSupported = true;
  8639. }
  8640. }
  8641. }
  8642. } catch (e2) {
  8643. isVersionSupported = false;
  8644. }
  8645. return isVersionSupported;
  8646. }
  8647. /**
  8648. Constructor for the Silverlight Runtime
  8649. */
  8650. function SilverlightRuntime(options) {
  8651. var I = this, initTimer;
  8652. options = Basic.extend({ xap_url: Env.xap_url }, options);
  8653. Runtime.call(this, options, type, {
  8654. access_binary: Runtime.capTrue,
  8655. access_image_binary: Runtime.capTrue,
  8656. display_media: Runtime.capTest(defined('moxie/image/Image')),
  8657. do_cors: Runtime.capTrue,
  8658. drag_and_drop: false,
  8659. report_upload_progress: Runtime.capTrue,
  8660. resize_image: Runtime.capTrue,
  8661. return_response_headers: function(value) {
  8662. return value && I.mode === 'client';
  8663. },
  8664. return_response_type: function(responseType) {
  8665. if (responseType !== 'json') {
  8666. return true;
  8667. } else {
  8668. return !!window.JSON;
  8669. }
  8670. },
  8671. return_status_code: function(code) {
  8672. return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]);
  8673. },
  8674. select_file: Runtime.capTrue,
  8675. select_multiple: Runtime.capTrue,
  8676. send_binary_string: Runtime.capTrue,
  8677. send_browser_cookies: function(value) {
  8678. return value && I.mode === 'browser';
  8679. },
  8680. send_custom_headers: function(value) {
  8681. return value && I.mode === 'client';
  8682. },
  8683. send_multipart: Runtime.capTrue,
  8684. slice_blob: Runtime.capTrue,
  8685. stream_upload: true,
  8686. summon_file_dialog: false,
  8687. upload_filesize: Runtime.capTrue,
  8688. use_http_method: function(methods) {
  8689. return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']);
  8690. }
  8691. }, {
  8692. // capabilities that require specific mode
  8693. return_response_headers: function(value) {
  8694. return value ? 'client' : 'browser';
  8695. },
  8696. return_status_code: function(code) {
  8697. return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser'];
  8698. },
  8699. send_browser_cookies: function(value) {
  8700. return value ? 'browser' : 'client';
  8701. },
  8702. send_custom_headers: function(value) {
  8703. return value ? 'client' : 'browser';
  8704. },
  8705. use_http_method: function(methods) {
  8706. return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser'];
  8707. }
  8708. });
  8709. // minimal requirement
  8710. if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') {
  8711. if (MXI_DEBUG && Env.debug.runtime) {
  8712. Env.log("\tSilverlight is not installed or minimal version (2.0.31005.0) requirement not met (not likely).");
  8713. }
  8714. this.mode = false;
  8715. }
  8716. Basic.extend(this, {
  8717. getShim: function() {
  8718. return Dom.get(this.uid).content.Moxie;
  8719. },
  8720. shimExec: function(component, action) {
  8721. var args = [].slice.call(arguments, 2);
  8722. return I.getShim().exec(this.uid, component, action, args);
  8723. },
  8724. init : function() {
  8725. var container;
  8726. container = this.getShimContainer();
  8727. container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' +
  8728. '<param name="source" value="' + options.xap_url + '"/>' +
  8729. '<param name="background" value="Transparent"/>' +
  8730. '<param name="windowless" value="true"/>' +
  8731. '<param name="enablehtmlaccess" value="true"/>' +
  8732. '<param name="initParams" value="uid=' + this.uid + ',target=' + Runtime.getGlobalEventTarget() + '"/>' +
  8733. '</object>';
  8734. // Init is dispatched by the shim
  8735. initTimer = setTimeout(function() {
  8736. if (I && !I.initialized) { // runtime might be already destroyed by this moment
  8737. I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
  8738. if (MXI_DEBUG && Env.debug.runtime) {
  8739. Env.log("\Silverlight failed to initialize within a specified period of time (5-10s).");
  8740. }
  8741. }
  8742. }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac)
  8743. },
  8744. destroy: (function(destroy) { // extend default destroy method
  8745. return function() {
  8746. destroy.call(I);
  8747. clearTimeout(initTimer); // initialization check might be still onwait
  8748. options = initTimer = destroy = I = null;
  8749. };
  8750. }(this.destroy))
  8751. }, extensions);
  8752. }
  8753. Runtime.addConstructor(type, SilverlightRuntime);
  8754. return extensions;
  8755. });
  8756. // Included from: src/javascript/runtime/silverlight/file/Blob.js
  8757. /**
  8758. * Blob.js
  8759. *
  8760. * Copyright 2013, Moxiecode Systems AB
  8761. * Released under GPL License.
  8762. *
  8763. * License: http://www.plupload.com/license
  8764. * Contributing: http://www.plupload.com/contributing
  8765. */
  8766. /**
  8767. @class moxie/runtime/silverlight/file/Blob
  8768. @private
  8769. */
  8770. define("moxie/runtime/silverlight/file/Blob", [
  8771. "moxie/runtime/silverlight/Runtime",
  8772. "moxie/core/utils/Basic",
  8773. "moxie/runtime/flash/file/Blob"
  8774. ], function(extensions, Basic, Blob) {
  8775. return (extensions.Blob = Basic.extend({}, Blob));
  8776. });
  8777. // Included from: src/javascript/runtime/silverlight/file/FileInput.js
  8778. /**
  8779. * FileInput.js
  8780. *
  8781. * Copyright 2013, Moxiecode Systems AB
  8782. * Released under GPL License.
  8783. *
  8784. * License: http://www.plupload.com/license
  8785. * Contributing: http://www.plupload.com/contributing
  8786. */
  8787. /**
  8788. @class moxie/runtime/silverlight/file/FileInput
  8789. @private
  8790. */
  8791. define("moxie/runtime/silverlight/file/FileInput", [
  8792. "moxie/runtime/silverlight/Runtime",
  8793. "moxie/file/File",
  8794. "moxie/core/utils/Dom",
  8795. "moxie/core/utils/Basic"
  8796. ], function(extensions, File, Dom, Basic) {
  8797. function toFilters(accept) {
  8798. var filter = '';
  8799. for (var i = 0; i < accept.length; i++) {
  8800. filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.');
  8801. }
  8802. return filter;
  8803. }
  8804. var FileInput = {
  8805. init: function(options) {
  8806. var comp = this, I = this.getRuntime();
  8807. var browseButton = Dom.get(options.browse_button);
  8808. if (browseButton) {
  8809. browseButton.setAttribute('tabindex', -1);
  8810. browseButton = null;
  8811. }
  8812. this.bind("Change", function() {
  8813. var files = I.shimExec.call(comp, 'FileInput', 'getFiles');
  8814. comp.files = [];
  8815. Basic.each(files, function(file) {
  8816. comp.files.push(new File(I.uid, file));
  8817. });
  8818. }, 999);
  8819. I.shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.multiple);
  8820. this.trigger('ready');
  8821. },
  8822. setOption: function(name, value) {
  8823. if (name == 'accept') {
  8824. value = toFilters(value);
  8825. }
  8826. this.getRuntime().shimExec.call(this, 'FileInput', 'setOption', name, value);
  8827. }
  8828. };
  8829. return (extensions.FileInput = FileInput);
  8830. });
  8831. // Included from: src/javascript/runtime/silverlight/file/FileDrop.js
  8832. /**
  8833. * FileDrop.js
  8834. *
  8835. * Copyright 2013, Moxiecode Systems AB
  8836. * Released under GPL License.
  8837. *
  8838. * License: http://www.plupload.com/license
  8839. * Contributing: http://www.plupload.com/contributing
  8840. */
  8841. /**
  8842. @class moxie/runtime/silverlight/file/FileDrop
  8843. @private
  8844. */
  8845. define("moxie/runtime/silverlight/file/FileDrop", [
  8846. "moxie/runtime/silverlight/Runtime",
  8847. "moxie/core/utils/Dom",
  8848. "moxie/core/utils/Events"
  8849. ], function(extensions, Dom, Events) {
  8850. // not exactly useful, since works only in safari (...crickets...)
  8851. var FileDrop = {
  8852. init: function() {
  8853. var comp = this, self = comp.getRuntime(), dropZone;
  8854. dropZone = self.getShimContainer();
  8855. Events.addEvent(dropZone, 'dragover', function(e) {
  8856. e.preventDefault();
  8857. e.stopPropagation();
  8858. e.dataTransfer.dropEffect = 'copy';
  8859. }, comp.uid);
  8860. Events.addEvent(dropZone, 'dragenter', function(e) {
  8861. e.preventDefault();
  8862. var flag = Dom.get(self.uid).dragEnter(e);
  8863. // If handled, then stop propagation of event in DOM
  8864. if (flag) {
  8865. e.stopPropagation();
  8866. }
  8867. }, comp.uid);
  8868. Events.addEvent(dropZone, 'drop', function(e) {
  8869. e.preventDefault();
  8870. var flag = Dom.get(self.uid).dragDrop(e);
  8871. // If handled, then stop propagation of event in DOM
  8872. if (flag) {
  8873. e.stopPropagation();
  8874. }
  8875. }, comp.uid);
  8876. return self.shimExec.call(this, 'FileDrop', 'init');
  8877. }
  8878. };
  8879. return (extensions.FileDrop = FileDrop);
  8880. });
  8881. // Included from: src/javascript/runtime/silverlight/file/FileReader.js
  8882. /**
  8883. * FileReader.js
  8884. *
  8885. * Copyright 2013, Moxiecode Systems AB
  8886. * Released under GPL License.
  8887. *
  8888. * License: http://www.plupload.com/license
  8889. * Contributing: http://www.plupload.com/contributing
  8890. */
  8891. /**
  8892. @class moxie/runtime/silverlight/file/FileReader
  8893. @private
  8894. */
  8895. define("moxie/runtime/silverlight/file/FileReader", [
  8896. "moxie/runtime/silverlight/Runtime",
  8897. "moxie/core/utils/Basic",
  8898. "moxie/runtime/flash/file/FileReader"
  8899. ], function(extensions, Basic, FileReader) {
  8900. return (extensions.FileReader = Basic.extend({}, FileReader));
  8901. });
  8902. // Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js
  8903. /**
  8904. * FileReaderSync.js
  8905. *
  8906. * Copyright 2013, Moxiecode Systems AB
  8907. * Released under GPL License.
  8908. *
  8909. * License: http://www.plupload.com/license
  8910. * Contributing: http://www.plupload.com/contributing
  8911. */
  8912. /**
  8913. @class moxie/runtime/silverlight/file/FileReaderSync
  8914. @private
  8915. */
  8916. define("moxie/runtime/silverlight/file/FileReaderSync", [
  8917. "moxie/runtime/silverlight/Runtime",
  8918. "moxie/core/utils/Basic",
  8919. "moxie/runtime/flash/file/FileReaderSync"
  8920. ], function(extensions, Basic, FileReaderSync) {
  8921. return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync));
  8922. });
  8923. // Included from: src/javascript/runtime/silverlight/runtime/Transporter.js
  8924. /**
  8925. * Transporter.js
  8926. *
  8927. * Copyright 2013, Moxiecode Systems AB
  8928. * Released under GPL License.
  8929. *
  8930. * License: http://www.plupload.com/license
  8931. * Contributing: http://www.plupload.com/contributing
  8932. */
  8933. /**
  8934. @class moxie/runtime/silverlight/runtime/Transporter
  8935. @private
  8936. */
  8937. define("moxie/runtime/silverlight/runtime/Transporter", [
  8938. "moxie/runtime/silverlight/Runtime",
  8939. "moxie/core/utils/Basic",
  8940. "moxie/runtime/flash/runtime/Transporter"
  8941. ], function(extensions, Basic, Transporter) {
  8942. return (extensions.Transporter = Basic.extend({}, Transporter));
  8943. });
  8944. // Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js
  8945. /**
  8946. * XMLHttpRequest.js
  8947. *
  8948. * Copyright 2013, Moxiecode Systems AB
  8949. * Released under GPL License.
  8950. *
  8951. * License: http://www.plupload.com/license
  8952. * Contributing: http://www.plupload.com/contributing
  8953. */
  8954. /**
  8955. @class moxie/runtime/silverlight/xhr/XMLHttpRequest
  8956. @private
  8957. */
  8958. define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [
  8959. "moxie/runtime/silverlight/Runtime",
  8960. "moxie/core/utils/Basic",
  8961. "moxie/runtime/flash/xhr/XMLHttpRequest",
  8962. "moxie/runtime/silverlight/file/FileReaderSync",
  8963. "moxie/runtime/silverlight/runtime/Transporter"
  8964. ], function(extensions, Basic, XMLHttpRequest, FileReaderSyncSilverlight, TransporterSilverlight) {
  8965. return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest));
  8966. });
  8967. // Included from: src/javascript/runtime/silverlight/image/Image.js
  8968. /**
  8969. * Image.js
  8970. *
  8971. * Copyright 2013, Moxiecode Systems AB
  8972. * Released under GPL License.
  8973. *
  8974. * License: http://www.plupload.com/license
  8975. * Contributing: http://www.plupload.com/contributing
  8976. */
  8977. /**
  8978. @class moxie/runtime/silverlight/image/Image
  8979. @private
  8980. */
  8981. define("moxie/runtime/silverlight/image/Image", [
  8982. "moxie/runtime/silverlight/Runtime",
  8983. "moxie/core/utils/Basic",
  8984. "moxie/file/Blob",
  8985. "moxie/runtime/flash/image/Image"
  8986. ], function(extensions, Basic, Blob, Image) {
  8987. return (extensions.Image = Basic.extend({}, Image, {
  8988. getInfo: function() {
  8989. var self = this.getRuntime()
  8990. , grps = ['tiff', 'exif', 'gps', 'thumb']
  8991. , info = { meta: {} }
  8992. , rawInfo = self.shimExec.call(this, 'Image', 'getInfo')
  8993. ;
  8994. if (rawInfo.meta) {
  8995. Basic.each(grps, function(grp) {
  8996. var meta = rawInfo.meta[grp]
  8997. , tag
  8998. , i
  8999. , length
  9000. , value
  9001. ;
  9002. if (meta && meta.keys) {
  9003. info.meta[grp] = {};
  9004. for (i = 0, length = meta.keys.length; i < length; i++) {
  9005. tag = meta.keys[i];
  9006. value = meta[tag];
  9007. if (value) {
  9008. // convert numbers
  9009. if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero)
  9010. value = parseInt(value, 10);
  9011. } else if (/^\d*\.\d+$/.test(value)) { // double
  9012. value = parseFloat(value);
  9013. }
  9014. info.meta[grp][tag] = value;
  9015. }
  9016. }
  9017. }
  9018. });
  9019. // save thumb data as blob
  9020. if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) {
  9021. info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data);
  9022. }
  9023. }
  9024. info.width = parseInt(rawInfo.width, 10);
  9025. info.height = parseInt(rawInfo.height, 10);
  9026. info.size = parseInt(rawInfo.size, 10);
  9027. info.type = rawInfo.type;
  9028. info.name = rawInfo.name;
  9029. return info;
  9030. },
  9031. resize: function(rect, ratio, opts) {
  9032. this.getRuntime().shimExec.call(this, 'Image', 'resize', rect.x, rect.y, rect.width, rect.height, ratio, opts.preserveHeaders, opts.resample);
  9033. }
  9034. }));
  9035. });
  9036. // Included from: src/javascript/runtime/html4/Runtime.js
  9037. /**
  9038. * Runtime.js
  9039. *
  9040. * Copyright 2013, Moxiecode Systems AB
  9041. * Released under GPL License.
  9042. *
  9043. * License: http://www.plupload.com/license
  9044. * Contributing: http://www.plupload.com/contributing
  9045. */
  9046. /*global File:true */
  9047. /**
  9048. Defines constructor for HTML4 runtime.
  9049. @class moxie/runtime/html4/Runtime
  9050. @private
  9051. */
  9052. define("moxie/runtime/html4/Runtime", [
  9053. "moxie/core/utils/Basic",
  9054. "moxie/core/Exceptions",
  9055. "moxie/runtime/Runtime",
  9056. "moxie/core/utils/Env"
  9057. ], function(Basic, x, Runtime, Env) {
  9058. var type = 'html4', extensions = {};
  9059. function Html4Runtime(options) {
  9060. var I = this
  9061. , Test = Runtime.capTest
  9062. , True = Runtime.capTrue
  9063. ;
  9064. Runtime.call(this, options, type, {
  9065. access_binary: Test(window.FileReader || window.File && File.getAsDataURL),
  9066. access_image_binary: false,
  9067. display_media: Test(
  9068. (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) &&
  9069. defined('moxie/image/Image')
  9070. ),
  9071. do_cors: false,
  9072. drag_and_drop: false,
  9073. filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
  9074. return !(
  9075. (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) ||
  9076. (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) ||
  9077. (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) ||
  9078. (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<'))
  9079. );
  9080. }()),
  9081. resize_image: function() {
  9082. return extensions.Image && I.can('access_binary') && Env.can('create_canvas');
  9083. },
  9084. report_upload_progress: false,
  9085. return_response_headers: false,
  9086. return_response_type: function(responseType) {
  9087. if (responseType === 'json' && !!window.JSON) {
  9088. return true;
  9089. }
  9090. return !!~Basic.inArray(responseType, ['text', 'document', '']);
  9091. },
  9092. return_status_code: function(code) {
  9093. return !Basic.arrayDiff(code, [200, 404]);
  9094. },
  9095. select_file: function() {
  9096. return Env.can('use_fileinput');
  9097. },
  9098. select_multiple: false,
  9099. send_binary_string: false,
  9100. send_custom_headers: false,
  9101. send_multipart: true,
  9102. slice_blob: false,
  9103. stream_upload: function() {
  9104. return I.can('select_file');
  9105. },
  9106. summon_file_dialog: function() { // yeah... some dirty sniffing here...
  9107. return I.can('select_file') && !(
  9108. (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) ||
  9109. (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) ||
  9110. (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<'))
  9111. );
  9112. },
  9113. upload_filesize: True,
  9114. use_http_method: function(methods) {
  9115. return !Basic.arrayDiff(methods, ['GET', 'POST']);
  9116. }
  9117. });
  9118. Basic.extend(this, {
  9119. init : function() {
  9120. this.trigger("Init");
  9121. },
  9122. destroy: (function(destroy) { // extend default destroy method
  9123. return function() {
  9124. destroy.call(I);
  9125. destroy = I = null;
  9126. };
  9127. }(this.destroy))
  9128. });
  9129. Basic.extend(this.getShim(), extensions);
  9130. }
  9131. Runtime.addConstructor(type, Html4Runtime);
  9132. return extensions;
  9133. });
  9134. // Included from: src/javascript/runtime/html4/file/FileInput.js
  9135. /**
  9136. * FileInput.js
  9137. *
  9138. * Copyright 2013, Moxiecode Systems AB
  9139. * Released under GPL License.
  9140. *
  9141. * License: http://www.plupload.com/license
  9142. * Contributing: http://www.plupload.com/contributing
  9143. */
  9144. /**
  9145. @class moxie/runtime/html4/file/FileInput
  9146. @private
  9147. */
  9148. define("moxie/runtime/html4/file/FileInput", [
  9149. "moxie/runtime/html4/Runtime",
  9150. "moxie/file/File",
  9151. "moxie/core/utils/Basic",
  9152. "moxie/core/utils/Dom",
  9153. "moxie/core/utils/Events",
  9154. "moxie/core/utils/Mime",
  9155. "moxie/core/utils/Env"
  9156. ], function(extensions, File, Basic, Dom, Events, Mime, Env) {
  9157. function FileInput() {
  9158. var _uid, _mimes = [], _options, _browseBtnZIndex; // save original z-index;
  9159. function addInput() {
  9160. var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid;
  9161. uid = Basic.guid('uid_');
  9162. shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE
  9163. if (_uid) { // move previous form out of the view
  9164. currForm = Dom.get(_uid + '_form');
  9165. if (currForm) {
  9166. Basic.extend(currForm.style, { top: '100%' });
  9167. // it shouldn't be possible to tab into the hidden element
  9168. currForm.firstChild.setAttribute('tabindex', -1);
  9169. }
  9170. }
  9171. // build form in DOM, since innerHTML version not able to submit file for some reason
  9172. form = document.createElement('form');
  9173. form.setAttribute('id', uid + '_form');
  9174. form.setAttribute('method', 'post');
  9175. form.setAttribute('enctype', 'multipart/form-data');
  9176. form.setAttribute('encoding', 'multipart/form-data');
  9177. Basic.extend(form.style, {
  9178. overflow: 'hidden',
  9179. position: 'absolute',
  9180. top: 0,
  9181. left: 0,
  9182. width: '100%',
  9183. height: '100%'
  9184. });
  9185. input = document.createElement('input');
  9186. input.setAttribute('id', uid);
  9187. input.setAttribute('type', 'file');
  9188. input.setAttribute('accept', _mimes.join(','));
  9189. if (I.can('summon_file_dialog')) {
  9190. input.setAttribute('tabindex', -1);
  9191. }
  9192. Basic.extend(input.style, {
  9193. fontSize: '999px',
  9194. opacity: 0
  9195. });
  9196. form.appendChild(input);
  9197. shimContainer.appendChild(form);
  9198. // prepare file input to be placed underneath the browse_button element
  9199. Basic.extend(input.style, {
  9200. position: 'absolute',
  9201. top: 0,
  9202. left: 0,
  9203. width: '100%',
  9204. height: '100%'
  9205. });
  9206. if (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) {
  9207. Basic.extend(input.style, {
  9208. filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)"
  9209. });
  9210. }
  9211. input.onchange = function() { // there should be only one handler for this
  9212. var file;
  9213. if (!this.value) {
  9214. return;
  9215. }
  9216. if (this.files) { // check if browser is fresh enough
  9217. file = this.files[0];
  9218. } else {
  9219. file = {
  9220. name: this.value
  9221. };
  9222. }
  9223. file = new File(I.uid, file);
  9224. // clear event handler
  9225. this.onchange = function() {};
  9226. addInput.call(comp);
  9227. comp.files = [file];
  9228. // substitute all ids with file uids (consider file.uid read-only - we cannot do it the other way around)
  9229. input.setAttribute('id', file.uid);
  9230. form.setAttribute('id', file.uid + '_form');
  9231. comp.trigger('change');
  9232. input = form = null;
  9233. };
  9234. // route click event to the input
  9235. if (I.can('summon_file_dialog')) {
  9236. browseButton = Dom.get(_options.browse_button);
  9237. Events.removeEvent(browseButton, 'click', comp.uid);
  9238. Events.addEvent(browseButton, 'click', function(e) {
  9239. if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
  9240. input.click();
  9241. }
  9242. e.preventDefault();
  9243. }, comp.uid);
  9244. }
  9245. _uid = uid;
  9246. shimContainer = currForm = browseButton = null;
  9247. }
  9248. Basic.extend(this, {
  9249. init: function(options) {
  9250. var comp = this, I = comp.getRuntime(), shimContainer;
  9251. // figure out accept string
  9252. _options = options;
  9253. _mimes = Mime.extList2mimes(options.accept, I.can('filter_by_extension'));
  9254. shimContainer = I.getShimContainer();
  9255. (function() {
  9256. var browseButton, zIndex, top;
  9257. browseButton = Dom.get(options.browse_button);
  9258. _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto';
  9259. // Route click event to the input[type=file] element for browsers that support such behavior
  9260. if (I.can('summon_file_dialog')) {
  9261. if (Dom.getStyle(browseButton, 'position') === 'static') {
  9262. browseButton.style.position = 'relative';
  9263. }
  9264. comp.bind('Refresh', function() {
  9265. zIndex = parseInt(_browseBtnZIndex, 10) || 1;
  9266. Dom.get(_options.browse_button).style.zIndex = zIndex;
  9267. this.getRuntime().getShimContainer().style.zIndex = zIndex - 1;
  9268. });
  9269. } else {
  9270. // it shouldn't be possible to tab into the hidden element
  9271. browseButton.setAttribute('tabindex', -1);
  9272. }
  9273. /* Since we have to place input[type=file] on top of the browse_button for some browsers,
  9274. browse_button loses interactivity, so we restore it here */
  9275. top = I.can('summon_file_dialog') ? browseButton : shimContainer;
  9276. Events.addEvent(top, 'mouseover', function() {
  9277. comp.trigger('mouseenter');
  9278. }, comp.uid);
  9279. Events.addEvent(top, 'mouseout', function() {
  9280. comp.trigger('mouseleave');
  9281. }, comp.uid);
  9282. Events.addEvent(top, 'mousedown', function() {
  9283. comp.trigger('mousedown');
  9284. }, comp.uid);
  9285. Events.addEvent(Dom.get(options.container), 'mouseup', function() {
  9286. comp.trigger('mouseup');
  9287. }, comp.uid);
  9288. browseButton = null;
  9289. }());
  9290. addInput.call(this);
  9291. shimContainer = null;
  9292. // trigger ready event asynchronously
  9293. comp.trigger({
  9294. type: 'ready',
  9295. async: true
  9296. });
  9297. },
  9298. setOption: function(name, value) {
  9299. var I = this.getRuntime();
  9300. var input;
  9301. if (name == 'accept') {
  9302. _mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension'));
  9303. }
  9304. // update current input
  9305. input = Dom.get(_uid)
  9306. if (input) {
  9307. input.setAttribute('accept', _mimes.join(','));
  9308. }
  9309. },
  9310. disable: function(state) {
  9311. var input;
  9312. if ((input = Dom.get(_uid))) {
  9313. input.disabled = !!state;
  9314. }
  9315. },
  9316. destroy: function() {
  9317. var I = this.getRuntime()
  9318. , shim = I.getShim()
  9319. , shimContainer = I.getShimContainer()
  9320. , container = _options && Dom.get(_options.container)
  9321. , browseButton = _options && Dom.get(_options.browse_button)
  9322. ;
  9323. if (container) {
  9324. Events.removeAllEvents(container, this.uid);
  9325. }
  9326. if (browseButton) {
  9327. Events.removeAllEvents(browseButton, this.uid);
  9328. browseButton.style.zIndex = _browseBtnZIndex; // reset to original value
  9329. }
  9330. if (shimContainer) {
  9331. Events.removeAllEvents(shimContainer, this.uid);
  9332. shimContainer.innerHTML = '';
  9333. }
  9334. shim.removeInstance(this.uid);
  9335. _uid = _mimes = _options = shimContainer = container = browseButton = shim = null;
  9336. }
  9337. });
  9338. }
  9339. return (extensions.FileInput = FileInput);
  9340. });
  9341. // Included from: src/javascript/runtime/html4/file/FileReader.js
  9342. /**
  9343. * FileReader.js
  9344. *
  9345. * Copyright 2013, Moxiecode Systems AB
  9346. * Released under GPL License.
  9347. *
  9348. * License: http://www.plupload.com/license
  9349. * Contributing: http://www.plupload.com/contributing
  9350. */
  9351. /**
  9352. @class moxie/runtime/html4/file/FileReader
  9353. @private
  9354. */
  9355. define("moxie/runtime/html4/file/FileReader", [
  9356. "moxie/runtime/html4/Runtime",
  9357. "moxie/runtime/html5/file/FileReader"
  9358. ], function(extensions, FileReader) {
  9359. return (extensions.FileReader = FileReader);
  9360. });
  9361. // Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js
  9362. /**
  9363. * XMLHttpRequest.js
  9364. *
  9365. * Copyright 2013, Moxiecode Systems AB
  9366. * Released under GPL License.
  9367. *
  9368. * License: http://www.plupload.com/license
  9369. * Contributing: http://www.plupload.com/contributing
  9370. */
  9371. /**
  9372. @class moxie/runtime/html4/xhr/XMLHttpRequest
  9373. @private
  9374. */
  9375. define("moxie/runtime/html4/xhr/XMLHttpRequest", [
  9376. "moxie/runtime/html4/Runtime",
  9377. "moxie/core/utils/Basic",
  9378. "moxie/core/utils/Dom",
  9379. "moxie/core/utils/Url",
  9380. "moxie/core/Exceptions",
  9381. "moxie/core/utils/Events",
  9382. "moxie/file/Blob",
  9383. "moxie/xhr/FormData"
  9384. ], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) {
  9385. function XMLHttpRequest() {
  9386. var _status, _response, _iframe;
  9387. function cleanup(cb) {
  9388. var target = this, uid, form, inputs, i, hasFile = false;
  9389. if (!_iframe) {
  9390. return;
  9391. }
  9392. uid = _iframe.id.replace(/_iframe$/, '');
  9393. form = Dom.get(uid + '_form');
  9394. if (form) {
  9395. inputs = form.getElementsByTagName('input');
  9396. i = inputs.length;
  9397. while (i--) {
  9398. switch (inputs[i].getAttribute('type')) {
  9399. case 'hidden':
  9400. inputs[i].parentNode.removeChild(inputs[i]);
  9401. break;
  9402. case 'file':
  9403. hasFile = true; // flag the case for later
  9404. break;
  9405. }
  9406. }
  9407. inputs = [];
  9408. if (!hasFile) { // we need to keep the form for sake of possible retries
  9409. form.parentNode.removeChild(form);
  9410. }
  9411. form = null;
  9412. }
  9413. // without timeout, request is marked as canceled (in console)
  9414. setTimeout(function() {
  9415. Events.removeEvent(_iframe, 'load', target.uid);
  9416. if (_iframe.parentNode) { // #382
  9417. _iframe.parentNode.removeChild(_iframe);
  9418. }
  9419. // check if shim container has any other children, if - not, remove it as well
  9420. var shimContainer = target.getRuntime().getShimContainer();
  9421. if (!shimContainer.children.length) {
  9422. shimContainer.parentNode.removeChild(shimContainer);
  9423. }
  9424. shimContainer = _iframe = null;
  9425. cb();
  9426. }, 1);
  9427. }
  9428. Basic.extend(this, {
  9429. send: function(meta, data) {
  9430. var target = this, I = target.getRuntime(), uid, form, input, blob;
  9431. _status = _response = null;
  9432. function createIframe() {
  9433. var container = I.getShimContainer() || document.body
  9434. , temp = document.createElement('div')
  9435. ;
  9436. // IE 6 won't be able to set the name using setAttribute or iframe.name
  9437. temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:&quot;&quot;" style="display:none"></iframe>';
  9438. _iframe = temp.firstChild;
  9439. container.appendChild(_iframe);
  9440. /* _iframe.onreadystatechange = function() {
  9441. console.info(_iframe.readyState);
  9442. };*/
  9443. Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8
  9444. var el;
  9445. try {
  9446. el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document;
  9447. // try to detect some standard error pages
  9448. if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error
  9449. _status = el.title.replace(/^(\d+).*$/, '$1');
  9450. } else {
  9451. _status = 200;
  9452. // get result
  9453. _response = Basic.trim(el.body.innerHTML);
  9454. // we need to fire these at least once
  9455. target.trigger({
  9456. type: 'progress',
  9457. loaded: _response.length,
  9458. total: _response.length
  9459. });
  9460. if (blob) { // if we were uploading a file
  9461. target.trigger({
  9462. type: 'uploadprogress',
  9463. loaded: blob.size || 1025,
  9464. total: blob.size || 1025
  9465. });
  9466. }
  9467. }
  9468. } catch (ex) {
  9469. if (Url.hasSameOrigin(meta.url)) {
  9470. // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm
  9471. // which obviously results to cross domain error (wtf?)
  9472. _status = 404;
  9473. } else {
  9474. cleanup.call(target, function() {
  9475. target.trigger('error');
  9476. });
  9477. return;
  9478. }
  9479. }
  9480. cleanup.call(target, function() {
  9481. target.trigger('load');
  9482. });
  9483. }, target.uid);
  9484. } // end createIframe
  9485. // prepare data to be sent and convert if required
  9486. if (data instanceof FormData && data.hasBlob()) {
  9487. blob = data.getBlob();
  9488. uid = blob.uid;
  9489. input = Dom.get(uid);
  9490. form = Dom.get(uid + '_form');
  9491. if (!form) {
  9492. throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
  9493. }
  9494. } else {
  9495. uid = Basic.guid('uid_');
  9496. form = document.createElement('form');
  9497. form.setAttribute('id', uid + '_form');
  9498. form.setAttribute('method', meta.method);
  9499. form.setAttribute('enctype', 'multipart/form-data');
  9500. form.setAttribute('encoding', 'multipart/form-data');
  9501. I.getShimContainer().appendChild(form);
  9502. }
  9503. // set upload target
  9504. form.setAttribute('target', uid + '_iframe');
  9505. if (data instanceof FormData) {
  9506. data.each(function(value, name) {
  9507. if (value instanceof Blob) {
  9508. if (input) {
  9509. input.setAttribute('name', name);
  9510. }
  9511. } else {
  9512. var hidden = document.createElement('input');
  9513. Basic.extend(hidden, {
  9514. type : 'hidden',
  9515. name : name,
  9516. value : value
  9517. });
  9518. // make sure that input[type="file"], if it's there, comes last
  9519. if (input) {
  9520. form.insertBefore(hidden, input);
  9521. } else {
  9522. form.appendChild(hidden);
  9523. }
  9524. }
  9525. });
  9526. }
  9527. // set destination url
  9528. form.setAttribute("action", meta.url);
  9529. createIframe();
  9530. form.submit();
  9531. target.trigger('loadstart');
  9532. },
  9533. getStatus: function() {
  9534. return _status;
  9535. },
  9536. getResponse: function(responseType) {
  9537. if ('json' === responseType) {
  9538. // strip off <pre>..</pre> tags that might be enclosing the response
  9539. if (Basic.typeOf(_response) === 'string' && !!window.JSON) {
  9540. try {
  9541. return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));
  9542. } catch (ex) {
  9543. return null;
  9544. }
  9545. }
  9546. } else if ('document' === responseType) {
  9547. }
  9548. return _response;
  9549. },
  9550. abort: function() {
  9551. var target = this;
  9552. if (_iframe && _iframe.contentWindow) {
  9553. if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome
  9554. _iframe.contentWindow.stop();
  9555. } else if (_iframe.contentWindow.document.execCommand) { // IE
  9556. _iframe.contentWindow.document.execCommand('Stop');
  9557. } else {
  9558. _iframe.src = "about:blank";
  9559. }
  9560. }
  9561. cleanup.call(this, function() {
  9562. // target.dispatchEvent('readystatechange');
  9563. target.dispatchEvent('abort');
  9564. });
  9565. },
  9566. destroy: function() {
  9567. this.getRuntime().getShim().removeInstance(this.uid);
  9568. }
  9569. });
  9570. }
  9571. return (extensions.XMLHttpRequest = XMLHttpRequest);
  9572. });
  9573. // Included from: src/javascript/runtime/html4/image/Image.js
  9574. /**
  9575. * Image.js
  9576. *
  9577. * Copyright 2013, Moxiecode Systems AB
  9578. * Released under GPL License.
  9579. *
  9580. * License: http://www.plupload.com/license
  9581. * Contributing: http://www.plupload.com/contributing
  9582. */
  9583. /**
  9584. @class moxie/runtime/html4/image/Image
  9585. @private
  9586. */
  9587. define("moxie/runtime/html4/image/Image", [
  9588. "moxie/runtime/html4/Runtime",
  9589. "moxie/runtime/html5/image/Image"
  9590. ], function(extensions, Image) {
  9591. return (extensions.Image = Image);
  9592. });
  9593. expose(["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Dom","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/core/I18n","moxie/core/utils/Mime","moxie/file/FileInput","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/image/Image","moxie/core/utils/Events","moxie/runtime/html5/image/ResizerCanvas"]);
  9594. })(this);
  9595. }));