moxie.js 269 KB

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