123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314 |
- 'use strict';
- /**
- * Classes
- *
- * FileUploader
- * FileUploader.FileLikeObject
- * FileUploader.FileItem
- * FileUploader.FileDirective
- * FileUploader.FileSelect
- * FileUploader.FileDrop
- * FileUploader.FileOver
- */
- module
- .value('fileUploaderOptions', {
- url: '/',
- alias: 'file',
- headers: {},
- queue: [],
- progress: 0,
- autoUpload: false,
- removeAfterUpload: false,
- method: 'POST',
- filters: [],
- formData: [],
- queueLimit: Number.MAX_VALUE,
- withCredentials: false
- })
- .factory('FileUploader', ['fileUploaderOptions', '$rootScope', '$http', '$window', '$compile',
- function(fileUploaderOptions, $rootScope, $http, $window, $compile) {
- /**
- * Creates an instance of FileUploader
- * @param {Object} [options]
- * @constructor
- */
- function FileUploader(options) {
- var settings = angular.copy(fileUploaderOptions);
- angular.extend(this, settings, options, {
- isUploading: false,
- _nextIndex: 0,
- _failFilterIndex: -1,
- _directives: {select: [], drop: [], over: []}
- });
- // add default filters
- this.filters.unshift({name: 'queueLimit', fn: this._queueLimitFilter});
- this.filters.unshift({name: 'folder', fn: this._folderFilter});
- }
- /**********************
- * PUBLIC
- **********************/
- /**
- * Checks a support the html5 uploader
- * @returns {Boolean}
- * @readonly
- */
- FileUploader.prototype.isHTML5 = !!($window.File && $window.FormData);
- /**
- * Adds items to the queue
- * @param {File|HTMLInputElement|Object|FileList|Array<Object>} files
- * @param {Object} [options]
- * @param {Array<Function>|String} filters
- */
- FileUploader.prototype.addToQueue = function(files, options, filters) {
- var list = this.isArrayLikeObject(files) ? files: [files];
- var arrayOfFilters = this._getFilters(filters);
- var count = this.queue.length;
- var addedFileItems = [];
- angular.forEach(list, function(some /*{File|HTMLInputElement|Object}*/) {
- var temp = new FileUploader.FileLikeObject(some);
- if (this._isValidFile(temp, arrayOfFilters, options)) {
- var fileItem = new FileUploader.FileItem(this, some, options);
- addedFileItems.push(fileItem);
- this.queue.push(fileItem);
- this._onAfterAddingFile(fileItem);
- } else {
- var filter = this.filters[this._failFilterIndex];
- this._onWhenAddingFileFailed(temp, filter, options);
- }
- }, this);
- if(this.queue.length !== count) {
- this._onAfterAddingAll(addedFileItems);
- this.progress = this._getTotalProgress();
- }
- this._render();
- if (this.autoUpload) this.uploadAll();
- };
- /**
- * Remove items from the queue. Remove last: index = -1
- * @param {FileItem|Number} value
- */
- FileUploader.prototype.removeFromQueue = function(value) {
- var index = this.getIndexOfItem(value);
- var item = this.queue[index];
- if (item.isUploading) item.cancel();
- this.queue.splice(index, 1);
- item._destroy();
- this.progress = this._getTotalProgress();
- };
- /**
- * Clears the queue
- */
- FileUploader.prototype.clearQueue = function() {
- while(this.queue.length) {
- this.queue[0].remove();
- }
- this.progress = 0;
- };
- /**
- * Uploads a item from the queue
- * @param {FileItem|Number} value
- */
- FileUploader.prototype.uploadItem = function(value) {
- var index = this.getIndexOfItem(value);
- var item = this.queue[index];
- var transport = this.isHTML5 ? '_xhrTransport' : '_iframeTransport';
- item._prepareToUploading();
- if(this.isUploading) return;
- this.isUploading = true;
- this[transport](item);
- };
- /**
- * Cancels uploading of item from the queue
- * @param {FileItem|Number} value
- */
- FileUploader.prototype.cancelItem = function(value) {
- var index = this.getIndexOfItem(value);
- var item = this.queue[index];
- var prop = this.isHTML5 ? '_xhr' : '_form';
- if (item && item.isUploading) item[prop].abort();
- };
- /**
- * Uploads all not uploaded items of queue
- */
- FileUploader.prototype.uploadAll = function() {
- var items = this.getNotUploadedItems().filter(function(item) {
- return !item.isUploading;
- });
- if (!items.length) return;
- angular.forEach(items, function(item) {
- item._prepareToUploading();
- });
- items[0].upload();
- };
- /**
- * Cancels all uploads
- */
- FileUploader.prototype.cancelAll = function() {
- var items = this.getNotUploadedItems();
- angular.forEach(items, function(item) {
- item.cancel();
- });
- };
- /**
- * Returns "true" if value an instance of File
- * @param {*} value
- * @returns {Boolean}
- * @private
- */
- FileUploader.prototype.isFile = function(value) {
- var fn = $window.File;
- return (fn && value instanceof fn);
- };
- /**
- * Returns "true" if value an instance of FileLikeObject
- * @param {*} value
- * @returns {Boolean}
- * @private
- */
- FileUploader.prototype.isFileLikeObject = function(value) {
- return value instanceof FileUploader.FileLikeObject;
- };
- /**
- * Returns "true" if value is array like object
- * @param {*} value
- * @returns {Boolean}
- */
- FileUploader.prototype.isArrayLikeObject = function(value) {
- return (angular.isObject(value) && 'length' in value);
- };
- /**
- * Returns a index of item from the queue
- * @param {Item|Number} value
- * @returns {Number}
- */
- FileUploader.prototype.getIndexOfItem = function(value) {
- return angular.isNumber(value) ? value : this.queue.indexOf(value);
- };
- /**
- * Returns not uploaded items
- * @returns {Array}
- */
- FileUploader.prototype.getNotUploadedItems = function() {
- return this.queue.filter(function(item) {
- return !item.isUploaded;
- });
- };
- /**
- * Returns items ready for upload
- * @returns {Array}
- */
- FileUploader.prototype.getReadyItems = function() {
- return this.queue
- .filter(function(item) {
- return (item.isReady && !item.isUploading);
- })
- .sort(function(item1, item2) {
- return item1.index - item2.index;
- });
- };
- /**
- * Destroys instance of FileUploader
- */
- FileUploader.prototype.destroy = function() {
- angular.forEach(this._directives, function(key) {
- angular.forEach(this._directives[key], function(object) {
- object.destroy();
- }, this);
- }, this);
- };
- /**
- * Callback
- * @param {Array} fileItems
- */
- FileUploader.prototype.onAfterAddingAll = function(fileItems) {};
- /**
- * Callback
- * @param {FileItem} fileItem
- */
- FileUploader.prototype.onAfterAddingFile = function(fileItem) {};
- /**
- * Callback
- * @param {File|Object} item
- * @param {Object} filter
- * @param {Object} options
- * @private
- */
- FileUploader.prototype.onWhenAddingFileFailed = function(item, filter, options) {};
- /**
- * Callback
- * @param {FileItem} fileItem
- */
- FileUploader.prototype.onBeforeUploadItem = function(fileItem) {};
- /**
- * Callback
- * @param {FileItem} fileItem
- * @param {Number} progress
- */
- FileUploader.prototype.onProgressItem = function(fileItem, progress) {};
- /**
- * Callback
- * @param {Number} progress
- */
- FileUploader.prototype.onProgressAll = function(progress) {};
- /**
- * Callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileUploader.prototype.onSuccessItem = function(item, response, status, headers) {};
- /**
- * Callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileUploader.prototype.onErrorItem = function(item, response, status, headers) {};
- /**
- * Callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileUploader.prototype.onCancelItem = function(item, response, status, headers) {};
- /**
- * Callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileUploader.prototype.onCompleteItem = function(item, response, status, headers) {};
- /**
- * Callback
- */
- FileUploader.prototype.onCompleteAll = function() {};
- /**********************
- * PRIVATE
- **********************/
- /**
- * Returns the total progress
- * @param {Number} [value]
- * @returns {Number}
- * @private
- */
- FileUploader.prototype._getTotalProgress = function(value) {
- if(this.removeAfterUpload) return value || 0;
- var notUploaded = this.getNotUploadedItems().length;
- var uploaded = notUploaded ? this.queue.length - notUploaded : this.queue.length;
- var ratio = 100 / this.queue.length;
- var current = (value || 0) * ratio / 100;
- return Math.round(uploaded * ratio + current);
- };
- /**
- * Returns array of filters
- * @param {Array<Function>|String} filters
- * @returns {Array<Function>}
- * @private
- */
- FileUploader.prototype._getFilters = function(filters) {
- if (angular.isUndefined(filters)) return this.filters;
- if (angular.isArray(filters)) return filters;
- var names = filters.match(/[^\s,]+/g);
- return this.filters.filter(function(filter) {
- return names.indexOf(filter.name) !== -1;
- }, this);
- };
- /**
- * Updates html
- * @private
- */
- FileUploader.prototype._render = function() {
- if (!$rootScope.$$phase) $rootScope.$apply();
- };
- /**
- * Returns "true" if item is a file (not folder)
- * @param {File|FileLikeObject} item
- * @returns {Boolean}
- * @private
- */
- FileUploader.prototype._folderFilter = function(item) {
- return !!(item.size || item.type);
- };
- /**
- * Returns "true" if the limit has not been reached
- * @returns {Boolean}
- * @private
- */
- FileUploader.prototype._queueLimitFilter = function() {
- return this.queue.length < this.queueLimit;
- };
- /**
- * Returns "true" if file pass all filters
- * @param {File|Object} file
- * @param {Array<Function>} filters
- * @param {Object} options
- * @returns {Boolean}
- * @private
- */
- FileUploader.prototype._isValidFile = function(file, filters, options) {
- this._failFilterIndex = -1;
- return !filters.length ? true : filters.every(function(filter) {
- this._failFilterIndex++;
- return filter.fn.call(this, file, options);
- }, this);
- };
- /**
- * Checks whether upload successful
- * @param {Number} status
- * @returns {Boolean}
- * @private
- */
- FileUploader.prototype._isSuccessCode = function(status) {
- return (status >= 200 && status < 300) || status === 304;
- };
- /**
- * Transforms the server response
- * @param {*} response
- * @param {Object} headers
- * @returns {*}
- * @private
- */
- FileUploader.prototype._transformResponse = function(response, headers) {
- var headersGetter = this._headersGetter(headers);
- angular.forEach($http.defaults.transformResponse, function(transformFn) {
- response = transformFn(response, headersGetter);
- });
- return response;
- };
- /**
- * Parsed response headers
- * @param headers
- * @returns {Object}
- * @see https://github.com/angular/angular.js/blob/master/src/ng/http.js
- * @private
- */
- FileUploader.prototype._parseHeaders = function(headers) {
- var parsed = {}, key, val, i;
- if (!headers) return parsed;
- angular.forEach(headers.split('\n'), function(line) {
- i = line.indexOf(':');
- key = line.slice(0, i).trim().toLowerCase();
- val = line.slice(i + 1).trim();
- if (key) {
- parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
- }
- });
- return parsed;
- };
- /**
- * Returns function that returns headers
- * @param {Object} parsedHeaders
- * @returns {Function}
- * @private
- */
- FileUploader.prototype._headersGetter = function(parsedHeaders) {
- return function(name) {
- if (name) {
- return parsedHeaders[name.toLowerCase()] || null;
- }
- return parsedHeaders;
- };
- };
- /**
- * The XMLHttpRequest transport
- * @param {FileItem} item
- * @private
- */
- FileUploader.prototype._xhrTransport = function(item) {
- var xhr = item._xhr = new XMLHttpRequest();
- var form = new FormData();
- var that = this;
- that._onBeforeUploadItem(item);
- angular.forEach(item.formData, function(obj) {
- angular.forEach(obj, function(value, key) {
- form.append(key, value);
- });
- });
- form.append(item.alias, item._file, item.file.name);
- xhr.upload.onprogress = function(event) {
- var progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
- that._onProgressItem(item, progress);
- };
- xhr.onload = function() {
- var headers = that._parseHeaders(xhr.getAllResponseHeaders());
- var response = that._transformResponse(xhr.response, headers);
- var gist = that._isSuccessCode(xhr.status) ? 'Success' : 'Error';
- var method = '_on' + gist + 'Item';
- that[method](item, response, xhr.status, headers);
- that._onCompleteItem(item, response, xhr.status, headers);
- };
- xhr.onerror = function() {
- var headers = that._parseHeaders(xhr.getAllResponseHeaders());
- var response = that._transformResponse(xhr.response, headers);
- that._onErrorItem(item, response, xhr.status, headers);
- that._onCompleteItem(item, response, xhr.status, headers);
- };
- xhr.onabort = function() {
- var headers = that._parseHeaders(xhr.getAllResponseHeaders());
- var response = that._transformResponse(xhr.response, headers);
- that._onCancelItem(item, response, xhr.status, headers);
- that._onCompleteItem(item, response, xhr.status, headers);
- };
- xhr.open(item.method, item.url, true);
- xhr.withCredentials = item.withCredentials;
- angular.forEach(item.headers, function(value, name) {
- xhr.setRequestHeader(name, value);
- });
- xhr.send(form);
- this._render();
- };
- /**
- * The IFrame transport
- * @param {FileItem} item
- * @private
- */
- FileUploader.prototype._iframeTransport = function(item) {
- var form = angular.element('<form style="display: none;" />');
- var iframe = angular.element('<iframe name="iframeTransport' + Date.now() + '">');
- var input = item._input;
- var that = this;
- if (item._form) item._form.replaceWith(input); // remove old form
- item._form = form; // save link to new form
- that._onBeforeUploadItem(item);
- input.prop('name', item.alias);
- angular.forEach(item.formData, function(obj) {
- angular.forEach(obj, function(value, key) {
- var element = angular.element('<input type="hidden" name="' + key + '" />');
- element.val(value);
- form.append(element);
- });
- });
- form.prop({
- action: item.url,
- method: 'POST',
- target: iframe.prop('name'),
- enctype: 'multipart/form-data',
- encoding: 'multipart/form-data' // old IE
- });
- iframe.bind('load', function() {
- try {
- // Fix for legacy IE browsers that loads internal error page
- // when failed WS response received. In consequence iframe
- // content access denied error is thrown becouse trying to
- // access cross domain page. When such thing occurs notifying
- // with empty response object. See more info at:
- // http://stackoverflow.com/questions/151362/access-is-denied-error-on-accessing-iframe-document-object
- // Note that if non standard 4xx or 5xx error code returned
- // from WS then response content can be accessed without error
- // but 'XHR' status becomes 200. In order to avoid confusion
- // returning response via same 'success' event handler.
- // fixed angular.contents() for iframes
- var html = iframe[0].contentDocument.body.innerHTML;
- } catch (e) {}
- var xhr = {response: html, status: 200, dummy: true};
- var headers = {};
- var response = that._transformResponse(xhr.response, headers);
- that._onSuccessItem(item, response, xhr.status, headers);
- that._onCompleteItem(item, response, xhr.status, headers);
- });
- form.abort = function() {
- var xhr = {status: 0, dummy: true};
- var headers = {};
- var response;
- iframe.unbind('load').prop('src', 'javascript:false;');
- form.replaceWith(input);
- that._onCancelItem(item, response, xhr.status, headers);
- that._onCompleteItem(item, response, xhr.status, headers);
- };
- input.after(form);
- form.append(input).append(iframe);
- form[0].submit();
- this._render();
- };
- /**
- * Inner callback
- * @param {File|Object} item
- * @param {Object} filter
- * @param {Object} options
- * @private
- */
- FileUploader.prototype._onWhenAddingFileFailed = function(item, filter, options) {
- this.onWhenAddingFileFailed(item, filter, options);
- };
- /**
- * Inner callback
- * @param {FileItem} item
- */
- FileUploader.prototype._onAfterAddingFile = function(item) {
- this.onAfterAddingFile(item);
- };
- /**
- * Inner callback
- * @param {Array<FileItem>} items
- */
- FileUploader.prototype._onAfterAddingAll = function(items) {
- this.onAfterAddingAll(items);
- };
- /**
- * Inner callback
- * @param {FileItem} item
- * @private
- */
- FileUploader.prototype._onBeforeUploadItem = function(item) {
- item._onBeforeUpload();
- this.onBeforeUploadItem(item);
- };
- /**
- * Inner callback
- * @param {FileItem} item
- * @param {Number} progress
- * @private
- */
- FileUploader.prototype._onProgressItem = function(item, progress) {
- var total = this._getTotalProgress(progress);
- this.progress = total;
- item._onProgress(progress);
- this.onProgressItem(item, progress);
- this.onProgressAll(total);
- this._render();
- };
- /**
- * Inner callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileUploader.prototype._onSuccessItem = function(item, response, status, headers) {
- item._onSuccess(response, status, headers);
- this.onSuccessItem(item, response, status, headers);
- };
- /**
- * Inner callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileUploader.prototype._onErrorItem = function(item, response, status, headers) {
- item._onError(response, status, headers);
- this.onErrorItem(item, response, status, headers);
- };
- /**
- * Inner callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileUploader.prototype._onCancelItem = function(item, response, status, headers) {
- item._onCancel(response, status, headers);
- this.onCancelItem(item, response, status, headers);
- };
- /**
- * Inner callback
- * @param {FileItem} item
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileUploader.prototype._onCompleteItem = function(item, response, status, headers) {
- item._onComplete(response, status, headers);
- this.onCompleteItem(item, response, status, headers);
- var nextItem = this.getReadyItems()[0];
- this.isUploading = false;
- if(angular.isDefined(nextItem)) {
- nextItem.upload();
- return;
- }
- this.onCompleteAll();
- this.progress = this._getTotalProgress();
- this._render();
- };
- /**********************
- * STATIC
- **********************/
- /**
- * @borrows FileUploader.prototype.isFile
- */
- FileUploader.isFile = FileUploader.prototype.isFile;
- /**
- * @borrows FileUploader.prototype.isFileLikeObject
- */
- FileUploader.isFileLikeObject = FileUploader.prototype.isFileLikeObject;
- /**
- * @borrows FileUploader.prototype.isArrayLikeObject
- */
- FileUploader.isArrayLikeObject = FileUploader.prototype.isArrayLikeObject;
- /**
- * @borrows FileUploader.prototype.isHTML5
- */
- FileUploader.isHTML5 = FileUploader.prototype.isHTML5;
- /**
- * Inherits a target (Class_1) by a source (Class_2)
- * @param {Function} target
- * @param {Function} source
- */
- FileUploader.inherit = function(target, source) {
- target.prototype = Object.create(source.prototype);
- target.prototype.constructor = target;
- target.super_ = source;
- };
- FileUploader.FileLikeObject = FileLikeObject;
- FileUploader.FileItem = FileItem;
- FileUploader.FileDirective = FileDirective;
- FileUploader.FileSelect = FileSelect;
- FileUploader.FileDrop = FileDrop;
- FileUploader.FileOver = FileOver;
- // ---------------------------
- /**
- * Creates an instance of FileLikeObject
- * @param {File|HTMLInputElement|Object} fileOrInput
- * @constructor
- */
- function FileLikeObject(fileOrInput) {
- var isInput = angular.isElement(fileOrInput);
- var fakePathOrObject = isInput ? fileOrInput.value : fileOrInput;
- var postfix = angular.isString(fakePathOrObject) ? 'FakePath' : 'Object';
- var method = '_createFrom' + postfix;
- this[method](fakePathOrObject);
- }
- /**
- * Creates file like object from fake path string
- * @param {String} path
- * @private
- */
- FileLikeObject.prototype._createFromFakePath = function(path) {
- this.lastModifiedDate = null;
- this.size = null;
- this.type = 'like/' + path.slice(path.lastIndexOf('.') + 1).toLowerCase();
- this.name = path.slice(path.lastIndexOf('/') + path.lastIndexOf('\\') + 2);
- };
- /**
- * Creates file like object from object
- * @param {File|FileLikeObject} object
- * @private
- */
- FileLikeObject.prototype._createFromObject = function(object) {
- this.lastModifiedDate = angular.copy(object.lastModifiedDate);
- this.size = object.size;
- this.type = object.type;
- this.name = object.name;
- };
- // ---------------------------
- /**
- * Creates an instance of FileItem
- * @param {FileUploader} uploader
- * @param {File|HTMLInputElement|Object} some
- * @param {Object} options
- * @constructor
- */
- function FileItem(uploader, some, options) {
- var isInput = angular.isElement(some);
- var input = isInput ? angular.element(some) : null;
- var file = !isInput ? some : null;
- angular.extend(this, {
- url: uploader.url,
- alias: uploader.alias,
- headers: angular.copy(uploader.headers),
- formData: angular.copy(uploader.formData),
- removeAfterUpload: uploader.removeAfterUpload,
- withCredentials: uploader.withCredentials,
- method: uploader.method
- }, options, {
- uploader: uploader,
- file: new FileUploader.FileLikeObject(some),
- isReady: false,
- isUploading: false,
- isUploaded: false,
- isSuccess: false,
- isCancel: false,
- isError: false,
- progress: 0,
- index: null,
- _file: file,
- _input: input
- });
- if (input) this._replaceNode(input);
- }
- /**********************
- * PUBLIC
- **********************/
- /**
- * Uploads a FileItem
- */
- FileItem.prototype.upload = function() {
- this.uploader.uploadItem(this);
- };
- /**
- * Cancels uploading of FileItem
- */
- FileItem.prototype.cancel = function() {
- this.uploader.cancelItem(this);
- };
- /**
- * Removes a FileItem
- */
- FileItem.prototype.remove = function() {
- this.uploader.removeFromQueue(this);
- };
- /**
- * Callback
- * @private
- */
- FileItem.prototype.onBeforeUpload = function() {};
- /**
- * Callback
- * @param {Number} progress
- * @private
- */
- FileItem.prototype.onProgress = function(progress) {};
- /**
- * Callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileItem.prototype.onSuccess = function(response, status, headers) {};
- /**
- * Callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileItem.prototype.onError = function(response, status, headers) {};
- /**
- * Callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileItem.prototype.onCancel = function(response, status, headers) {};
- /**
- * Callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- */
- FileItem.prototype.onComplete = function(response, status, headers) {};
- /**********************
- * PRIVATE
- **********************/
- /**
- * Inner callback
- */
- FileItem.prototype._onBeforeUpload = function() {
- this.isReady = true;
- this.isUploading = true;
- this.isUploaded = false;
- this.isSuccess = false;
- this.isCancel = false;
- this.isError = false;
- this.progress = 0;
- this.onBeforeUpload();
- };
- /**
- * Inner callback
- * @param {Number} progress
- * @private
- */
- FileItem.prototype._onProgress = function(progress) {
- this.progress = progress;
- this.onProgress(progress);
- };
- /**
- * Inner callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileItem.prototype._onSuccess = function(response, status, headers) {
- this.isReady = false;
- this.isUploading = false;
- this.isUploaded = true;
- this.isSuccess = true;
- this.isCancel = false;
- this.isError = false;
- this.progress = 100;
- this.index = null;
- this.onSuccess(response, status, headers);
- };
- /**
- * Inner callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileItem.prototype._onError = function(response, status, headers) {
- this.isReady = false;
- this.isUploading = false;
- this.isUploaded = true;
- this.isSuccess = false;
- this.isCancel = false;
- this.isError = true;
- this.progress = 0;
- this.index = null;
- this.onError(response, status, headers);
- };
- /**
- * Inner callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileItem.prototype._onCancel = function(response, status, headers) {
- this.isReady = false;
- this.isUploading = false;
- this.isUploaded = false;
- this.isSuccess = false;
- this.isCancel = true;
- this.isError = false;
- this.progress = 0;
- this.index = null;
- this.onCancel(response, status, headers);
- };
- /**
- * Inner callback
- * @param {*} response
- * @param {Number} status
- * @param {Object} headers
- * @private
- */
- FileItem.prototype._onComplete = function(response, status, headers) {
- this.onComplete(response, status, headers);
- if (this.removeAfterUpload) this.remove();
- };
- /**
- * Destroys a FileItem
- */
- FileItem.prototype._destroy = function() {
- if (this._input) this._input.remove();
- if (this._form) this._form.remove();
- delete this._form;
- delete this._input;
- };
- /**
- * Prepares to uploading
- * @private
- */
- FileItem.prototype._prepareToUploading = function() {
- this.index = this.index || ++this.uploader._nextIndex;
- this.isReady = true;
- };
- /**
- * Replaces input element on his clone
- * @param {JQLite|jQuery} input
- * @private
- */
- FileItem.prototype._replaceNode = function(input) {
- var clone = $compile(input.clone())(input.scope());
- clone.prop('value', null); // FF fix
- input.css('display', 'none');
- input.after(clone); // remove jquery dependency
- };
- // ---------------------------
- /**
- * Creates instance of {FileDirective} object
- * @param {Object} options
- * @param {Object} options.uploader
- * @param {HTMLElement} options.element
- * @param {Object} options.events
- * @param {String} options.prop
- * @constructor
- */
- function FileDirective(options) {
- angular.extend(this, options);
- this.uploader._directives[this.prop].push(this);
- this._saveLinks();
- this.bind();
- }
- /**
- * Map of events
- * @type {Object}
- */
- FileDirective.prototype.events = {};
- /**
- * Binds events handles
- */
- FileDirective.prototype.bind = function() {
- for(var key in this.events) {
- var prop = this.events[key];
- this.element.bind(key, this[prop]);
- }
- };
- /**
- * Unbinds events handles
- */
- FileDirective.prototype.unbind = function() {
- for(var key in this.events) {
- this.element.unbind(key, this.events[key]);
- }
- };
- /**
- * Destroys directive
- */
- FileDirective.prototype.destroy = function() {
- var index = this.uploader._directives[this.prop].indexOf(this);
- this.uploader._directives[this.prop].splice(index, 1);
- this.unbind();
- // this.element = null;
- };
- /**
- * Saves links to functions
- * @private
- */
- FileDirective.prototype._saveLinks = function() {
- for(var key in this.events) {
- var prop = this.events[key];
- this[prop] = this[prop].bind(this);
- }
- };
- // ---------------------------
- FileUploader.inherit(FileSelect, FileDirective);
- /**
- * Creates instance of {FileSelect} object
- * @param {Object} options
- * @constructor
- */
- function FileSelect(options) {
- FileSelect.super_.apply(this, arguments);
- if(!this.uploader.isHTML5) {
- this.element.removeAttr('multiple');
- }
- this.element.prop('value', null); // FF fix
- }
- /**
- * Map of events
- * @type {Object}
- */
- FileSelect.prototype.events = {
- $destroy: 'destroy',
- change: 'onChange'
- };
- /**
- * Name of property inside uploader._directive object
- * @type {String}
- */
- FileSelect.prototype.prop = 'select';
- /**
- * Returns options
- * @return {Object|undefined}
- */
- FileSelect.prototype.getOptions = function() {};
- /**
- * Returns filters
- * @return {Array<Function>|String|undefined}
- */
- FileSelect.prototype.getFilters = function() {};
- /**
- * If returns "true" then HTMLInputElement will be cleared
- * @returns {Boolean}
- */
- FileSelect.prototype.isEmptyAfterSelection = function() {
- return !!this.element.attr('multiple');
- };
- /**
- * Event handler
- */
- FileSelect.prototype.onChange = function() {
- var files = this.uploader.isHTML5 ? this.element[0].files : this.element[0];
- var options = this.getOptions();
- var filters = this.getFilters();
- if (!this.uploader.isHTML5) this.destroy();
- this.uploader.addToQueue(files, options, filters);
- if (this.isEmptyAfterSelection()) this.element.prop('value', null);
- };
- // ---------------------------
- FileUploader.inherit(FileDrop, FileDirective);
- /**
- * Creates instance of {FileDrop} object
- * @param {Object} options
- * @constructor
- */
- function FileDrop(options) {
- FileDrop.super_.apply(this, arguments);
- }
- /**
- * Map of events
- * @type {Object}
- */
- FileDrop.prototype.events = {
- $destroy: 'destroy',
- drop: 'onDrop',
- dragover: 'onDragOver',
- dragleave: 'onDragLeave'
- };
- /**
- * Name of property inside uploader._directive object
- * @type {String}
- */
- FileDrop.prototype.prop = 'drop';
- /**
- * Returns options
- * @return {Object|undefined}
- */
- FileDrop.prototype.getOptions = function() {};
- /**
- * Returns filters
- * @return {Array<Function>|String|undefined}
- */
- FileDrop.prototype.getFilters = function() {};
- /**
- * Event handler
- */
- FileDrop.prototype.onDrop = function(event) {
- var transfer = this._getTransfer(event);
- if (!transfer) return;
- var options = this.getOptions();
- var filters = this.getFilters();
- this._preventAndStop(event);
- angular.forEach(this.uploader._directives.over, this._removeOverClass, this);
- this.uploader.addToQueue(transfer.files, options, filters);
- };
- /**
- * Event handler
- */
- FileDrop.prototype.onDragOver = function(event) {
- var transfer = this._getTransfer(event);
- if(!this._haveFiles(transfer.types)) return;
- transfer.dropEffect = 'copy';
- this._preventAndStop(event);
- angular.forEach(this.uploader._directives.over, this._addOverClass, this);
- };
- /**
- * Event handler
- */
- FileDrop.prototype.onDragLeave = function(event) {
- if (event.currentTarget !== this.element[0]) return;
- this._preventAndStop(event);
- angular.forEach(this.uploader._directives.over, this._removeOverClass, this);
- };
- /**
- * Helper
- */
- FileDrop.prototype._getTransfer = function(event) {
- return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix;
- };
- /**
- * Helper
- */
- FileDrop.prototype._preventAndStop = function(event) {
- event.preventDefault();
- event.stopPropagation();
- };
- /**
- * Returns "true" if types contains files
- * @param {Object} types
- */
- FileDrop.prototype._haveFiles = function(types) {
- if (!types) return false;
- if (types.indexOf) {
- return types.indexOf('Files') !== -1;
- } else if(types.contains) {
- return types.contains('Files');
- } else {
- return false;
- }
- };
- /**
- * Callback
- */
- FileDrop.prototype._addOverClass = function(item) {
- item.addOverClass();
- };
- /**
- * Callback
- */
- FileDrop.prototype._removeOverClass = function(item) {
- item.removeOverClass();
- };
- // ---------------------------
- FileUploader.inherit(FileOver, FileDirective);
- /**
- * Creates instance of {FileDrop} object
- * @param {Object} options
- * @constructor
- */
- function FileOver(options) {
- FileOver.super_.apply(this, arguments);
- }
- /**
- * Map of events
- * @type {Object}
- */
- FileOver.prototype.events = {
- $destroy: 'destroy'
- };
- /**
- * Name of property inside uploader._directive object
- * @type {String}
- */
- FileOver.prototype.prop = 'over';
- /**
- * Over class
- * @type {string}
- */
- FileOver.prototype.overClass = 'nv-file-over';
- /**
- * Adds over class
- */
- FileOver.prototype.addOverClass = function() {
- this.element.addClass(this.getOverClass());
- };
- /**
- * Removes over class
- */
- FileOver.prototype.removeOverClass = function() {
- this.element.removeClass(this.getOverClass());
- };
- /**
- * Returns over class
- * @returns {String}
- */
- FileOver.prototype.getOverClass = function() {
- return this.overClass;
- };
- return FileUploader;
- }])
- .directive('nvFileSelect', ['$parse', 'FileUploader', function($parse, FileUploader) {
- return {
- link: function(scope, element, attributes) {
- var uploader = scope.$eval(attributes.uploader);
- if (!(uploader instanceof FileUploader)) {
- throw new TypeError('"Uploader" must be an instance of FileUploader');
- }
- var object = new FileUploader.FileSelect({
- uploader: uploader,
- element: element
- });
- object.getOptions = $parse(attributes.options).bind(object, scope);
- object.getFilters = function() {return attributes.filters;};
- }
- };
- }])
- .directive('nvFileDrop', ['$parse', 'FileUploader', function($parse, FileUploader) {
- return {
- link: function(scope, element, attributes) {
- var uploader = scope.$eval(attributes.uploader);
- if (!(uploader instanceof FileUploader)) {
- throw new TypeError('"Uploader" must be an instance of FileUploader');
- }
- if (!uploader.isHTML5) return;
- var object = new FileUploader.FileDrop({
- uploader: uploader,
- element: element
- });
- object.getOptions = $parse(attributes.options).bind(object, scope);
- object.getFilters = function() {return attributes.filters;};
- }
- };
- }])
- .directive('nvFileOver', ['FileUploader', function(FileUploader) {
- return {
- link: function(scope, element, attributes) {
- var uploader = scope.$eval(attributes.uploader);
- if (!(uploader instanceof FileUploader)) {
- throw new TypeError('"Uploader" must be an instance of FileUploader');
- }
- var object = new FileUploader.FileOver({
- uploader: uploader,
- element: element
- });
- object.getOverClass = function() {
- return attributes.overClass || this.overClass;
- };
- }
- };
- }])
|