12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313 |
- /*! FileAPI 2.0.7 - BSD | git://github.com/mailru/FileAPI.git
- * FileAPI — a set of javascript tools for working with files. Multiupload, drag'n'drop and chunked file upload. Images: crop, resize and auto orientation by EXIF.
- */
- /*
- * JavaScript Canvas to Blob 2.0.5
- * https://github.com/blueimp/JavaScript-Canvas-to-Blob
- *
- * Copyright 2012, Sebastian Tschan
- * https://blueimp.net
- *
- * Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
- *
- * Based on stackoverflow user Stoive's code snippet:
- * http://stackoverflow.com/q/4998908
- */
- /*jslint nomen: true, regexp: true */
- /*global window, atob, Blob, ArrayBuffer, Uint8Array */
- (function (window) {
- 'use strict';
- var CanvasPrototype = window.HTMLCanvasElement &&
- window.HTMLCanvasElement.prototype,
- hasBlobConstructor = window.Blob && (function () {
- try {
- return Boolean(new Blob());
- } catch (e) {
- return false;
- }
- }()),
- hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array &&
- (function () {
- try {
- return new Blob([new Uint8Array(100)]).size === 100;
- } catch (e) {
- return false;
- }
- }()),
- BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
- window.MozBlobBuilder || window.MSBlobBuilder,
- dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob &&
- window.ArrayBuffer && window.Uint8Array && function (dataURI) {
- var byteString,
- arrayBuffer,
- intArray,
- i,
- mimeString,
- bb;
- if (dataURI.split(',')[0].indexOf('base64') >= 0) {
- // Convert base64 to raw binary data held in a string:
- byteString = atob(dataURI.split(',')[1]);
- } else {
- // Convert base64/URLEncoded data component to raw binary data:
- byteString = decodeURIComponent(dataURI.split(',')[1]);
- }
- // Write the bytes of the string to an ArrayBuffer:
- arrayBuffer = new ArrayBuffer(byteString.length);
- intArray = new Uint8Array(arrayBuffer);
- for (i = 0; i < byteString.length; i += 1) {
- intArray[i] = byteString.charCodeAt(i);
- }
- // Separate out the mime component:
- mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
- // Write the ArrayBuffer (or ArrayBufferView) to a blob:
- if (hasBlobConstructor) {
- return new Blob(
- [hasArrayBufferViewSupport ? intArray : arrayBuffer],
- {type: mimeString}
- );
- }
- bb = new BlobBuilder();
- bb.append(arrayBuffer);
- return bb.getBlob(mimeString);
- };
- if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) {
- if (CanvasPrototype.mozGetAsFile) {
- CanvasPrototype.toBlob = function (callback, type, quality) {
- if (quality && CanvasPrototype.toDataURL && dataURLtoBlob) {
- callback(dataURLtoBlob(this.toDataURL(type, quality)));
- } else {
- callback(this.mozGetAsFile('blob', type));
- }
- };
- } else if (CanvasPrototype.toDataURL && dataURLtoBlob) {
- CanvasPrototype.toBlob = function (callback, type, quality) {
- callback(dataURLtoBlob(this.toDataURL(type, quality)));
- };
- }
- }
- window.dataURLtoBlob = dataURLtoBlob;
- })(window);
- /*jslint evil: true */
- /*global window, URL, webkitURL, ActiveXObject */
- (function (window, undef){
- 'use strict';
- var
- gid = 1,
- noop = function (){},
- document = window.document,
- doctype = document.doctype || {},
- userAgent = window.navigator.userAgent,
- // https://github.com/blueimp/JavaScript-Load-Image/blob/master/load-image.js#L48
- apiURL = (window.createObjectURL && window) || (window.URL && URL.revokeObjectURL && URL) || (window.webkitURL && webkitURL),
- Blob = window.Blob,
- File = window.File,
- FileReader = window.FileReader,
- FormData = window.FormData,
- XMLHttpRequest = window.XMLHttpRequest,
- jQuery = window.jQuery,
- html5 = !!(File && (FileReader && (window.Uint8Array || FormData || XMLHttpRequest.prototype.sendAsBinary)))
- && !(/safari\//i.test(userAgent) && !/chrome\//i.test(userAgent) && /windows/i.test(userAgent)), // BugFix: https://github.com/mailru/FileAPI/issues/25
- cors = html5 && ('withCredentials' in (new XMLHttpRequest)),
- chunked = html5 && !!Blob && !!(Blob.prototype.webkitSlice || Blob.prototype.mozSlice || Blob.prototype.slice),
- // https://github.com/blueimp/JavaScript-Canvas-to-Blob
- dataURLtoBlob = window.dataURLtoBlob,
- _rimg = /img/i,
- _rcanvas = /canvas/i,
- _rimgcanvas = /img|canvas/i,
- _rinput = /input/i,
- _rdata = /^data:[^,]+,/,
- _toString = {}.toString,
- Math = window.Math,
- _SIZE_CONST = function (pow){
- pow = new window.Number(Math.pow(1024, pow));
- pow.from = function (sz){ return Math.round(sz * this); };
- return pow;
- },
- _elEvents = {}, // element event listeners
- _infoReader = [], // list of file info processors
- _readerEvents = 'abort progress error load loadend',
- _xhrPropsExport = 'status statusText readyState response responseXML responseText responseBody'.split(' '),
- currentTarget = 'currentTarget', // for minimize
- preventDefault = 'preventDefault', // and this too
- _isArray = function (ar) {
- return ar && ('length' in ar);
- },
- /**
- * Iterate over a object or array
- */
- _each = function (obj, fn, ctx){
- if( obj ){
- if( _isArray(obj) ){
- for( var i = 0, n = obj.length; i < n; i++ ){
- if( i in obj ){
- fn.call(ctx, obj[i], i, obj);
- }
- }
- }
- else {
- for( var key in obj ){
- if( obj.hasOwnProperty(key) ){
- fn.call(ctx, obj[key], key, obj);
- }
- }
- }
- }
- },
- /**
- * Merge the contents of two or more objects together into the first object
- */
- _extend = function (dst){
- var args = arguments, i = 1, _ext = function (val, key){ dst[key] = val; };
- for( ; i < args.length; i++ ){
- _each(args[i], _ext);
- }
- return dst;
- },
- /**
- * Add event listener
- */
- _on = function (el, type, fn){
- if( el ){
- var uid = api.uid(el);
- if( !_elEvents[uid] ){
- _elEvents[uid] = {};
- }
- var isFileReader = (FileReader && el) && (el instanceof FileReader);
- _each(type.split(/\s+/), function (type){
- if( jQuery && !isFileReader){
- jQuery.event.add(el, type, fn);
- } else {
- if( !_elEvents[uid][type] ){
- _elEvents[uid][type] = [];
- }
- _elEvents[uid][type].push(fn);
- if( el.addEventListener ){ el.addEventListener(type, fn, false); }
- else if( el.attachEvent ){ el.attachEvent('on'+type, fn); }
- else { el['on'+type] = fn; }
- }
- });
- }
- },
- /**
- * Remove event listener
- */
- _off = function (el, type, fn){
- if( el ){
- var uid = api.uid(el), events = _elEvents[uid] || {};
- var isFileReader = (FileReader && el) && (el instanceof FileReader);
- _each(type.split(/\s+/), function (type){
- if( jQuery && !isFileReader){
- jQuery.event.remove(el, type, fn);
- }
- else {
- var fns = events[type] || [], i = fns.length;
- while( i-- ){
- if( fns[i] === fn ){
- fns.splice(i, 1);
- break;
- }
- }
- if( el.addEventListener ){ el.removeEventListener(type, fn, false); }
- else if( el.detachEvent ){ el.detachEvent('on'+type, fn); }
- else { el['on'+type] = null; }
- }
- });
- }
- },
- _one = function(el, type, fn){
- _on(el, type, function _(evt){
- _off(el, type, _);
- fn(evt);
- });
- },
- _fixEvent = function (evt){
- if( !evt.target ){ evt.target = window.event && window.event.srcElement || document; }
- if( evt.target.nodeType === 3 ){ evt.target = evt.target.parentNode; }
- return evt;
- },
- _supportInputAttr = function (attr){
- var input = document.createElement('input');
- input.setAttribute('type', "file");
- return attr in input;
- },
- /**
- * FileAPI (core object)
- */
- api = {
- version: '2.0.7',
- cors: false,
- html5: true,
- media: false,
- formData: true,
- multiPassResize: true,
- debug: false,
- pingUrl: false,
- multiFlash: false,
- flashAbortTimeout: 0,
- withCredentials: true,
- staticPath: './dist/',
- flashUrl: 0, // @default: './FileAPI.flash.swf'
- flashImageUrl: 0, // @default: './FileAPI.flash.image.swf'
- postNameConcat: function (name, idx){
- return name + (idx != null ? '['+ idx +']' : '');
- },
- ext2mime: {
- jpg: 'image/jpeg'
- , tif: 'image/tiff'
- , txt: 'text/plain'
- },
- // Fallback for flash
- accept: {
- 'image/*': 'art bm bmp dwg dxf cbr cbz fif fpx gif ico iefs jfif jpe jpeg jpg jps jut mcf nap nif pbm pcx pgm pict pm png pnm qif qtif ras rast rf rp svf tga tif tiff xbm xbm xpm xwd'
- , 'audio/*': 'm4a flac aac rm mpa wav wma ogg mp3 mp2 m3u mod amf dmf dsm far gdm imf it m15 med okt s3m stm sfx ult uni xm sid ac3 dts cue aif aiff wpl ape mac mpc mpp shn wv nsf spc gym adplug adx dsp adp ymf ast afc hps xs'
- , 'video/*': 'm4v 3gp nsv ts ty strm rm rmvb m3u ifo mov qt divx xvid bivx vob nrg img iso pva wmv asf asx ogm m2v avi bin dat dvr-ms mpg mpeg mp4 mkv avc vp3 svq3 nuv viv dv fli flv wpl'
- },
- uploadRetry : 0,
- networkDownRetryTimeout : 5000, // milliseconds, don't flood when network is down
- chunkSize : 0,
- chunkUploadRetry : 0,
- chunkNetworkDownRetryTimeout : 2000, // milliseconds, don't flood when network is down
- KB: _SIZE_CONST(1),
- MB: _SIZE_CONST(2),
- GB: _SIZE_CONST(3),
- TB: _SIZE_CONST(4),
- EMPTY_PNG: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=',
- expando: 'fileapi' + (new Date).getTime(),
- uid: function (obj){
- return obj
- ? (obj[api.expando] = obj[api.expando] || api.uid())
- : (++gid, api.expando + gid)
- ;
- },
- log: function (){
- // ngf fix for IE8 #1071
- if( api.debug && api._supportConsoleLog ){
- if( api._supportConsoleLogApply ){
- console.log.apply(console, arguments);
- }
- else {
- console.log([].join.call(arguments, ' '));
- }
- }
- },
- /**
- * Create new image
- *
- * @param {String} [src]
- * @param {Function} [fn] 1. error -- boolean, 2. img -- Image element
- * @returns {HTMLElement}
- */
- newImage: function (src, fn){
- var img = document.createElement('img');
- if( fn ){
- api.event.one(img, 'error load', function (evt){
- fn(evt.type == 'error', img);
- img = null;
- });
- }
- img.src = src;
- return img;
- },
- /**
- * Get XHR
- * @returns {XMLHttpRequest}
- */
- getXHR: function (){
- var xhr;
- if( XMLHttpRequest ){
- xhr = new XMLHttpRequest;
- }
- else if( window.ActiveXObject ){
- try {
- xhr = new ActiveXObject('MSXML2.XMLHttp.3.0');
- } catch (e) {
- xhr = new ActiveXObject('Microsoft.XMLHTTP');
- }
- }
- return xhr;
- },
- isArray: _isArray,
- support: {
- dnd: cors && ('ondrop' in document.createElement('div')),
- cors: cors,
- html5: html5,
- chunked: chunked,
- dataURI: true,
- accept: _supportInputAttr('accept'),
- multiple: _supportInputAttr('multiple')
- },
- event: {
- on: _on
- , off: _off
- , one: _one
- , fix: _fixEvent
- },
- throttle: function(fn, delay) {
- var id, args;
- return function _throttle(){
- args = arguments;
- if( !id ){
- fn.apply(window, args);
- id = setTimeout(function (){
- id = 0;
- fn.apply(window, args);
- }, delay);
- }
- };
- },
- F: function (){},
- parseJSON: function (str){
- var json;
- if( window.JSON && JSON.parse ){
- json = JSON.parse(str);
- }
- else {
- json = (new Function('return ('+str.replace(/([\r\n])/g, '\\$1')+');'))();
- }
- return json;
- },
- trim: function (str){
- str = String(str);
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
- },
- /**
- * Simple Defer
- * @return {Object}
- */
- defer: function (){
- var
- list = []
- , result
- , error
- , defer = {
- resolve: function (err, res){
- defer.resolve = noop;
- error = err || false;
- result = res;
- while( res = list.shift() ){
- res(error, result);
- }
- },
- then: function (fn){
- if( error !== undef ){
- fn(error, result);
- } else {
- list.push(fn);
- }
- }
- };
- return defer;
- },
- queue: function (fn){
- var
- _idx = 0
- , _length = 0
- , _fail = false
- , _end = false
- , queue = {
- inc: function (){
- _length++;
- },
- next: function (){
- _idx++;
- setTimeout(queue.check, 0);
- },
- check: function (){
- (_idx >= _length) && !_fail && queue.end();
- },
- isFail: function (){
- return _fail;
- },
- fail: function (){
- !_fail && fn(_fail = true);
- },
- end: function (){
- if( !_end ){
- _end = true;
- fn();
- }
- }
- }
- ;
- return queue;
- },
- /**
- * For each object
- *
- * @param {Object|Array} obj
- * @param {Function} fn
- * @param {*} [ctx]
- */
- each: _each,
- /**
- * Async for
- * @param {Array} array
- * @param {Function} callback
- */
- afor: function (array, callback){
- var i = 0, n = array.length;
- if( _isArray(array) && n-- ){
- (function _next(){
- callback(n != i && _next, array[i], i++);
- })();
- }
- else {
- callback(false);
- }
- },
- /**
- * Merge the contents of two or more objects together into the first object
- *
- * @param {Object} dst
- * @return {Object}
- */
- extend: _extend,
- /**
- * Is file?
- * @param {File} file
- * @return {Boolean}
- */
- isFile: function (file){
- return _toString.call(file) === '[object File]';
- },
- /**
- * Is blob?
- * @param {Blob} blob
- * @returns {Boolean}
- */
- isBlob: function (blob) {
- return this.isFile(blob) || (_toString.call(blob) === '[object Blob]');
- },
- /**
- * Is canvas element
- *
- * @param {HTMLElement} el
- * @return {Boolean}
- */
- isCanvas: function (el){
- return el && _rcanvas.test(el.nodeName);
- },
- getFilesFilter: function (filter){
- filter = typeof filter == 'string' ? filter : (filter.getAttribute && filter.getAttribute('accept') || '');
- return filter ? new RegExp('('+ filter.replace(/\./g, '\\.').replace(/,/g, '|') +')$', 'i') : /./;
- },
- /**
- * Read as DataURL
- *
- * @param {File|Element} file
- * @param {Function} fn
- */
- readAsDataURL: function (file, fn){
- if( api.isCanvas(file) ){
- _emit(file, fn, 'load', api.toDataURL(file));
- }
- else {
- _readAs(file, fn, 'DataURL');
- }
- },
- /**
- * Read as Binary string
- *
- * @param {File} file
- * @param {Function} fn
- */
- readAsBinaryString: function (file, fn){
- if( _hasSupportReadAs('BinaryString') ){
- _readAs(file, fn, 'BinaryString');
- } else {
- // Hello IE10!
- _readAs(file, function (evt){
- if( evt.type == 'load' ){
- try {
- // dataURL -> binaryString
- evt.result = api.toBinaryString(evt.result);
- } catch (e){
- evt.type = 'error';
- evt.message = e.toString();
- }
- }
- fn(evt);
- }, 'DataURL');
- }
- },
- /**
- * Read as ArrayBuffer
- *
- * @param {File} file
- * @param {Function} fn
- */
- readAsArrayBuffer: function(file, fn){
- _readAs(file, fn, 'ArrayBuffer');
- },
- /**
- * Read as text
- *
- * @param {File} file
- * @param {String} encoding
- * @param {Function} [fn]
- */
- readAsText: function(file, encoding, fn){
- if( !fn ){
- fn = encoding;
- encoding = 'utf-8';
- }
- _readAs(file, fn, 'Text', encoding);
- },
- /**
- * Convert image or canvas to DataURL
- *
- * @param {Element} el Image or Canvas element
- * @param {String} [type] mime-type
- * @return {String}
- */
- toDataURL: function (el, type){
- if( typeof el == 'string' ){
- return el;
- }
- else if( el.toDataURL ){
- return el.toDataURL(type || 'image/png');
- }
- },
- /**
- * Canvert string, image or canvas to binary string
- *
- * @param {String|Element} val
- * @return {String}
- */
- toBinaryString: function (val){
- return window.atob(api.toDataURL(val).replace(_rdata, ''));
- },
- /**
- * Read file or DataURL as ImageElement
- *
- * @param {File|String} file
- * @param {Function} fn
- * @param {Boolean} [progress]
- */
- readAsImage: function (file, fn, progress){
- if( api.isFile(file) ){
- if( apiURL ){
- /** @namespace apiURL.createObjectURL */
- var data = apiURL.createObjectURL(file);
- if( data === undef ){
- _emit(file, fn, 'error');
- }
- else {
- api.readAsImage(data, fn, progress);
- }
- }
- else {
- api.readAsDataURL(file, function (evt){
- if( evt.type == 'load' ){
- api.readAsImage(evt.result, fn, progress);
- }
- else if( progress || evt.type == 'error' ){
- _emit(file, fn, evt, null, { loaded: evt.loaded, total: evt.total });
- }
- });
- }
- }
- else if( api.isCanvas(file) ){
- _emit(file, fn, 'load', file);
- }
- else if( _rimg.test(file.nodeName) ){
- if( file.complete ){
- _emit(file, fn, 'load', file);
- }
- else {
- var events = 'error abort load';
- _one(file, events, function _fn(evt){
- if( evt.type == 'load' && apiURL ){
- /** @namespace apiURL.revokeObjectURL */
- apiURL.revokeObjectURL(file.src);
- }
- _off(file, events, _fn);
- _emit(file, fn, evt, file);
- });
- }
- }
- else if( file.iframe ){
- _emit(file, fn, { type: 'error' });
- }
- else {
- // Created image
- var img = api.newImage(file.dataURL || file);
- api.readAsImage(img, fn, progress);
- }
- },
- /**
- * Make file by name
- *
- * @param {String} name
- * @return {Array}
- */
- checkFileObj: function (name){
- var file = {}, accept = api.accept;
- if( typeof name == 'object' ){
- file = name;
- }
- else {
- file.name = (name + '').split(/\\|\//g).pop();
- }
- if( file.type == null ){
- file.type = file.name.split('.').pop();
- }
- _each(accept, function (ext, type){
- ext = new RegExp(ext.replace(/\s/g, '|'), 'i');
- if( ext.test(file.type) || api.ext2mime[file.type] ){
- file.type = api.ext2mime[file.type] || (type.split('/')[0] +'/'+ file.type);
- }
- });
- return file;
- },
- /**
- * Get drop files
- *
- * @param {Event} evt
- * @param {Function} callback
- */
- getDropFiles: function (evt, callback){
- var
- files = []
- , dataTransfer = _getDataTransfer(evt)
- , entrySupport = _isArray(dataTransfer.items) && dataTransfer.items[0] && _getAsEntry(dataTransfer.items[0])
- , queue = api.queue(function (){ callback(files); })
- ;
- _each((entrySupport ? dataTransfer.items : dataTransfer.files) || [], function (item){
- queue.inc();
- try {
- if( entrySupport ){
- _readEntryAsFiles(item, function (err, entryFiles){
- if( err ){
- api.log('[err] getDropFiles:', err);
- } else {
- files.push.apply(files, entryFiles);
- }
- queue.next();
- });
- }
- else {
- _isRegularFile(item, function (yes){
- yes && files.push(item);
- queue.next();
- });
- }
- }
- catch( err ){
- queue.next();
- api.log('[err] getDropFiles: ', err);
- }
- });
- queue.check();
- },
- /**
- * Get file list
- *
- * @param {HTMLInputElement|Event} input
- * @param {String|Function} [filter]
- * @param {Function} [callback]
- * @return {Array|Null}
- */
- getFiles: function (input, filter, callback){
- var files = [];
- if( callback ){
- api.filterFiles(api.getFiles(input), filter, callback);
- return null;
- }
- if( input.jquery ){
- // jQuery object
- input.each(function (){
- files = files.concat(api.getFiles(this));
- });
- input = files;
- files = [];
- }
- if( typeof filter == 'string' ){
- filter = api.getFilesFilter(filter);
- }
- if( input.originalEvent ){
- // jQuery event
- input = _fixEvent(input.originalEvent);
- }
- else if( input.srcElement ){
- // IE Event
- input = _fixEvent(input);
- }
- if( input.dataTransfer ){
- // Drag'n'Drop
- input = input.dataTransfer;
- }
- else if( input.target ){
- // Event
- input = input.target;
- }
- if( input.files ){
- // Input[type="file"]
- files = input.files;
- if( !html5 ){
- // Partial support for file api
- files[0].blob = input;
- files[0].iframe = true;
- }
- }
- else if( !html5 && isInputFile(input) ){
- if( api.trim(input.value) ){
- files = [api.checkFileObj(input.value)];
- files[0].blob = input;
- files[0].iframe = true;
- }
- }
- else if( _isArray(input) ){
- files = input;
- }
- return api.filter(files, function (file){ return !filter || filter.test(file.name); });
- },
- /**
- * Get total file size
- * @param {Array} files
- * @return {Number}
- */
- getTotalSize: function (files){
- var size = 0, i = files && files.length;
- while( i-- ){
- size += files[i].size;
- }
- return size;
- },
- /**
- * Get image information
- *
- * @param {File} file
- * @param {Function} fn
- */
- getInfo: function (file, fn){
- var info = {}, readers = _infoReader.concat();
- if( api.isFile(file) ){
- (function _next(){
- var reader = readers.shift();
- if( reader ){
- if( reader.test(file.type) ){
- reader(file, function (err, res){
- if( err ){
- fn(err);
- }
- else {
- _extend(info, res);
- _next();
- }
- });
- }
- else {
- _next();
- }
- }
- else {
- fn(false, info);
- }
- })();
- }
- else {
- fn('not_support_info', info);
- }
- },
- /**
- * Add information reader
- *
- * @param {RegExp} mime
- * @param {Function} fn
- */
- addInfoReader: function (mime, fn){
- fn.test = function (type){ return mime.test(type); };
- _infoReader.push(fn);
- },
- /**
- * Filter of array
- *
- * @param {Array} input
- * @param {Function} fn
- * @return {Array}
- */
- filter: function (input, fn){
- var result = [], i = 0, n = input.length, val;
- for( ; i < n; i++ ){
- if( i in input ){
- val = input[i];
- if( fn.call(val, val, i, input) ){
- result.push(val);
- }
- }
- }
- return result;
- },
- /**
- * Filter files
- *
- * @param {Array} files
- * @param {Function} eachFn
- * @param {Function} resultFn
- */
- filterFiles: function (files, eachFn, resultFn){
- if( files.length ){
- // HTML5 or Flash
- var queue = files.concat(), file, result = [], deleted = [];
- (function _next(){
- if( queue.length ){
- file = queue.shift();
- api.getInfo(file, function (err, info){
- (eachFn(file, err ? false : info) ? result : deleted).push(file);
- _next();
- });
- }
- else {
- resultFn(result, deleted);
- }
- })();
- }
- else {
- resultFn([], files);
- }
- },
- upload: function (options){
- options = _extend({
- jsonp: 'callback'
- , prepare: api.F
- , beforeupload: api.F
- , upload: api.F
- , fileupload: api.F
- , fileprogress: api.F
- , filecomplete: api.F
- , progress: api.F
- , complete: api.F
- , pause: api.F
- , imageOriginal: true
- , chunkSize: api.chunkSize
- , chunkUploadRetry: api.chunkUploadRetry
- , uploadRetry: api.uploadRetry
- }, options);
- if( options.imageAutoOrientation && !options.imageTransform ){
- options.imageTransform = { rotate: 'auto' };
- }
- var
- proxyXHR = new api.XHR(options)
- , dataArray = this._getFilesDataArray(options.files)
- , _this = this
- , _total = 0
- , _loaded = 0
- , _nextFile
- , _complete = false
- ;
- // calc total size
- _each(dataArray, function (data){
- _total += data.size;
- });
- // Array of files
- proxyXHR.files = [];
- _each(dataArray, function (data){
- proxyXHR.files.push(data.file);
- });
- // Set upload status props
- proxyXHR.total = _total;
- proxyXHR.loaded = 0;
- proxyXHR.filesLeft = dataArray.length;
- // emit "beforeupload" event
- options.beforeupload(proxyXHR, options);
- // Upload by file
- _nextFile = function (){
- var
- data = dataArray.shift()
- , _file = data && data.file
- , _fileLoaded = false
- , _fileOptions = _simpleClone(options)
- ;
- proxyXHR.filesLeft = dataArray.length;
- if( _file && _file.name === api.expando ){
- _file = null;
- api.log('[warn] FileAPI.upload() — called without files');
- }
- if( ( proxyXHR.statusText != 'abort' || proxyXHR.current ) && data ){
- // Mark active job
- _complete = false;
- // Set current upload file
- proxyXHR.currentFile = _file;
- // Prepare file options
- if (_file && options.prepare(_file, _fileOptions) === false) {
- _nextFile.call(_this);
- return;
- }
- _fileOptions.file = _file;
- _this._getFormData(_fileOptions, data, function (form){
- if( !_loaded ){
- // emit "upload" event
- options.upload(proxyXHR, options);
- }
- var xhr = new api.XHR(_extend({}, _fileOptions, {
- upload: _file ? function (){
- // emit "fileupload" event
- options.fileupload(_file, xhr, _fileOptions);
- } : noop,
- progress: _file ? function (evt){
- if( !_fileLoaded ){
- // For ignore the double calls.
- _fileLoaded = (evt.loaded === evt.total);
- // emit "fileprogress" event
- options.fileprogress({
- type: 'progress'
- , total: data.total = evt.total
- , loaded: data.loaded = evt.loaded
- }, _file, xhr, _fileOptions);
- // emit "progress" event
- options.progress({
- type: 'progress'
- , total: _total
- , loaded: proxyXHR.loaded = (_loaded + data.size * (evt.loaded/evt.total))|0
- }, _file, xhr, _fileOptions);
- }
- } : noop,
- complete: function (err){
- _each(_xhrPropsExport, function (name){
- proxyXHR[name] = xhr[name];
- });
- if( _file ){
- data.total = (data.total || data.size);
- data.loaded = data.total;
- if( !err ) {
- // emulate 100% "progress"
- this.progress(data);
- // fixed throttle event
- _fileLoaded = true;
- // bytes loaded
- _loaded += data.size; // data.size != data.total, it's desirable fix this
- proxyXHR.loaded = _loaded;
- }
- // emit "filecomplete" event
- options.filecomplete(err, xhr, _file, _fileOptions);
- }
- // upload next file
- setTimeout(function () {_nextFile.call(_this);}, 0);
- }
- })); // xhr
- // ...
- proxyXHR.abort = function (current){
- if (!current) { dataArray.length = 0; }
- this.current = current;
- xhr.abort();
- };
- // Start upload
- xhr.send(form);
- });
- }
- else {
- var successful = proxyXHR.status == 200 || proxyXHR.status == 201 || proxyXHR.status == 204;
- options.complete(successful ? false : (proxyXHR.statusText || 'error'), proxyXHR, options);
- // Mark done state
- _complete = true;
- }
- };
- // Next tick
- setTimeout(_nextFile, 0);
- // Append more files to the existing request
- // first - add them to the queue head/tail
- proxyXHR.append = function (files, first) {
- files = api._getFilesDataArray([].concat(files));
- _each(files, function (data) {
- _total += data.size;
- proxyXHR.files.push(data.file);
- if (first) {
- dataArray.unshift(data);
- } else {
- dataArray.push(data);
- }
- });
- proxyXHR.statusText = "";
- if( _complete ){
- _nextFile.call(_this);
- }
- };
- // Removes file from queue by file reference and returns it
- proxyXHR.remove = function (file) {
- var i = dataArray.length, _file;
- while( i-- ){
- if( dataArray[i].file == file ){
- _file = dataArray.splice(i, 1);
- _total -= _file.size;
- }
- }
- return _file;
- };
- return proxyXHR;
- },
- _getFilesDataArray: function (data){
- var files = [], oFiles = {};
- if( isInputFile(data) ){
- var tmp = api.getFiles(data);
- oFiles[data.name || 'file'] = data.getAttribute('multiple') !== null ? tmp : tmp[0];
- }
- else if( _isArray(data) && isInputFile(data[0]) ){
- _each(data, function (input){
- oFiles[input.name || 'file'] = api.getFiles(input);
- });
- }
- else {
- oFiles = data;
- }
- _each(oFiles, function add(file, name){
- if( _isArray(file) ){
- _each(file, function (file){
- add(file, name);
- });
- }
- else if( file && (file.name || file.image) ){
- files.push({
- name: name
- , file: file
- , size: file.size
- , total: file.size
- , loaded: 0
- });
- }
- });
- if( !files.length ){
- // Create fake `file` object
- files.push({ file: { name: api.expando } });
- }
- return files;
- },
- _getFormData: function (options, data, fn){
- var
- file = data.file
- , name = data.name
- , filename = file.name
- , filetype = file.type
- , trans = api.support.transform && options.imageTransform
- , Form = new api.Form
- , queue = api.queue(function (){ fn(Form); })
- , isOrignTrans = trans && _isOriginTransform(trans)
- , postNameConcat = api.postNameConcat
- ;
- // Append data
- _each(options.data, function add(val, name){
- if( typeof val == 'object' ){
- _each(val, function (v, i){
- add(v, postNameConcat(name, i));
- });
- }
- else {
- Form.append(name, val);
- }
- });
- (function _addFile(file/**Object*/){
- if( file.image ){ // This is a FileAPI.Image
- queue.inc();
- file.toData(function (err, image){
- // @todo: error
- filename = filename || (new Date).getTime()+'.png';
- _addFile(image);
- queue.next();
- });
- }
- else if( api.Image && trans && (/^image/.test(file.type) || _rimgcanvas.test(file.nodeName)) ){
- queue.inc();
- if( isOrignTrans ){
- // Convert to array for transform function
- trans = [trans];
- }
- api.Image.transform(file, trans, options.imageAutoOrientation, function (err, images){
- if( isOrignTrans && !err ){
- if( !dataURLtoBlob && !api.flashEngine ){
- // Canvas.toBlob or Flash not supported, use multipart
- Form.multipart = true;
- }
- Form.append(name, images[0], filename, trans[0].type || filetype);
- }
- else {
- var addOrigin = 0;
- if( !err ){
- _each(images, function (image, idx){
- if( !dataURLtoBlob && !api.flashEngine ){
- Form.multipart = true;
- }
- if( !trans[idx].postName ){
- addOrigin = 1;
- }
- Form.append(trans[idx].postName || postNameConcat(name, idx), image, filename, trans[idx].type || filetype);
- });
- }
- if( err || options.imageOriginal ){
- Form.append(postNameConcat(name, (addOrigin ? 'original' : null)), file, filename, filetype);
- }
- }
- queue.next();
- });
- }
- else if( filename !== api.expando ){
- Form.append(name, file, filename);
- }
- })(file);
- queue.check();
- },
- reset: function (inp, notRemove){
- var parent, clone;
- if( jQuery ){
- clone = jQuery(inp).clone(true).insertBefore(inp).val('')[0];
- if( !notRemove ){
- jQuery(inp).remove();
- }
- } else {
- parent = inp.parentNode;
- clone = parent.insertBefore(inp.cloneNode(true), inp);
- clone.value = '';
- if( !notRemove ){
- parent.removeChild(inp);
- }
- _each(_elEvents[api.uid(inp)], function (fns, type){
- _each(fns, function (fn){
- _off(inp, type, fn);
- _on(clone, type, fn);
- });
- });
- }
- return clone;
- },
- /**
- * Load remote file
- *
- * @param {String} url
- * @param {Function} fn
- * @return {XMLHttpRequest}
- */
- load: function (url, fn){
- var xhr = api.getXHR();
- if( xhr ){
- xhr.open('GET', url, true);
- if( xhr.overrideMimeType ){
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- }
- _on(xhr, 'progress', function (/**Event*/evt){
- /** @namespace evt.lengthComputable */
- if( evt.lengthComputable ){
- fn({ type: evt.type, loaded: evt.loaded, total: evt.total }, xhr);
- }
- });
- xhr.onreadystatechange = function(){
- if( xhr.readyState == 4 ){
- xhr.onreadystatechange = null;
- if( xhr.status == 200 ){
- url = url.split('/');
- /** @namespace xhr.responseBody */
- var file = {
- name: url[url.length-1]
- , size: xhr.getResponseHeader('Content-Length')
- , type: xhr.getResponseHeader('Content-Type')
- };
- file.dataURL = 'data:'+file.type+';base64,' + api.encode64(xhr.responseBody || xhr.responseText);
- fn({ type: 'load', result: file }, xhr);
- }
- else {
- fn({ type: 'error' }, xhr);
- }
- }
- };
- xhr.send(null);
- } else {
- fn({ type: 'error' });
- }
- return xhr;
- },
- encode64: function (str){
- var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', outStr = '', i = 0;
- if( typeof str !== 'string' ){
- str = String(str);
- }
- while( i < str.length ){
- //all three "& 0xff" added below are there to fix a known bug
- //with bytes returned by xhr.responseText
- var
- byte1 = str.charCodeAt(i++) & 0xff
- , byte2 = str.charCodeAt(i++) & 0xff
- , byte3 = str.charCodeAt(i++) & 0xff
- , enc1 = byte1 >> 2
- , enc2 = ((byte1 & 3) << 4) | (byte2 >> 4)
- , enc3, enc4
- ;
- if( isNaN(byte2) ){
- enc3 = enc4 = 64;
- } else {
- enc3 = ((byte2 & 15) << 2) | (byte3 >> 6);
- enc4 = isNaN(byte3) ? 64 : byte3 & 63;
- }
- outStr += b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4);
- }
- return outStr;
- }
- } // api
- ;
- function _emit(target, fn, name, res, ext){
- var evt = {
- type: name.type || name
- , target: target
- , result: res
- };
- _extend(evt, ext);
- fn(evt);
- }
- function _hasSupportReadAs(as){
- return FileReader && !!FileReader.prototype['readAs'+as];
- }
- function _readAs(file, fn, as, encoding){
- if( api.isBlob(file) && _hasSupportReadAs(as) ){
- var Reader = new FileReader;
- // Add event listener
- _on(Reader, _readerEvents, function _fn(evt){
- var type = evt.type;
- if( type == 'progress' ){
- _emit(file, fn, evt, evt.target.result, { loaded: evt.loaded, total: evt.total });
- }
- else if( type == 'loadend' ){
- _off(Reader, _readerEvents, _fn);
- Reader = null;
- }
- else {
- _emit(file, fn, evt, evt.target.result);
- }
- });
- try {
- // ReadAs ...
- if( encoding ){
- Reader['readAs'+as](file, encoding);
- }
- else {
- Reader['readAs'+as](file);
- }
- }
- catch (err){
- _emit(file, fn, 'error', undef, { error: err.toString() });
- }
- }
- else {
- _emit(file, fn, 'error', undef, { error: 'FileReader_not_support_'+as });
- }
- }
- function _isRegularFile(file, callback){
- // http://stackoverflow.com/questions/8856628/detecting-folders-directories-in-javascript-filelist-objects
- if( !file.type && (file.size % 4096) === 0 && (file.size <= 102400) ){
- if( FileReader ){
- try {
- var Reader = new FileReader();
- _one(Reader, _readerEvents, function (evt){
- var isFile = evt.type != 'error';
- callback(isFile);
- if( isFile ){
- Reader.abort();
- }
- });
- Reader.readAsDataURL(file);
- } catch( err ){
- callback(false);
- }
- }
- else {
- callback(null);
- }
- }
- else {
- callback(true);
- }
- }
- function _getAsEntry(item){
- var entry;
- if( item.getAsEntry ){ entry = item.getAsEntry(); }
- else if( item.webkitGetAsEntry ){ entry = item.webkitGetAsEntry(); }
- return entry;
- }
- function _readEntryAsFiles(entry, callback){
- if( !entry ){
- // error
- callback('invalid entry');
- }
- else if( entry.isFile ){
- // Read as file
- entry.file(function(file){
- // success
- file.fullPath = entry.fullPath;
- callback(false, [file]);
- }, function (err){
- // error
- callback('FileError.code: '+err.code);
- });
- }
- else if( entry.isDirectory ){
- var reader = entry.createReader(), result = [];
- reader.readEntries(function(entries){
- // success
- api.afor(entries, function (next, entry){
- _readEntryAsFiles(entry, function (err, files){
- if( err ){
- api.log(err);
- }
- else {
- result = result.concat(files);
- }
- if( next ){
- next();
- }
- else {
- callback(false, result);
- }
- });
- });
- }, function (err){
- // error
- callback('directory_reader: ' + err);
- });
- }
- else {
- _readEntryAsFiles(_getAsEntry(entry), callback);
- }
- }
- function _simpleClone(obj){
- var copy = {};
- _each(obj, function (val, key){
- if( val && (typeof val === 'object') && (val.nodeType === void 0) ){
- val = _extend({}, val);
- }
- copy[key] = val;
- });
- return copy;
- }
- function isInputFile(el){
- return _rinput.test(el && el.tagName);
- }
- function _getDataTransfer(evt){
- return (evt.originalEvent || evt || '').dataTransfer || {};
- }
- function _isOriginTransform(trans){
- var key;
- for( key in trans ){
- if( trans.hasOwnProperty(key) ){
- if( !(trans[key] instanceof Object || key === 'overlay' || key === 'filter') ){
- return true;
- }
- }
- }
- return false;
- }
- // Add default image info reader
- api.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){
- if( !file.__dimensions ){
- var defer = file.__dimensions = api.defer();
- api.readAsImage(file, function (evt){
- var img = evt.target;
- defer.resolve(evt.type == 'load' ? false : 'error', {
- width: img.width
- , height: img.height
- });
- img.src = api.EMPTY_PNG;
- img = null;
- });
- }
- file.__dimensions.then(callback);
- });
- /**
- * Drag'n'Drop special event
- *
- * @param {HTMLElement} el
- * @param {Function} onHover
- * @param {Function} onDrop
- */
- api.event.dnd = function (el, onHover, onDrop){
- var _id, _type;
- if( !onDrop ){
- onDrop = onHover;
- onHover = api.F;
- }
- if( FileReader ){
- // Hover
- _on(el, 'dragenter dragleave dragover', onHover.ff = onHover.ff || function (evt){
- var
- types = _getDataTransfer(evt).types
- , i = types && types.length
- , debounceTrigger = false
- ;
- while( i-- ){
- if( ~types[i].indexOf('File') ){
- evt[preventDefault]();
- if( _type !== evt.type ){
- _type = evt.type; // Store current type of event
- if( _type != 'dragleave' ){
- onHover.call(evt[currentTarget], true, evt);
- }
- debounceTrigger = true;
- }
- break; // exit from "while"
- }
- }
- if( debounceTrigger ){
- clearTimeout(_id);
- _id = setTimeout(function (){
- onHover.call(evt[currentTarget], _type != 'dragleave', evt);
- }, 50);
- }
- });
- // Drop
- _on(el, 'drop', onDrop.ff = onDrop.ff || function (evt){
- evt[preventDefault]();
- _type = 0;
- onHover.call(evt[currentTarget], false, evt);
- api.getDropFiles(evt, function (files){
- onDrop.call(evt[currentTarget], files, evt);
- });
- });
- }
- else {
- api.log("Drag'n'Drop -- not supported");
- }
- };
- /**
- * Remove drag'n'drop
- * @param {HTMLElement} el
- * @param {Function} onHover
- * @param {Function} onDrop
- */
- api.event.dnd.off = function (el, onHover, onDrop){
- _off(el, 'dragenter dragleave dragover', onHover.ff);
- _off(el, 'drop', onDrop.ff);
- };
- // Support jQuery
- if( jQuery && !jQuery.fn.dnd ){
- jQuery.fn.dnd = function (onHover, onDrop){
- return this.each(function (){
- api.event.dnd(this, onHover, onDrop);
- });
- };
- jQuery.fn.offdnd = function (onHover, onDrop){
- return this.each(function (){
- api.event.dnd.off(this, onHover, onDrop);
- });
- };
- }
- // @export
- window.FileAPI = _extend(api, window.FileAPI);
- // Debug info
- api.log('FileAPI: ' + api.version);
- api.log('protocol: ' + window.location.protocol);
- api.log('doctype: [' + doctype.name + '] ' + doctype.publicId + ' ' + doctype.systemId);
- // @detect 'x-ua-compatible'
- _each(document.getElementsByTagName('meta'), function (meta){
- if( /x-ua-compatible/i.test(meta.getAttribute('http-equiv')) ){
- api.log('meta.http-equiv: ' + meta.getAttribute('content'));
- }
- });
- // configuration
- try {
- api._supportConsoleLog = !!console.log;
- api._supportConsoleLogApply = !!console.log.apply;
- } catch (err) {}
- if( !api.flashUrl ){ api.flashUrl = api.staticPath + 'FileAPI.flash.swf'; }
- if( !api.flashImageUrl ){ api.flashImageUrl = api.staticPath + 'FileAPI.flash.image.swf'; }
- if( !api.flashWebcamUrl ){ api.flashWebcamUrl = api.staticPath + 'FileAPI.flash.camera.swf'; }
- })(window, void 0);
- /*global window, FileAPI, document */
- (function (api, document, undef) {
- 'use strict';
- var
- min = Math.min,
- round = Math.round,
- getCanvas = function () { return document.createElement('canvas'); },
- support = false,
- exifOrientation = {
- 8: 270
- , 3: 180
- , 6: 90
- , 7: 270
- , 4: 180
- , 5: 90
- }
- ;
- try {
- support = getCanvas().toDataURL('image/png').indexOf('data:image/png') > -1;
- }
- catch (e){}
- function Image(file){
- if( file instanceof Image ){
- var img = new Image(file.file);
- api.extend(img.matrix, file.matrix);
- return img;
- }
- else if( !(this instanceof Image) ){
- return new Image(file);
- }
- this.file = file;
- this.size = file.size || 100;
- this.matrix = {
- sx: 0,
- sy: 0,
- sw: 0,
- sh: 0,
- dx: 0,
- dy: 0,
- dw: 0,
- dh: 0,
- resize: 0, // min, max OR preview
- deg: 0,
- quality: 1, // jpeg quality
- filter: 0
- };
- }
- Image.prototype = {
- image: true,
- constructor: Image,
- set: function (attrs){
- api.extend(this.matrix, attrs);
- return this;
- },
- crop: function (x, y, w, h){
- if( w === undef ){
- w = x;
- h = y;
- x = y = 0;
- }
- return this.set({ sx: x, sy: y, sw: w, sh: h || w });
- },
- resize: function (w, h, strategy){
- if( /min|max/.test(h) ){
- strategy = h;
- h = w;
- }
- return this.set({ dw: w, dh: h || w, resize: strategy });
- },
- preview: function (w, h){
- return this.resize(w, h || w, 'preview');
- },
- rotate: function (deg){
- return this.set({ deg: deg });
- },
- filter: function (filter){
- return this.set({ filter: filter });
- },
- overlay: function (images){
- return this.set({ overlay: images });
- },
- clone: function (){
- return new Image(this);
- },
- _load: function (image, fn){
- var self = this;
- if( /img|video/i.test(image.nodeName) ){
- fn.call(self, null, image);
- }
- else {
- api.readAsImage(image, function (evt){
- fn.call(self, evt.type != 'load', evt.result);
- });
- }
- },
- _apply: function (image, fn){
- var
- canvas = getCanvas()
- , m = this.getMatrix(image)
- , ctx = canvas.getContext('2d')
- , width = image.videoWidth || image.width
- , height = image.videoHeight || image.height
- , deg = m.deg
- , dw = m.dw
- , dh = m.dh
- , w = width
- , h = height
- , filter = m.filter
- , copy // canvas copy
- , buffer = image
- , overlay = m.overlay
- , queue = api.queue(function (){ image.src = api.EMPTY_PNG; fn(false, canvas); })
- , renderImageToCanvas = api.renderImageToCanvas
- ;
- // Normalize angle
- deg = deg - Math.floor(deg/360)*360;
- // For `renderImageToCanvas`
- image._type = this.file.type;
- while(m.multipass && min(w/dw, h/dh) > 2 ){
- w = (w/2 + 0.5)|0;
- h = (h/2 + 0.5)|0;
- copy = getCanvas();
- copy.width = w;
- copy.height = h;
- if( buffer !== image ){
- renderImageToCanvas(copy, buffer, 0, 0, buffer.width, buffer.height, 0, 0, w, h);
- buffer = copy;
- }
- else {
- buffer = copy;
- renderImageToCanvas(buffer, image, m.sx, m.sy, m.sw, m.sh, 0, 0, w, h);
- m.sx = m.sy = m.sw = m.sh = 0;
- }
- }
- canvas.width = (deg % 180) ? dh : dw;
- canvas.height = (deg % 180) ? dw : dh;
- canvas.type = m.type;
- canvas.quality = m.quality;
- ctx.rotate(deg * Math.PI / 180);
- renderImageToCanvas(ctx.canvas, buffer
- , m.sx, m.sy
- , m.sw || buffer.width
- , m.sh || buffer.height
- , (deg == 180 || deg == 270 ? -dw : 0)
- , (deg == 90 || deg == 180 ? -dh : 0)
- , dw, dh
- );
- dw = canvas.width;
- dh = canvas.height;
- // Apply overlay
- overlay && api.each([].concat(overlay), function (over){
- queue.inc();
- // preload
- var img = new window.Image, fn = function (){
- var
- x = over.x|0
- , y = over.y|0
- , w = over.w || img.width
- , h = over.h || img.height
- , rel = over.rel
- ;
- // center | right | left
- x = (rel == 1 || rel == 4 || rel == 7) ? (dw - w + x)/2 : (rel == 2 || rel == 5 || rel == 8 ? dw - (w + x) : x);
- // center | bottom | top
- y = (rel == 3 || rel == 4 || rel == 5) ? (dh - h + y)/2 : (rel >= 6 ? dh - (h + y) : y);
- api.event.off(img, 'error load abort', fn);
- try {
- ctx.globalAlpha = over.opacity || 1;
- ctx.drawImage(img, x, y, w, h);
- }
- catch (er){}
- queue.next();
- };
- api.event.on(img, 'error load abort', fn);
- img.src = over.src;
- if( img.complete ){
- fn();
- }
- });
- if( filter ){
- queue.inc();
- Image.applyFilter(canvas, filter, queue.next);
- }
- queue.check();
- },
- getMatrix: function (image){
- var
- m = api.extend({}, this.matrix)
- , sw = m.sw = m.sw || image.videoWidth || image.naturalWidth || image.width
- , sh = m.sh = m.sh || image.videoHeight || image.naturalHeight || image.height
- , dw = m.dw = m.dw || sw
- , dh = m.dh = m.dh || sh
- , sf = sw/sh, df = dw/dh
- , strategy = m.resize
- ;
- if( strategy == 'preview' ){
- if( dw != sw || dh != sh ){
- // Make preview
- var w, h;
- if( df >= sf ){
- w = sw;
- h = w / df;
- } else {
- h = sh;
- w = h * df;
- }
- if( w != sw || h != sh ){
- m.sx = ~~((sw - w)/2);
- m.sy = ~~((sh - h)/2);
- sw = w;
- sh = h;
- }
- }
- }
- else if( strategy ){
- if( !(sw > dw || sh > dh) ){
- dw = sw;
- dh = sh;
- }
- else if( strategy == 'min' ){
- dw = round(sf < df ? min(sw, dw) : dh*sf);
- dh = round(sf < df ? dw/sf : min(sh, dh));
- }
- else {
- dw = round(sf >= df ? min(sw, dw) : dh*sf);
- dh = round(sf >= df ? dw/sf : min(sh, dh));
- }
- }
- m.sw = sw;
- m.sh = sh;
- m.dw = dw;
- m.dh = dh;
- m.multipass = api.multiPassResize;
- return m;
- },
- _trans: function (fn){
- this._load(this.file, function (err, image){
- if( err ){
- fn(err);
- }
- else {
- try {
- this._apply(image, fn);
- } catch (err){
- api.log('[err] FileAPI.Image.fn._apply:', err);
- fn(err);
- }
- }
- });
- },
- get: function (fn){
- if( api.support.transform ){
- var _this = this, matrix = _this.matrix;
- if( matrix.deg == 'auto' ){
- api.getInfo(_this.file, function (err, info){
- // rotate by exif orientation
- matrix.deg = exifOrientation[info && info.exif && info.exif.Orientation] || 0;
- _this._trans(fn);
- });
- }
- else {
- _this._trans(fn);
- }
- }
- else {
- fn('not_support_transform');
- }
- return this;
- },
- toData: function (fn){
- return this.get(fn);
- }
- };
- Image.exifOrientation = exifOrientation;
- Image.transform = function (file, transform, autoOrientation, fn){
- function _transform(err, img){
- // img -- info object
- var
- images = {}
- , queue = api.queue(function (err){
- fn(err, images);
- })
- ;
- if( !err ){
- api.each(transform, function (params, name){
- if( !queue.isFail() ){
- var ImgTrans = new Image(img.nodeType ? img : file), isFn = typeof params == 'function';
- if( isFn ){
- params(img, ImgTrans);
- }
- else if( params.width ){
- ImgTrans[params.preview ? 'preview' : 'resize'](params.width, params.height, params.strategy);
- }
- else {
- if( params.maxWidth && (img.width > params.maxWidth || img.height > params.maxHeight) ){
- ImgTrans.resize(params.maxWidth, params.maxHeight, 'max');
- }
- }
- if( params.crop ){
- var crop = params.crop;
- ImgTrans.crop(crop.x|0, crop.y|0, crop.w || crop.width, crop.h || crop.height);
- }
- if( params.rotate === undef && autoOrientation ){
- params.rotate = 'auto';
- }
- ImgTrans.set({ type: ImgTrans.matrix.type || params.type || file.type || 'image/png' });
- if( !isFn ){
- ImgTrans.set({
- deg: params.rotate
- , overlay: params.overlay
- , filter: params.filter
- , quality: params.quality || 1
- });
- }
- queue.inc();
- ImgTrans.toData(function (err, image){
- if( err ){
- queue.fail();
- }
- else {
- images[name] = image;
- queue.next();
- }
- });
- }
- });
- }
- else {
- queue.fail();
- }
- }
- // @todo: Оло-ло, нужно рефакторить это место
- if( file.width ){
- _transform(false, file);
- } else {
- api.getInfo(file, _transform);
- }
- };
- // @const
- api.each(['TOP', 'CENTER', 'BOTTOM'], function (x, i){
- api.each(['LEFT', 'CENTER', 'RIGHT'], function (y, j){
- Image[x+'_'+y] = i*3 + j;
- Image[y+'_'+x] = i*3 + j;
- });
- });
- /**
- * Trabsform element to canvas
- *
- * @param {Image|HTMLVideoElement} el
- * @returns {Canvas}
- */
- Image.toCanvas = function(el){
- var canvas = document.createElement('canvas');
- canvas.width = el.videoWidth || el.width;
- canvas.height = el.videoHeight || el.height;
- canvas.getContext('2d').drawImage(el, 0, 0);
- return canvas;
- };
- /**
- * Create image from DataURL
- * @param {String} dataURL
- * @param {Object} size
- * @param {Function} callback
- */
- Image.fromDataURL = function (dataURL, size, callback){
- var img = api.newImage(dataURL);
- api.extend(img, size);
- callback(img);
- };
- /**
- * Apply filter (caman.js)
- *
- * @param {Canvas|Image} canvas
- * @param {String|Function} filter
- * @param {Function} doneFn
- */
- Image.applyFilter = function (canvas, filter, doneFn){
- if( typeof filter == 'function' ){
- filter(canvas, doneFn);
- }
- else if( window.Caman ){
- // http://camanjs.com/guides/
- window.Caman(canvas.tagName == 'IMG' ? Image.toCanvas(canvas) : canvas, function (){
- if( typeof filter == 'string' ){
- this[filter]();
- }
- else {
- api.each(filter, function (val, method){
- this[method](val);
- }, this);
- }
- this.render(doneFn);
- });
- }
- };
- /**
- * For load-image-ios.js
- */
- api.renderImageToCanvas = function (canvas, img, sx, sy, sw, sh, dx, dy, dw, dh){
- try {
- return canvas.getContext('2d').drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
- } catch (ex) {
- api.log('renderImageToCanvas failed');
- throw ex;
- }
- };
- // @export
- api.support.canvas = api.support.transform = support;
- api.Image = Image;
- })(FileAPI, document);
- /*
- * JavaScript Load Image iOS scaling fixes 1.0.3
- * https://github.com/blueimp/JavaScript-Load-Image
- *
- * Copyright 2013, Sebastian Tschan
- * https://blueimp.net
- *
- * iOS image scaling fixes based on
- * https://github.com/stomita/ios-imagefile-megapixel
- *
- * Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
- */
- /*jslint nomen: true, bitwise: true */
- /*global FileAPI, window, document */
- (function (factory) {
- 'use strict';
- factory(FileAPI);
- }(function (loadImage) {
- 'use strict';
- // Only apply fixes on the iOS platform:
- if (!window.navigator || !window.navigator.platform ||
- !(/iP(hone|od|ad)/).test(window.navigator.platform)) {
- return;
- }
- var originalRenderMethod = loadImage.renderImageToCanvas;
- // Detects subsampling in JPEG images:
- loadImage.detectSubsampling = function (img) {
- var canvas,
- context;
- if (img.width * img.height > 1024 * 1024) { // only consider mexapixel images
- canvas = document.createElement('canvas');
- canvas.width = canvas.height = 1;
- context = canvas.getContext('2d');
- context.drawImage(img, -img.width + 1, 0);
- // subsampled image becomes half smaller in rendering size.
- // check alpha channel value to confirm image is covering edge pixel or not.
- // if alpha value is 0 image is not covering, hence subsampled.
- return context.getImageData(0, 0, 1, 1).data[3] === 0;
- }
- return false;
- };
- // Detects vertical squash in JPEG images:
- loadImage.detectVerticalSquash = function (img, subsampled) {
- var naturalHeight = img.naturalHeight || img.height,
- canvas = document.createElement('canvas'),
- context = canvas.getContext('2d'),
- data,
- sy,
- ey,
- py,
- alpha;
- if (subsampled) {
- naturalHeight /= 2;
- }
- canvas.width = 1;
- canvas.height = naturalHeight;
- context.drawImage(img, 0, 0);
- data = context.getImageData(0, 0, 1, naturalHeight).data;
- // search image edge pixel position in case it is squashed vertically:
- sy = 0;
- ey = naturalHeight;
- py = naturalHeight;
- while (py > sy) {
- alpha = data[(py - 1) * 4 + 3];
- if (alpha === 0) {
- ey = py;
- } else {
- sy = py;
- }
- py = (ey + sy) >> 1;
- }
- return (py / naturalHeight) || 1;
- };
- // Renders image to canvas while working around iOS image scaling bugs:
- // https://github.com/blueimp/JavaScript-Load-Image/issues/13
- loadImage.renderImageToCanvas = function (
- canvas,
- img,
- sourceX,
- sourceY,
- sourceWidth,
- sourceHeight,
- destX,
- destY,
- destWidth,
- destHeight
- ) {
- if (img._type === 'image/jpeg') {
- var context = canvas.getContext('2d'),
- tmpCanvas = document.createElement('canvas'),
- tileSize = 1024,
- tmpContext = tmpCanvas.getContext('2d'),
- subsampled,
- vertSquashRatio,
- tileX,
- tileY;
- tmpCanvas.width = tileSize;
- tmpCanvas.height = tileSize;
- context.save();
- subsampled = loadImage.detectSubsampling(img);
- if (subsampled) {
- sourceX /= 2;
- sourceY /= 2;
- sourceWidth /= 2;
- sourceHeight /= 2;
- }
- vertSquashRatio = loadImage.detectVerticalSquash(img, subsampled);
- if (subsampled || vertSquashRatio !== 1) {
- sourceY *= vertSquashRatio;
- destWidth = Math.ceil(tileSize * destWidth / sourceWidth);
- destHeight = Math.ceil(
- tileSize * destHeight / sourceHeight / vertSquashRatio
- );
- destY = 0;
- tileY = 0;
- while (tileY < sourceHeight) {
- destX = 0;
- tileX = 0;
- while (tileX < sourceWidth) {
- tmpContext.clearRect(0, 0, tileSize, tileSize);
- tmpContext.drawImage(
- img,
- sourceX,
- sourceY,
- sourceWidth,
- sourceHeight,
- -tileX,
- -tileY,
- sourceWidth,
- sourceHeight
- );
- context.drawImage(
- tmpCanvas,
- 0,
- 0,
- tileSize,
- tileSize,
- destX,
- destY,
- destWidth,
- destHeight
- );
- tileX += tileSize;
- destX += destWidth;
- }
- tileY += tileSize;
- destY += destHeight;
- }
- context.restore();
- return canvas;
- }
- }
- return originalRenderMethod(
- canvas,
- img,
- sourceX,
- sourceY,
- sourceWidth,
- sourceHeight,
- destX,
- destY,
- destWidth,
- destHeight
- );
- };
- }));
- /*global window, FileAPI */
- (function (api, window){
- "use strict";
- var
- document = window.document
- , FormData = window.FormData
- , Form = function (){ this.items = []; }
- , encodeURIComponent = window.encodeURIComponent
- ;
- Form.prototype = {
- append: function (name, blob, file, type){
- this.items.push({
- name: name
- , blob: blob && blob.blob || (blob == void 0 ? '' : blob)
- , file: blob && (file || blob.name)
- , type: blob && (type || blob.type)
- });
- },
- each: function (fn){
- var i = 0, n = this.items.length;
- for( ; i < n; i++ ){
- fn.call(this, this.items[i]);
- }
- },
- toData: function (fn, options){
- // allow chunked transfer if we have only one file to send
- // flag is used below and in XHR._send
- options._chunked = api.support.chunked && options.chunkSize > 0 && api.filter(this.items, function (item){ return item.file; }).length == 1;
- if( !api.support.html5 ){
- api.log('FileAPI.Form.toHtmlData');
- this.toHtmlData(fn);
- }
- else if( !api.formData || this.multipart || !FormData ){
- api.log('FileAPI.Form.toMultipartData');
- this.toMultipartData(fn);
- }
- else if( options._chunked ){
- api.log('FileAPI.Form.toPlainData');
- this.toPlainData(fn);
- }
- else {
- api.log('FileAPI.Form.toFormData');
- this.toFormData(fn);
- }
- },
- _to: function (data, complete, next, arg){
- var queue = api.queue(function (){
- complete(data);
- });
- this.each(function (file){
- next(file, data, queue, arg);
- });
- queue.check();
- },
- toHtmlData: function (fn){
- this._to(document.createDocumentFragment(), fn, function (file, data/**DocumentFragment*/){
- var blob = file.blob, hidden;
- if( file.file ){
- api.reset(blob, true);
- // set new name
- blob.name = file.name;
- blob.disabled = false;
- data.appendChild(blob);
- }
- else {
- hidden = document.createElement('input');
- hidden.name = file.name;
- hidden.type = 'hidden';
- hidden.value = blob;
- data.appendChild(hidden);
- }
- });
- },
- toPlainData: function (fn){
- this._to({}, fn, function (file, data, queue){
- if( file.file ){
- data.type = file.file;
- }
- if( file.blob.toBlob ){
- // canvas
- queue.inc();
- _convertFile(file, function (file, blob){
- data.name = file.name;
- data.file = blob;
- data.size = blob.length;
- data.type = file.type;
- queue.next();
- });
- }
- else if( file.file ){
- // file
- data.name = file.blob.name;
- data.file = file.blob;
- data.size = file.blob.size;
- data.type = file.type;
- }
- else {
- // additional data
- if( !data.params ){
- data.params = [];
- }
- data.params.push(encodeURIComponent(file.name) +"="+ encodeURIComponent(file.blob));
- }
- data.start = -1;
- data.end = data.file && data.file.FileAPIReadPosition || -1;
- data.retry = 0;
- });
- },
- toFormData: function (fn){
- this._to(new FormData, fn, function (file, data, queue){
- if( file.blob && file.blob.toBlob ){
- queue.inc();
- _convertFile(file, function (file, blob){
- data.append(file.name, blob, file.file);
- queue.next();
- });
- }
- else if( file.file ){
- data.append(file.name, file.blob, file.file);
- }
- else {
- data.append(file.name, file.blob);
- }
- if( file.file ){
- data.append('_'+file.name, file.file);
- }
- });
- },
- toMultipartData: function (fn){
- this._to([], fn, function (file, data, queue, boundary){
- queue.inc();
- _convertFile(file, function (file, blob){
- data.push(
- '--_' + boundary + ('\r\nContent-Disposition: form-data; name="'+ file.name +'"'+ (file.file ? '; filename="'+ encodeURIComponent(file.file) +'"' : '')
- + (file.file ? '\r\nContent-Type: '+ (file.type || 'application/octet-stream') : '')
- + '\r\n'
- + '\r\n'+ (file.file ? blob : encodeURIComponent(blob))
- + '\r\n')
- );
- queue.next();
- }, true);
- }, api.expando);
- }
- };
- function _convertFile(file, fn, useBinaryString){
- var blob = file.blob, filename = file.file;
- if( filename ){
- if( !blob.toDataURL ){
- // The Blob is not an image.
- api.readAsBinaryString(blob, function (evt){
- if( evt.type == 'load' ){
- fn(file, evt.result);
- }
- });
- return;
- }
- var
- mime = { 'image/jpeg': '.jpe?g', 'image/png': '.png' }
- , type = mime[file.type] ? file.type : 'image/png'
- , ext = mime[type] || '.png'
- , quality = blob.quality || 1
- ;
- if( !filename.match(new RegExp(ext+'$', 'i')) ){
- // Does not change the current extension, but add a new one.
- filename += ext.replace('?', '');
- }
- file.file = filename;
- file.type = type;
- if( !useBinaryString && blob.toBlob ){
- blob.toBlob(function (blob){
- fn(file, blob);
- }, type, quality);
- }
- else {
- fn(file, api.toBinaryString(blob.toDataURL(type, quality)));
- }
- }
- else {
- fn(file, blob);
- }
- }
- // @export
- api.Form = Form;
- })(FileAPI, window);
- /*global window, FileAPI, Uint8Array */
- (function (window, api){
- "use strict";
- var
- noop = function (){}
- , document = window.document
- , XHR = function (options){
- this.uid = api.uid();
- this.xhr = {
- abort: noop
- , getResponseHeader: noop
- , getAllResponseHeaders: noop
- };
- this.options = options;
- },
- _xhrResponsePostfix = { '': 1, XML: 1, Text: 1, Body: 1 }
- ;
- XHR.prototype = {
- status: 0,
- statusText: '',
- constructor: XHR,
- getResponseHeader: function (name){
- return this.xhr.getResponseHeader(name);
- },
- getAllResponseHeaders: function (){
- return this.xhr.getAllResponseHeaders() || {};
- },
- end: function (status, statusText){
- var _this = this, options = _this.options;
- _this.end =
- _this.abort = noop;
- _this.status = status;
- if( statusText ){
- _this.statusText = statusText;
- }
- api.log('xhr.end:', status, statusText);
- options.complete(status == 200 || status == 201 ? false : _this.statusText || 'unknown', _this);
- if( _this.xhr && _this.xhr.node ){
- setTimeout(function (){
- var node = _this.xhr.node;
- try { node.parentNode.removeChild(node); } catch (e){}
- try { delete window[_this.uid]; } catch (e){}
- window[_this.uid] = _this.xhr.node = null;
- }, 9);
- }
- },
- abort: function (){
- this.end(0, 'abort');
- if( this.xhr ){
- this.xhr.aborted = true;
- this.xhr.abort();
- }
- },
- send: function (FormData){
- var _this = this, options = this.options;
- FormData.toData(function (data){
- // Start uploading
- options.upload(options, _this);
- _this._send.call(_this, options, data);
- }, options);
- },
- _send: function (options, data){
- var _this = this, xhr, uid = _this.uid, onloadFuncName = _this.uid + "Load", url = options.url;
- api.log('XHR._send:', data);
- if( !options.cache ){
- // No cache
- url += (~url.indexOf('?') ? '&' : '?') + api.uid();
- }
- if( data.nodeName ){
- var jsonp = options.jsonp;
- // prepare callback in GET
- url = url.replace(/([a-z]+)=(\?)/i, '$1='+uid);
- // legacy
- options.upload(options, _this);
- var
- onPostMessage = function (evt){
- if( ~url.indexOf(evt.origin) ){
- try {
- var result = api.parseJSON(evt.data);
- if( result.id == uid ){
- complete(result.status, result.statusText, result.response);
- }
- } catch( err ){
- complete(0, err.message);
- }
- }
- },
- // jsonp-callack
- complete = window[uid] = function (status, statusText, response){
- _this.readyState = 4;
- _this.responseText = response;
- _this.end(status, statusText);
- api.event.off(window, 'message', onPostMessage);
- window[uid] = xhr = transport = window[onloadFuncName] = null;
- }
- ;
- _this.xhr.abort = function (){
- try {
- if( transport.stop ){ transport.stop(); }
- else if( transport.contentWindow.stop ){ transport.contentWindow.stop(); }
- else { transport.contentWindow.document.execCommand('Stop'); }
- }
- catch (er) {}
- complete(0, "abort");
- };
- api.event.on(window, 'message', onPostMessage);
- window[onloadFuncName] = function (){
- try {
- var
- win = transport.contentWindow
- , doc = win.document
- , result = win.result || api.parseJSON(doc.body.innerHTML)
- ;
- complete(result.status, result.statusText, result.response);
- } catch (e){
- api.log('[transport.onload]', e);
- }
- };
- xhr = document.createElement('div');
- xhr.innerHTML = '<form target="'+ uid +'" action="'+ url +'" method="POST" enctype="multipart/form-data" style="position: absolute; top: -1000px; overflow: hidden; width: 1px; height: 1px;">'
- + '<iframe name="'+ uid +'" src="javascript:false;" onload="' + onloadFuncName + '()"></iframe>'
- + (jsonp && (options.url.indexOf('=?') < 0) ? '<input value="'+ uid +'" name="'+jsonp+'" type="hidden"/>' : '')
- + '</form>'
- ;
- // get form-data & transport
- var
- form = xhr.getElementsByTagName('form')[0]
- , transport = xhr.getElementsByTagName('iframe')[0]
- ;
- form.appendChild(data);
- api.log(form.parentNode.innerHTML);
- // append to DOM
- document.body.appendChild(xhr);
- // keep a reference to node-transport
- _this.xhr.node = xhr;
- // send
- _this.readyState = 2; // loaded
- form.submit();
- form = null;
- }
- else {
- // Clean url
- url = url.replace(/([a-z]+)=(\?)&?/i, '');
- // html5
- if (this.xhr && this.xhr.aborted) {
- api.log("Error: already aborted");
- return;
- }
- xhr = _this.xhr = api.getXHR();
- if (data.params) {
- url += (url.indexOf('?') < 0 ? "?" : "&") + data.params.join("&");
- }
- xhr.open('POST', url, true);
- if( api.withCredentials ){
- xhr.withCredentials = "true";
- }
- if( !options.headers || !options.headers['X-Requested-With'] ){
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
- }
- api.each(options.headers, function (val, key){
- xhr.setRequestHeader(key, val);
- });
- if ( options._chunked ) {
- // chunked upload
- if( xhr.upload ){
- xhr.upload.addEventListener('progress', api.throttle(function (/**Event*/evt){
- if (!data.retry) {
- // show progress only for correct chunk uploads
- options.progress({
- type: evt.type
- , total: data.size
- , loaded: data.start + evt.loaded
- , totalSize: data.size
- }, _this, options);
- }
- }, 100), false);
- }
- xhr.onreadystatechange = function (){
- var lkb = parseInt(xhr.getResponseHeader('X-Last-Known-Byte'), 10);
- _this.status = xhr.status;
- _this.statusText = xhr.statusText;
- _this.readyState = xhr.readyState;
- if( xhr.readyState == 4 ){
- try {
- for( var k in _xhrResponsePostfix ){
- _this['response'+k] = xhr['response'+k];
- }
- }catch(_){}
- xhr.onreadystatechange = null;
- if (!xhr.status || xhr.status - 201 > 0) {
- api.log("Error: " + xhr.status);
- // some kind of error
- // 0 - connection fail or timeout, if xhr.aborted is true, then it's not recoverable user action
- // up - server error
- if (((!xhr.status && !xhr.aborted) || 500 == xhr.status || 416 == xhr.status) && ++data.retry <= options.chunkUploadRetry) {
- // let's try again the same chunk
- // only applicable for recoverable error codes 500 && 416
- var delay = xhr.status ? 0 : api.chunkNetworkDownRetryTimeout;
- // inform about recoverable problems
- options.pause(data.file, options);
- // smart restart if server reports about the last known byte
- api.log("X-Last-Known-Byte: " + lkb);
- if (lkb) {
- data.end = lkb;
- } else {
- data.end = data.start - 1;
- if (416 == xhr.status) {
- data.end = data.end - options.chunkSize;
- }
- }
- setTimeout(function () {
- _this._send(options, data);
- }, delay);
- } else {
- // no mo retries
- _this.end(xhr.status);
- }
- } else {
- // success
- data.retry = 0;
- if (data.end == data.size - 1) {
- // finished
- _this.end(xhr.status);
- } else {
- // next chunk
- // shift position if server reports about the last known byte
- api.log("X-Last-Known-Byte: " + lkb);
- if (lkb) {
- data.end = lkb;
- }
- data.file.FileAPIReadPosition = data.end;
- setTimeout(function () {
- _this._send(options, data);
- }, 0);
- }
- }
- xhr = null;
- }
- };
- data.start = data.end + 1;
- data.end = Math.max(Math.min(data.start + options.chunkSize, data.size) - 1, data.start);
- // Retrieve a slice of file
- var
- file = data.file
- , slice = (file.slice || file.mozSlice || file.webkitSlice).call(file, data.start, data.end + 1)
- ;
- if( data.size && !slice.size ){
- setTimeout(function (){
- _this.end(-1);
- });
- } else {
- xhr.setRequestHeader("Content-Range", "bytes " + data.start + "-" + data.end + "/" + data.size);
- xhr.setRequestHeader("Content-Disposition", 'attachment; filename=' + encodeURIComponent(data.name));
- xhr.setRequestHeader("Content-Type", data.type || "application/octet-stream");
- xhr.send(slice);
- }
- file = slice = null;
- } else {
- // single piece upload
- if( xhr.upload ){
- // https://github.com/blueimp/jQuery-File-Upload/wiki/Fixing-Safari-hanging-on-very-high-speed-connections-%281Gbps%29
- xhr.upload.addEventListener('progress', api.throttle(function (/**Event*/evt){
- options.progress(evt, _this, options);
- }, 100), false);
- }
- xhr.onreadystatechange = function (){
- _this.status = xhr.status;
- _this.statusText = xhr.statusText;
- _this.readyState = xhr.readyState;
- if( xhr.readyState == 4 ){
- for( var k in _xhrResponsePostfix ){
- _this['response'+k] = xhr['response'+k];
- }
- xhr.onreadystatechange = null;
- if (!xhr.status || xhr.status > 201) {
- api.log("Error: " + xhr.status);
- if (((!xhr.status && !xhr.aborted) || 500 == xhr.status) && (options.retry || 0) < options.uploadRetry) {
- options.retry = (options.retry || 0) + 1;
- var delay = api.networkDownRetryTimeout;
- // inform about recoverable problems
- options.pause(options.file, options);
- setTimeout(function () {
- _this._send(options, data);
- }, delay);
- } else {
- //success
- _this.end(xhr.status);
- }
- } else {
- //success
- _this.end(xhr.status);
- }
- xhr = null;
- }
- };
- if( api.isArray(data) ){
- // multipart
- xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=_'+api.expando);
- var rawData = data.join('') +'--_'+ api.expando +'--';
- /** @namespace xhr.sendAsBinary https://developer.mozilla.org/ru/XMLHttpRequest#Sending_binary_content */
- if( xhr.sendAsBinary ){
- xhr.sendAsBinary(rawData);
- }
- else {
- var bytes = Array.prototype.map.call(rawData, function(c){ return c.charCodeAt(0) & 0xff; });
- xhr.send(new Uint8Array(bytes).buffer);
- }
- } else {
- // FormData
- xhr.send(data);
- }
- }
- }
- }
- };
- // @export
- api.XHR = XHR;
- })(window, FileAPI);
- /**
- * @class FileAPI.Camera
- * @author RubaXa <trash@rubaxa.org>
- * @support Chrome 21+, FF 18+, Opera 12+
- */
- /*global window, FileAPI, jQuery */
- /** @namespace LocalMediaStream -- https://developer.mozilla.org/en-US/docs/WebRTC/MediaStream_API#LocalMediaStream */
- (function (window, api){
- "use strict";
- var
- URL = window.URL || window.webkitURL,
- document = window.document,
- navigator = window.navigator,
- getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia,
- html5 = !!getMedia
- ;
- // Support "media"
- api.support.media = html5;
- var Camera = function (video){
- this.video = video;
- };
- Camera.prototype = {
- isActive: function (){
- return !!this._active;
- },
- /**
- * Start camera streaming
- * @param {Function} callback
- */
- start: function (callback){
- var
- _this = this
- , video = _this.video
- , _successId
- , _failId
- , _complete = function (err){
- _this._active = !err;
- clearTimeout(_failId);
- clearTimeout(_successId);
- // api.event.off(video, 'loadedmetadata', _complete);
- callback && callback(err, _this);
- }
- ;
- getMedia.call(navigator, { video: true }, function (stream/**LocalMediaStream*/){
- // Success
- _this.stream = stream;
- // api.event.on(video, 'loadedmetadata', function (){
- // _complete(null);
- // });
- // Set camera stream
- video.src = URL.createObjectURL(stream);
- // Note: onloadedmetadata doesn't fire in Chrome when using it with getUserMedia.
- // See crbug.com/110938.
- _successId = setInterval(function (){
- if( _detectVideoSignal(video) ){
- _complete(null);
- }
- }, 1000);
- _failId = setTimeout(function (){
- _complete('timeout');
- }, 5000);
- // Go-go-go!
- video.play();
- }, _complete/*error*/);
- },
- /**
- * Stop camera streaming
- */
- stop: function (){
- try {
- this._active = false;
- this.video.pause();
- this.stream.stop();
- } catch( err ){ }
- },
- /**
- * Create screenshot
- * @return {FileAPI.Camera.Shot}
- */
- shot: function (){
- return new Shot(this.video);
- }
- };
- /**
- * Get camera element from container
- *
- * @static
- * @param {HTMLElement} el
- * @return {Camera}
- */
- Camera.get = function (el){
- return new Camera(el.firstChild);
- };
- /**
- * Publish camera element into container
- *
- * @static
- * @param {HTMLElement} el
- * @param {Object} options
- * @param {Function} [callback]
- */
- Camera.publish = function (el, options, callback){
- if( typeof options == 'function' ){
- callback = options;
- options = {};
- }
- // Dimensions of "camera"
- options = api.extend({}, {
- width: '100%'
- , height: '100%'
- , start: true
- }, options);
- if( el.jquery ){
- // Extract first element, from jQuery collection
- el = el[0];
- }
- var doneFn = function (err){
- if( err ){
- callback(err);
- }
- else {
- // Get camera
- var cam = Camera.get(el);
- if( options.start ){
- cam.start(callback);
- }
- else {
- callback(null, cam);
- }
- }
- };
- el.style.width = _px(options.width);
- el.style.height = _px(options.height);
- if( api.html5 && html5 ){
- // Create video element
- var video = document.createElement('video');
- // Set dimensions
- video.style.width = _px(options.width);
- video.style.height = _px(options.height);
- // Clean container
- if( window.jQuery ){
- jQuery(el).empty();
- } else {
- el.innerHTML = '';
- }
- // Add "camera" to container
- el.appendChild(video);
- // end
- doneFn();
- }
- else {
- Camera.fallback(el, options, doneFn);
- }
- };
- Camera.fallback = function (el, options, callback){
- callback('not_support_camera');
- };
- /**
- * @class FileAPI.Camera.Shot
- */
- var Shot = function (video){
- var canvas = video.nodeName ? api.Image.toCanvas(video) : video;
- var shot = api.Image(canvas);
- shot.type = 'image/png';
- shot.width = canvas.width;
- shot.height = canvas.height;
- shot.size = canvas.width * canvas.height * 4;
- return shot;
- };
- /**
- * Add "px" postfix, if value is a number
- *
- * @private
- * @param {*} val
- * @return {String}
- */
- function _px(val){
- return val >= 0 ? val + 'px' : val;
- }
- /**
- * @private
- * @param {HTMLVideoElement} video
- * @return {Boolean}
- */
- function _detectVideoSignal(video){
- var canvas = document.createElement('canvas'), ctx, res = false;
- try {
- ctx = canvas.getContext('2d');
- ctx.drawImage(video, 0, 0, 1, 1);
- res = ctx.getImageData(0, 0, 1, 1).data[4] != 255;
- }
- catch( e ){}
- return res;
- }
- // @export
- Camera.Shot = Shot;
- api.Camera = Camera;
- })(window, FileAPI);
- /**
- * FileAPI fallback to Flash
- *
- * @flash-developer "Vladimir Demidov" <v.demidov@corp.mail.ru>
- */
- /*global window, ActiveXObject, FileAPI */
- (function (window, jQuery, api) {
- "use strict";
- var
- document = window.document
- , location = window.location
- , navigator = window.navigator
- , _each = api.each
- ;
- api.support.flash = (function (){
- var mime = navigator.mimeTypes, has = false;
- if( navigator.plugins && typeof navigator.plugins['Shockwave Flash'] == 'object' ){
- has = navigator.plugins['Shockwave Flash'].description && !(mime && mime['application/x-shockwave-flash'] && !mime['application/x-shockwave-flash'].enabledPlugin);
- }
- else {
- try {
- has = !!(window.ActiveXObject && new ActiveXObject('ShockwaveFlash.ShockwaveFlash'));
- }
- catch(er){
- api.log('Flash -- does not supported.');
- }
- }
- if( has && /^file:/i.test(location) ){
- api.log('[warn] Flash does not work on `file:` protocol.');
- }
- return has;
- })();
- api.support.flash
- && (0
- || !api.html5 || !api.support.html5
- || (api.cors && !api.support.cors)
- || (api.media && !api.support.media)
- )
- && (function (){
- var
- _attr = api.uid()
- , _retry = 0
- , _files = {}
- , _rhttp = /^https?:/i
- , flash = {
- _fn: {},
- /**
- * Publish flash-object
- *
- * @param {HTMLElement} el
- * @param {String} id
- * @param {Object} [opts]
- */
- publish: function (el, id, opts){
- opts = opts || {};
- el.innerHTML = _makeFlashHTML({
- id: id
- , src: _getUrl(api.flashUrl, 'r=' + api.version)
- // , src: _getUrl('http://v.demidov.boom.corp.mail.ru/uploaderfileapi/FlashFileAPI.swf?1')
- , wmode: opts.camera ? '' : 'transparent'
- , flashvars: 'callback=' + (opts.onEvent || 'FileAPI.Flash.onEvent')
- + '&flashId='+ id
- + '&storeKey='+ navigator.userAgent.match(/\d/ig).join('') +'_'+ api.version
- + (flash.isReady || (api.pingUrl ? '&ping='+api.pingUrl : ''))
- + '&timeout='+api.flashAbortTimeout
- + (opts.camera ? '&useCamera=' + _getUrl(api.flashWebcamUrl) : '')
- + '&debug='+(api.debug?"1":"")
- }, opts);
- },
- /**
- * Initialization & preload flash object
- */
- init: function (){
- var child = document.body && document.body.firstChild;
- if( child ){
- do {
- if( child.nodeType == 1 ){
- api.log('FlashAPI.state: awaiting');
- var dummy = document.createElement('div');
- dummy.id = '_' + _attr;
- _css(dummy, {
- top: 1
- , right: 1
- , width: 5
- , height: 5
- , position: 'absolute'
- , zIndex: 1e6+'' // set max zIndex
- });
- child.parentNode.insertBefore(dummy, child);
- flash.publish(dummy, _attr);
- return;
- }
- }
- while( child = child.nextSibling );
- }
- if( _retry < 10 ){
- setTimeout(flash.init, ++_retry*50);
- }
- },
- ready: function (){
- api.log('FlashAPI.state: ready');
- flash.ready = api.F;
- flash.isReady = true;
- flash.patch();
- flash.patchCamera && flash.patchCamera();
- api.event.on(document, 'mouseover', flash.mouseover);
- api.event.on(document, 'click', function (evt){
- if( flash.mouseover(evt) ){
- evt.preventDefault
- ? evt.preventDefault()
- : (evt.returnValue = true)
- ;
- }
- });
- },
- getEl: function (){
- return document.getElementById('_'+_attr);
- },
- getWrapper: function (node){
- do {
- if( /js-fileapi-wrapper/.test(node.className) ){
- return node;
- }
- }
- while( (node = node.parentNode) && (node !== document.body) );
- },
-
- disableMouseover: false,
- mouseover: function (evt){
- if (!flash.disableMouseover) {
- var target = api.event.fix(evt).target;
-
- if( /input/i.test(target.nodeName) && target.type == 'file' && !target.disabled ){
- var
- state = target.getAttribute(_attr)
- , wrapper = flash.getWrapper(target)
- ;
-
- if( api.multiFlash ){
- // check state:
- // i — published
- // i — initialization
- // r — ready
- if( state == 'i' || state == 'r' ){
- // publish fail
- return false;
- }
- else if( state != 'p' ){
- // set "init" state
- target.setAttribute(_attr, 'i');
-
- var dummy = document.createElement('div');
-
- if( !wrapper ){
- api.log('[err] FlashAPI.mouseover: js-fileapi-wrapper not found');
- return;
- }
-
- _css(dummy, {
- top: 0
- , left: 0
- , width: target.offsetWidth
- , height: target.offsetHeight
- , zIndex: 1e6+'' // set max zIndex
- , position: 'absolute'
- });
-
- wrapper.appendChild(dummy);
- flash.publish(dummy, api.uid());
-
- // set "publish" state
- target.setAttribute(_attr, 'p');
- }
-
- return true;
- }
- else if( wrapper ){
- // Use one flash element
- var box = _getDimensions(wrapper);
- _css(flash.getEl(), box);
-
- // Set current input
- flash.curInp = target;
- }
- }
- else if( !/object|embed/i.test(target.nodeName) ){
- _css(flash.getEl(), { top: 1, left: 1, width: 5, height: 5 });
- }
- }
- },
- onEvent: function (evt){
- var type = evt.type;
-
- if( type == 'ready' ){
- try {
- // set "ready" state
- flash.getInput(evt.flashId).setAttribute(_attr, 'r');
- } catch (e){
- }
- flash.ready();
- setTimeout(function (){ flash.mouseenter(evt); }, 50);
- return true;
- }
- else if( type === 'ping' ){
- api.log('(flash -> js).ping:', [evt.status, evt.savedStatus], evt.error);
- }
- else if( type === 'log' ){
- api.log('(flash -> js).log:', evt.target);
- }
- else if( type in flash ){
- setTimeout(function (){
- api.log('FlashAPI.event.'+evt.type+':', evt);
- flash[type](evt);
- }, 1);
- }
- },
- mouseDown: function(evt) {
- flash.disableMouseover = true;
- },
- cancel: function(evt) {
- flash.disableMouseover = false;
- },
- mouseenter: function (evt){
- var node = flash.getInput(evt.flashId);
- if( node ){
- // Set multiple mode
- flash.cmd(evt, 'multiple', node.getAttribute('multiple') != null);
- // Set files filter
- var accept = [], exts = {};
- _each((node.getAttribute('accept') || '').split(/,\s*/), function (mime){
- api.accept[mime] && _each(api.accept[mime].split(' '), function (ext){
- exts[ext] = 1;
- });
- });
- _each(exts, function (i, ext){
- accept.push( ext );
- });
- flash.cmd(evt, 'accept', accept.length ? accept.join(',')+','+accept.join(',').toUpperCase() : '*');
- }
- },
- get: function (id){
- return document[id] || window[id] || document.embeds[id];
- },
- getInput: function (id){
- if( api.multiFlash ){
- try {
- var node = flash.getWrapper(flash.get(id));
- if( node ){
- return node.getElementsByTagName('input')[0];
- }
- } catch (e){
- api.log('[err] Can not find "input" by flashId:', id, e);
- }
- } else {
- return flash.curInp;
- }
- },
- select: function (evt){
- try {
- var
- inp = flash.getInput(evt.flashId)
- , uid = api.uid(inp)
- , files = evt.target.files
- , event
- ;
- _each(files, function (file){
- api.checkFileObj(file);
- });
-
- _files[uid] = files;
-
- if( document.createEvent ){
- event = document.createEvent('Event');
- event.files = files;
- event.initEvent('change', true, true);
- inp.dispatchEvent(event);
- }
- else if( jQuery ){
- jQuery(inp).trigger({ type: 'change', files: files });
- }
- else {
- event = document.createEventObject();
- event.files = files;
- inp.fireEvent('onchange', event);
- }
- } finally {
- flash.disableMouseover = false;
- }
- },
- interval: null,
- cmd: function (id, name, data, last) {
- if (flash.uploadInProgress && flash.readInProgress) {
- setTimeout(function() {
- flash.cmd(id, name, data, last);
- }, 100);
- } else {
- this.cmdFn(id, name, data, last);
- }
- },
-
- cmdFn: function(id, name, data, last) {
- try {
- api.log('(js -> flash).'+name+':', data);
- return flash.get(id.flashId || id).cmd(name, data);
- } catch (e){
- api.log('(js -> flash).onError:', e);
- if( !last ){
- // try again
- setTimeout(function (){ flash.cmd(id, name, data, true); }, 50);
- }
- }
- },
- patch: function (){
- api.flashEngine = true;
- // FileAPI
- _inherit(api, {
- readAsDataURL: function (file, callback){
- if( _isHtmlFile(file) ){
- this.parent.apply(this, arguments);
- }
- else {
- api.log('FlashAPI.readAsBase64');
- flash.readInProgress = true;
- flash.cmd(file, 'readAsBase64', {
- id: file.id,
- callback: _wrap(function _(err, base64){
- flash.readInProgress = false;
- _unwrap(_);
- api.log('FlashAPI.readAsBase64:', err);
- callback({
- type: err ? 'error' : 'load'
- , error: err
- , result: 'data:'+ file.type +';base64,'+ base64
- });
- })
- });
- }
- },
- readAsText: function (file, encoding, callback){
- if( callback ){
- api.log('[warn] FlashAPI.readAsText not supported `encoding` param');
- } else {
- callback = encoding;
- }
- api.readAsDataURL(file, function (evt){
- if( evt.type == 'load' ){
- try {
- evt.result = window.atob(evt.result.split(';base64,')[1]);
- } catch( err ){
- evt.type = 'error';
- evt.error = err.toString();
- }
- }
- callback(evt);
- });
- },
-
- getFiles: function (input, filter, callback){
- if( callback ){
- api.filterFiles(api.getFiles(input), filter, callback);
- return null;
- }
- var files = api.isArray(input) ? input : _files[api.uid(input.target || input.srcElement || input)];
- if( !files ){
- // Файлов нету, вызываем родительский метод
- return this.parent.apply(this, arguments);
- }
- if( filter ){
- filter = api.getFilesFilter(filter);
- files = api.filter(files, function (file){ return filter.test(file.name); });
- }
- return files;
- },
- getInfo: function (file, fn){
- if( _isHtmlFile(file) ){
- this.parent.apply(this, arguments);
- }
- else if( file.isShot ){
- fn(null, file.info = {
- width: file.width,
- height: file.height
- });
- }
- else {
- if( !file.__info ){
- var defer = file.__info = api.defer();
- // flash.cmd(file, 'getFileInfo', {
- // id: file.id
- // , callback: _wrap(function _(err, info){
- // _unwrap(_);
- // defer.resolve(err, file.info = info);
- // })
- // });
- defer.resolve(null, file.info = null);
- }
- file.__info.then(fn);
- }
- }
- });
- // FileAPI.Image
- api.support.transform = true;
- api.Image && _inherit(api.Image.prototype, {
- get: function (fn, scaleMode){
- this.set({ scaleMode: scaleMode || 'noScale' }); // noScale, exactFit
- return this.parent(fn);
- },
- _load: function (file, fn){
- api.log('FlashAPI.Image._load:', file);
- if( _isHtmlFile(file) ){
- this.parent.apply(this, arguments);
- }
- else {
- var _this = this;
- api.getInfo(file, function (err){
- fn.call(_this, err, file);
- });
- }
- },
- _apply: function (file, fn){
- api.log('FlashAPI.Image._apply:', file);
- if( _isHtmlFile(file) ){
- this.parent.apply(this, arguments);
- }
- else {
- var m = this.getMatrix(file.info), doneFn = fn;
- flash.cmd(file, 'imageTransform', {
- id: file.id
- , matrix: m
- , callback: _wrap(function _(err, base64){
- api.log('FlashAPI.Image._apply.callback:', err);
- _unwrap(_);
- if( err ){
- doneFn(err);
- }
- else if( !api.support.html5 && (!api.support.dataURI || base64.length > 3e4) ){
- _makeFlashImage({
- width: (m.deg % 180) ? m.dh : m.dw
- , height: (m.deg % 180) ? m.dw : m.dh
- , scale: m.scaleMode
- }, base64, doneFn);
- }
- else {
- if( m.filter ){
- doneFn = function (err, img){
- if( err ){
- fn(err);
- }
- else {
- api.Image.applyFilter(img, m.filter, function (){
- fn(err, this.canvas);
- });
- }
- };
- }
- api.newImage('data:'+ file.type +';base64,'+ base64, doneFn);
- }
- })
- });
- }
- },
- toData: function (fn){
- var
- file = this.file
- , info = file.info
- , matrix = this.getMatrix(info)
- ;
- api.log('FlashAPI.Image.toData');
- if( _isHtmlFile(file) ){
- this.parent.apply(this, arguments);
- }
- else {
- if( matrix.deg == 'auto' ){
- matrix.deg = api.Image.exifOrientation[info && info.exif && info.exif.Orientation] || 0;
- }
- fn.call(this, !file.info, {
- id: file.id
- , flashId: file.flashId
- , name: file.name
- , type: file.type
- , matrix: matrix
- });
- }
- }
- });
- api.Image && _inherit(api.Image, {
- fromDataURL: function (dataURL, size, callback){
- if( !api.support.dataURI || dataURL.length > 3e4 ){
- _makeFlashImage(
- api.extend({ scale: 'exactFit' }, size)
- , dataURL.replace(/^data:[^,]+,/, '')
- , function (err, el){ callback(el); }
- );
- }
- else {
- this.parent(dataURL, size, callback);
- }
- }
- });
- // FileAPI.Form
- _inherit(api.Form.prototype, {
- toData: function (fn){
- var items = this.items, i = items.length;
- for( ; i--; ){
- if( items[i].file && _isHtmlFile(items[i].blob) ){
- return this.parent.apply(this, arguments);
- }
- }
- api.log('FlashAPI.Form.toData');
- fn(items);
- }
- });
- // FileAPI.XHR
- _inherit(api.XHR.prototype, {
- _send: function (options, formData){
- if(
- formData.nodeName
- || formData.append && api.support.html5
- || api.isArray(formData) && (typeof formData[0] === 'string')
- ){
- // HTML5, Multipart or IFrame
- return this.parent.apply(this, arguments);
- }
- var
- data = {}
- , files = {}
- , _this = this
- , flashId
- , fileId
- ;
- _each(formData, function (item){
- if( item.file ){
- files[item.name] = item = _getFileDescr(item.blob);
- fileId = item.id;
- flashId = item.flashId;
- }
- else {
- data[item.name] = item.blob;
- }
- });
- if( !fileId ){
- flashId = _attr;
- }
- if( !flashId ){
- api.log('[err] FlashAPI._send: flashId -- undefined');
- return this.parent.apply(this, arguments);
- }
- else {
- api.log('FlashAPI.XHR._send: '+ flashId +' -> '+ fileId);
- }
- _this.xhr = {
- headers: {},
- abort: function (){ flash.uploadInProgress = false; flash.cmd(flashId, 'abort', { id: fileId }); },
- getResponseHeader: function (name){ return this.headers[name]; },
- getAllResponseHeaders: function (){ return this.headers; }
- };
- var queue = api.queue(function (){
- flash.uploadInProgress = true;
- flash.cmd(flashId, 'upload', {
- url: _getUrl(options.url.replace(/([a-z]+)=(\?)&?/i, ''))
- , data: data
- , files: fileId ? files : null
- , headers: options.headers || {}
- , callback: _wrap(function upload(evt){
- var type = evt.type, result = evt.result;
- api.log('FlashAPI.upload.'+type);
- if( type == 'progress' ){
- evt.loaded = Math.min(evt.loaded, evt.total); // @todo fixme
- evt.lengthComputable = true;
- options.progress(evt);
- }
- else if( type == 'complete' ){
- flash.uploadInProgress = false;
- _unwrap(upload);
- if( typeof result == 'string' ){
- _this.responseText = result.replace(/%22/g, "\"").replace(/%5c/g, "\\").replace(/%26/g, "&").replace(/%25/g, "%");
- }
- _this.end(evt.status || 200);
- }
- else if( type == 'abort' || type == 'error' ){
- flash.uploadInProgress = false;
- _this.end(evt.status || 0, evt.message);
- _unwrap(upload);
- }
- })
- });
- });
- // #2174: FileReference.load() call while FileReference.upload() or vice versa
- _each(files, function (file){
- queue.inc();
- api.getInfo(file, queue.next);
- });
- queue.check();
- }
- });
- }
- }
- ;
- function _makeFlashHTML(opts){
- return ('<object id="#id#" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+(opts.width || '100%')+'" height="'+(opts.height || '100%')+'">'
- + '<param name="movie" value="#src#" />'
- + '<param name="flashvars" value="#flashvars#" />'
- + '<param name="swliveconnect" value="true" />'
- + '<param name="allowscriptaccess" value="always" />'
- + '<param name="allownetworking" value="all" />'
- + '<param name="menu" value="false" />'
- + '<param name="wmode" value="#wmode#" />'
- + '<embed flashvars="#flashvars#" swliveconnect="true" allownetworking="all" allowscriptaccess="always" name="#id#" src="#src#" width="'+(opts.width || '100%')+'" height="'+(opts.height || '100%')+'" menu="false" wmode="transparent" type="application/x-shockwave-flash"></embed>'
- + '</object>').replace(/#(\w+)#/ig, function (a, name){ return opts[name]; })
- ;
- }
- function _css(el, css){
- if( el && el.style ){
- var key, val;
- for( key in css ){
- val = css[key];
- if( typeof val == 'number' ){
- val += 'px';
- }
- try { el.style[key] = val; } catch (e) {}
- }
-
- }
- }
- function _inherit(obj, methods){
- _each(methods, function (fn, name){
- var prev = obj[name];
- obj[name] = function (){
- this.parent = prev;
- return fn.apply(this, arguments);
- };
- });
- }
- function _isHtmlFile(file){
- return file && !file.flashId;
- }
- function _wrap(fn){
- var id = fn.wid = api.uid();
- flash._fn[id] = fn;
- return 'FileAPI.Flash._fn.'+id;
- }
- function _unwrap(fn){
- try {
- flash._fn[fn.wid] = null;
- delete flash._fn[fn.wid];
- }
- catch(e){}
- }
- function _getUrl(url, params){
- if( !_rhttp.test(url) ){
- if( /^\.\//.test(url) || '/' != url.charAt(0) ){
- var path = location.pathname;
- path = path.substr(0, path.lastIndexOf('/'));
- url = (path +'/'+ url).replace('/./', '/');
- }
- if( '//' != url.substr(0, 2) ){
- url = '//' + location.host + url;
- }
- if( !_rhttp.test(url) ){
- url = location.protocol + url;
- }
- }
- if( params ){
- url += (/\?/.test(url) ? '&' : '?') + params;
- }
- return url;
- }
- function _makeFlashImage(opts, base64, fn){
- var
- key
- , flashId = api.uid()
- , el = document.createElement('div')
- , attempts = 10
- ;
- for( key in opts ){
- el.setAttribute(key, opts[key]);
- el[key] = opts[key];
- }
- _css(el, opts);
- opts.width = '100%';
- opts.height = '100%';
- el.innerHTML = _makeFlashHTML(api.extend({
- id: flashId
- , src: _getUrl(api.flashImageUrl, 'r='+ api.uid())
- , wmode: 'opaque'
- , flashvars: 'scale='+ opts.scale +'&callback='+_wrap(function _(){
- _unwrap(_);
- if( --attempts > 0 ){
- _setImage();
- }
- return true;
- })
- }, opts));
- function _setImage(){
- try {
- // Get flash-object by id
- var img = flash.get(flashId);
- img.setImage(base64);
- } catch (e){
- api.log('[err] FlashAPI.Preview.setImage -- can not set "base64":', e);
- }
- }
- fn(false, el);
- el = null;
- }
- function _getFileDescr(file){
- return {
- id: file.id
- , name: file.name
- , matrix: file.matrix
- , flashId: file.flashId
- };
- }
- function _getDimensions(el){
- var
- box = el.getBoundingClientRect()
- , body = document.body
- , docEl = (el && el.ownerDocument).documentElement
- ;
-
- function getOffset(obj) {
- var left, top;
- left = top = 0;
- if (obj.offsetParent) {
- do {
- left += obj.offsetLeft;
- top += obj.offsetTop;
- } while (obj = obj.offsetParent);
- }
- return {
- left : left,
- top : top
- };
- };
-
- return {
- top: getOffset(el).top
- , left: getOffset(el).left
- , width: el.offsetWidth
- , height: el.offsetHeight
- };
- }
- // @export
- api.Flash = flash;
- // Check dataURI support
- api.newImage('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==', function (err, img){
- api.support.dataURI = !(img.width != 1 || img.height != 1);
- flash.init();
- });
- })();
- })(window, window.jQuery, FileAPI);
- /**
- * FileAPI fallback to Flash
- *
- * @flash-developer "Vladimir Demidov" <v.demidov@corp.mail.ru>
- */
- /*global window, FileAPI */
- (function (window, jQuery, api) {
- "use strict";
- var _each = api.each,
- _cameraQueue = [];
- if (api.support.flash && (api.media && !api.support.media)) {
- (function () {
- function _wrap(fn) {
- var id = fn.wid = api.uid();
- api.Flash._fn[id] = fn;
- return 'FileAPI.Flash._fn.' + id;
- }
- function _unwrap(fn) {
- try {
- api.Flash._fn[fn.wid] = null;
- delete api.Flash._fn[fn.wid];
- } catch (e) {
- }
- }
- var flash = api.Flash;
- api.extend(api.Flash, {
- patchCamera: function () {
- api.Camera.fallback = function (el, options, callback) {
- var camId = api.uid();
- api.log('FlashAPI.Camera.publish: ' + camId);
- flash.publish(el, camId, api.extend(options, {
- camera: true,
- onEvent: _wrap(function _(evt) {
- if (evt.type === 'camera') {
- _unwrap(_);
- if (evt.error) {
- api.log('FlashAPI.Camera.publish.error: ' + evt.error);
- callback(evt.error);
- } else {
- api.log('FlashAPI.Camera.publish.success: ' + camId);
- callback(null);
- }
- }
- })
- }));
- };
- // Run
- _each(_cameraQueue, function (args) {
- api.Camera.fallback.apply(api.Camera, args);
- });
- _cameraQueue = [];
- // FileAPI.Camera:proto
- api.extend(api.Camera.prototype, {
- _id: function () {
- return this.video.id;
- },
- start: function (callback) {
- var _this = this;
- flash.cmd(this._id(), 'camera.on', {
- callback: _wrap(function _(evt) {
- _unwrap(_);
- if (evt.error) {
- api.log('FlashAPI.camera.on.error: ' + evt.error);
- callback(evt.error, _this);
- } else {
- api.log('FlashAPI.camera.on.success: ' + _this._id());
- _this._active = true;
- callback(null, _this);
- }
- })
- });
- },
- stop: function () {
- this._active = false;
- flash.cmd(this._id(), 'camera.off');
- },
- shot: function () {
- api.log('FlashAPI.Camera.shot:', this._id());
- var shot = api.Flash.cmd(this._id(), 'shot', {});
- shot.type = 'image/png';
- shot.flashId = this._id();
- shot.isShot = true;
- return new api.Camera.Shot(shot);
- }
- });
- }
- });
- api.Camera.fallback = function () {
- _cameraQueue.push(arguments);
- };
- }());
- }
- }(window, window.jQuery, FileAPI));
- if( typeof define === "function" && define.amd ){ define("FileAPI", [], function (){ return FileAPI; }); }
|