moxie.js 264 KB

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