diff options
Diffstat (limited to 'www/crm/wp-content/plugins/civicrm/civicrm/bower_components/angular-file-upload/src/module.js')
-rw-r--r-- | www/crm/wp-content/plugins/civicrm/civicrm/bower_components/angular-file-upload/src/module.js | 1322 |
1 files changed, 1322 insertions, 0 deletions
diff --git a/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/angular-file-upload/src/module.js b/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/angular-file-upload/src/module.js new file mode 100644 index 00000000..3813fd16 --- /dev/null +++ b/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/angular-file-upload/src/module.js @@ -0,0 +1,1322 @@ +'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 = arrayOfFilters[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); + }); + }); + + if ( typeof(item._file.size) != 'number' ) { + throw new TypeError('The file specified is no longer valid'); + } + + 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() { + try { + this.uploader.uploadItem(this); + } catch (e) { + this.uploader._onCompleteItem( this, '', 0, [] ); + this.uploader._onErrorItem( this, '', 0, [] ); + } + }; + /** + * 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; + }; + } + }; + }]) |