Migrate examples
- Move example dirs to loopback-example-storage - Refactor tests to depend on local files in test/fixtures - Add link to example in README.md
This commit is contained in:
parent
1bcb33a115
commit
8eaf78b912
|
@ -13,3 +13,7 @@ storage services including:
|
||||||
- Azure
|
- Azure
|
||||||
|
|
||||||
> Please see the [Storage Service Documenation](http://docs.strongloop.com/display/public/LB/Storage+component).
|
> Please see the [Storage Service Documenation](http://docs.strongloop.com/display/public/LB/Storage+component).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
See https://github.com/strongloop/loopback-example-storage.
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# EditorConfig helps developers define and maintain consistent
|
|
||||||
# coding styles between different editors and IDEs
|
|
||||||
# http://editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
|
@ -1,2 +0,0 @@
|
||||||
/client/
|
|
||||||
/node_modules/
|
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"node": true,
|
|
||||||
"esnext": true,
|
|
||||||
"bitwise": true,
|
|
||||||
"camelcase": true,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"eqnull": true,
|
|
||||||
"immed": true,
|
|
||||||
"indent": 2,
|
|
||||||
"latedef": "nofunc",
|
|
||||||
"newcap": true,
|
|
||||||
"nonew": true,
|
|
||||||
"noarg": true,
|
|
||||||
"quotmark": "single",
|
|
||||||
"regexp": true,
|
|
||||||
"undef": true,
|
|
||||||
"unused": false,
|
|
||||||
"trailing": true,
|
|
||||||
"sub": true,
|
|
||||||
"maxlen": 80
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
.idea
|
|
||||||
.project
|
|
||||||
*.sublime-*
|
|
||||||
.DS_Store
|
|
||||||
*.seed
|
|
||||||
*.log
|
|
||||||
*.csv
|
|
||||||
*.dat
|
|
||||||
*.out
|
|
||||||
*.pid
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
node_modules
|
|
||||||
coverage
|
|
||||||
*.tgz
|
|
||||||
*.xml
|
|
|
@ -1,3 +0,0 @@
|
||||||
## Client
|
|
||||||
|
|
||||||
This is the place for your application front-end files.
|
|
|
@ -1,685 +0,0 @@
|
||||||
/*
|
|
||||||
Angular File Upload v0.3.3.1
|
|
||||||
https://github.com/nervgh/angular-file-upload
|
|
||||||
*/
|
|
||||||
(function(angular, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
define('angular-file-upload', ['angular'], function(angular) {
|
|
||||||
return factory(angular);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return factory(angular);
|
|
||||||
}
|
|
||||||
}(angular || null, function(angular) {
|
|
||||||
var app = angular.module('angularFileUpload', []);
|
|
||||||
|
|
||||||
// It is attached to an element that catches the event drop file
|
|
||||||
app.directive('ngFileDrop', [ '$fileUploader', function ($fileUploader) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
// don't use drag-n-drop files in IE9, because not File API support
|
|
||||||
link: !$fileUploader.isHTML5 ? angular.noop : function (scope, element, attributes) {
|
|
||||||
element
|
|
||||||
.bind('drop', function (event) {
|
|
||||||
var dataTransfer = event.dataTransfer ?
|
|
||||||
event.dataTransfer :
|
|
||||||
event.originalEvent.dataTransfer; // jQuery fix;
|
|
||||||
if (!dataTransfer) return;
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
scope.$broadcast('file:removeoverclass');
|
|
||||||
scope.$emit('file:add', dataTransfer.files, scope.$eval(attributes.ngFileDrop));
|
|
||||||
})
|
|
||||||
.bind('dragover', function (event) {
|
|
||||||
var dataTransfer = event.dataTransfer ?
|
|
||||||
event.dataTransfer :
|
|
||||||
event.originalEvent.dataTransfer; // jQuery fix;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
dataTransfer.dropEffect = 'copy';
|
|
||||||
scope.$broadcast('file:addoverclass');
|
|
||||||
})
|
|
||||||
.bind('dragleave', function () {
|
|
||||||
scope.$broadcast('file:removeoverclass');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
// It is attached to an element which will be assigned to a class "ng-file-over" or ng-file-over="className"
|
|
||||||
app.directive('ngFileOver', function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
link: function (scope, element, attributes) {
|
|
||||||
scope.$on('file:addoverclass', function () {
|
|
||||||
element.addClass(attributes.ngFileOver || 'ng-file-over');
|
|
||||||
});
|
|
||||||
scope.$on('file:removeoverclass', function () {
|
|
||||||
element.removeClass(attributes.ngFileOver || 'ng-file-over');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// It is attached to <input type="file"> element like <ng-file-select="options">
|
|
||||||
app.directive('ngFileSelect', [ '$fileUploader', function ($fileUploader) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
link: function (scope, element, attributes) {
|
|
||||||
$fileUploader.isHTML5 || element.removeAttr('multiple');
|
|
||||||
|
|
||||||
element.bind('change', function () {
|
|
||||||
scope.$emit('file:add', $fileUploader.isHTML5 ? this.files : this, scope.$eval(attributes.ngFileSelect));
|
|
||||||
($fileUploader.isHTML5 && element.attr('multiple')) && element.prop('value', null);
|
|
||||||
});
|
|
||||||
|
|
||||||
element.prop('value', null); // FF fix
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
app.factory('$fileUploader', [ '$compile', '$rootScope', '$http', '$window', function ($compile, $rootScope, $http, $window) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a uploader
|
|
||||||
* @param {Object} params
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function Uploader(params) {
|
|
||||||
angular.extend(this, {
|
|
||||||
scope: $rootScope,
|
|
||||||
url: '/',
|
|
||||||
alias: 'file',
|
|
||||||
queue: [],
|
|
||||||
headers: {},
|
|
||||||
progress: null,
|
|
||||||
autoUpload: false,
|
|
||||||
removeAfterUpload: false,
|
|
||||||
method: 'POST',
|
|
||||||
filters: [],
|
|
||||||
formData: [],
|
|
||||||
isUploading: false,
|
|
||||||
_nextIndex: 0,
|
|
||||||
_timestamp: Date.now()
|
|
||||||
}, params);
|
|
||||||
|
|
||||||
// add the base filter
|
|
||||||
this.filters.unshift(this._filter);
|
|
||||||
|
|
||||||
this.scope.$on('file:add', function (event, items, options) {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.addToQueue(items, options);
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
this.bind('beforeupload', Item.prototype._beforeupload);
|
|
||||||
this.bind('in:progress', Item.prototype._progress);
|
|
||||||
this.bind('in:success', Item.prototype._success);
|
|
||||||
this.bind('in:cancel', Item.prototype._cancel);
|
|
||||||
this.bind('in:error', Item.prototype._error);
|
|
||||||
this.bind('in:complete', Item.prototype._complete);
|
|
||||||
this.bind('in:progress', this._progress);
|
|
||||||
this.bind('in:complete', this._complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
Uploader.prototype = {
|
|
||||||
/**
|
|
||||||
* Link to the constructor
|
|
||||||
*/
|
|
||||||
constructor: Uploader,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base filter. If returns "true" an item will be added to the queue
|
|
||||||
* @param {File|Input} item
|
|
||||||
* @returns {boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_filter: function (item) {
|
|
||||||
return angular.isElement(item) ? true : !!item.size;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a event handler
|
|
||||||
* @param {String} event
|
|
||||||
* @param {Function} handler
|
|
||||||
* @return {Function} unsubscribe function
|
|
||||||
*/
|
|
||||||
bind: function (event, handler) {
|
|
||||||
return this.scope.$on(this._timestamp + ':' + event, handler.bind(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers events
|
|
||||||
* @param {String} event
|
|
||||||
* @param {...*} [some]
|
|
||||||
*/
|
|
||||||
trigger: function (event, some) {
|
|
||||||
arguments[ 0 ] = this._timestamp + ':' + event;
|
|
||||||
this.scope.$broadcast.apply(this.scope, arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks a support the html5 uploader
|
|
||||||
* @returns {Boolean}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
isHTML5: !!($window.File && $window.FormData),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds items to the queue
|
|
||||||
* @param {FileList|File|HTMLInputElement} items
|
|
||||||
* @param {Object} [options]
|
|
||||||
*/
|
|
||||||
addToQueue: function (items, options) {
|
|
||||||
var length = this.queue.length;
|
|
||||||
var list = 'length' in items ? items : [items];
|
|
||||||
|
|
||||||
angular.forEach(list, function (file) {
|
|
||||||
// check a [File|HTMLInputElement]
|
|
||||||
var isValid = !this.filters.length ? true : this.filters.every(function (filter) {
|
|
||||||
return filter.call(this, file);
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// create new item
|
|
||||||
var item = new Item(angular.extend({
|
|
||||||
url: this.url,
|
|
||||||
alias: this.alias,
|
|
||||||
headers: angular.copy(this.headers),
|
|
||||||
formData: angular.copy(this.formData),
|
|
||||||
removeAfterUpload: this.removeAfterUpload,
|
|
||||||
method: this.method,
|
|
||||||
uploader: this,
|
|
||||||
file: file
|
|
||||||
}, options));
|
|
||||||
|
|
||||||
if (isValid) {
|
|
||||||
this.queue.push(item);
|
|
||||||
this.trigger('afteraddingfile', item);
|
|
||||||
} else {
|
|
||||||
this.trigger('whenaddingfilefailed', item);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
if (this.queue.length !== length) {
|
|
||||||
this.trigger('afteraddingall', this.queue);
|
|
||||||
this.progress = this._getTotalProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._render();
|
|
||||||
this.autoUpload && this.uploadAll();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove items from the queue. Remove last: index = -1
|
|
||||||
* @param {Item|Number} value
|
|
||||||
*/
|
|
||||||
removeFromQueue: function (value) {
|
|
||||||
var index = this.getIndexOfItem(value);
|
|
||||||
var item = this.queue[ index ];
|
|
||||||
item.isUploading && item.cancel();
|
|
||||||
this.queue.splice(index, 1);
|
|
||||||
item._destroy();
|
|
||||||
this.progress = this._getTotalProgress();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the queue
|
|
||||||
*/
|
|
||||||
clearQueue: function () {
|
|
||||||
this.queue.forEach(function (item) {
|
|
||||||
item.isUploading && item.cancel();
|
|
||||||
item._destroy();
|
|
||||||
}, this);
|
|
||||||
this.queue.length = 0;
|
|
||||||
this.progress = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a index of item from the queue
|
|
||||||
* @param {Item|Number} value
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
getIndexOfItem: function (value) {
|
|
||||||
return angular.isObject(value) ? this.queue.indexOf(value) : value;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns not uploaded items
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
getNotUploadedItems: function () {
|
|
||||||
return this.queue.filter(function (item) {
|
|
||||||
return !item.isUploaded;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns items ready for upload
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
getReadyItems: function() {
|
|
||||||
return this.queue
|
|
||||||
.filter(function(item) {
|
|
||||||
return item.isReady && !item.isUploading;
|
|
||||||
})
|
|
||||||
.sort(function(item1, item2) {
|
|
||||||
return item1.index - item2.index;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uploads a item from the queue
|
|
||||||
* @param {Item|Number} value
|
|
||||||
*/
|
|
||||||
uploadItem: function (value) {
|
|
||||||
var index = this.getIndexOfItem(value);
|
|
||||||
var item = this.queue[ index ];
|
|
||||||
var transport = this.isHTML5 ? '_xhrTransport' : '_iframeTransport';
|
|
||||||
|
|
||||||
item.index = item.index || this._nextIndex++;
|
|
||||||
item.isReady = true;
|
|
||||||
|
|
||||||
if (this.isUploading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isUploading = true;
|
|
||||||
this[ transport ](item);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels uploading of item from the queue
|
|
||||||
* @param {Item|Number} value
|
|
||||||
*/
|
|
||||||
cancelItem: function(value) {
|
|
||||||
var index = this.getIndexOfItem(value);
|
|
||||||
var item = this.queue[ index ];
|
|
||||||
var prop = this.isHTML5 ? '_xhr' : '_form';
|
|
||||||
item[prop] && item[prop].abort();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uploads all not uploaded items of queue
|
|
||||||
*/
|
|
||||||
uploadAll: function () {
|
|
||||||
var items = this.getNotUploadedItems().filter(function(item) {
|
|
||||||
return !item.isUploading;
|
|
||||||
});
|
|
||||||
items.forEach(function(item) {
|
|
||||||
item.index = item.index || this._nextIndex++;
|
|
||||||
item.isReady = true;
|
|
||||||
}, this);
|
|
||||||
items.length && this.uploadItem(items[ 0 ]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels all uploads
|
|
||||||
*/
|
|
||||||
cancelAll: function() {
|
|
||||||
this.getNotUploadedItems().forEach(function(item) {
|
|
||||||
this.cancelItem(item);
|
|
||||||
}, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates angular scope
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_render: function() {
|
|
||||||
this.scope.$$phase || this.scope.$digest();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the total progress
|
|
||||||
* @param {Number} [value]
|
|
||||||
* @returns {Number}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_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);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'in:progress' handler
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_progress: function (event, item, progress) {
|
|
||||||
var result = this._getTotalProgress(progress);
|
|
||||||
this.trigger('progressall', result);
|
|
||||||
this.progress = result;
|
|
||||||
this._render();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'in:complete' handler
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_complete: function () {
|
|
||||||
var item = this.getReadyItems()[ 0 ];
|
|
||||||
this.isUploading = false;
|
|
||||||
|
|
||||||
if (angular.isDefined(item)) {
|
|
||||||
this.uploadItem(item);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.trigger('completeall', this.queue);
|
|
||||||
this.progress = this._getTotalProgress();
|
|
||||||
this._render();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The XMLHttpRequest transport
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_xhrTransport: function (item) {
|
|
||||||
var xhr = item._xhr = new XMLHttpRequest();
|
|
||||||
var form = new FormData();
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
this.trigger('beforeupload', item);
|
|
||||||
|
|
||||||
item.formData.forEach(function(obj) {
|
|
||||||
angular.forEach(obj, function(value, key) {
|
|
||||||
form.append(key, value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
form.append(item.alias, item.file);
|
|
||||||
|
|
||||||
xhr.upload.onprogress = function (event) {
|
|
||||||
var progress = event.lengthComputable ? event.loaded * 100 / event.total : 0;
|
|
||||||
that.trigger('in:progress', item, Math.round(progress));
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onload = function () {
|
|
||||||
var response = that._transformResponse(xhr.response);
|
|
||||||
var event = that._isSuccessCode(xhr.status) ? 'success' : 'error';
|
|
||||||
that.trigger('in:' + event, xhr, item, response);
|
|
||||||
that.trigger('in:complete', xhr, item, response);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onerror = function () {
|
|
||||||
that.trigger('in:error', xhr, item);
|
|
||||||
that.trigger('in:complete', xhr, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onabort = function () {
|
|
||||||
that.trigger('in:cancel', xhr, item);
|
|
||||||
that.trigger('in:complete', xhr, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open(item.method, item.url, true);
|
|
||||||
|
|
||||||
angular.forEach(item.headers, function (value, name) {
|
|
||||||
xhr.setRequestHeader(name, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.send(form);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The IFrame transport
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_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;
|
|
||||||
|
|
||||||
item._form && item._form.replaceWith(input); // remove old form
|
|
||||||
item._form = form; // save link to new form
|
|
||||||
|
|
||||||
this.trigger('beforeupload', item);
|
|
||||||
|
|
||||||
input.prop('name', item.alias);
|
|
||||||
|
|
||||||
item.formData.forEach(function(obj) {
|
|
||||||
angular.forEach(obj, function(value, key) {
|
|
||||||
form.append(angular.element('<input type="hidden" name="' + key + '" value="' + value + '" />'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
form.prop({
|
|
||||||
action: item.url,
|
|
||||||
method: item.method,
|
|
||||||
target: iframe.prop('name'),
|
|
||||||
enctype: 'multipart/form-data',
|
|
||||||
encoding: 'multipart/form-data' // old IE
|
|
||||||
});
|
|
||||||
|
|
||||||
iframe.bind('load', function () {
|
|
||||||
// fixed angular.contents() for iframes
|
|
||||||
var html = iframe[0].contentDocument.body.innerHTML;
|
|
||||||
var xhr = { response: html, status: 200, dummy: true };
|
|
||||||
var response = that._transformResponse(xhr.response);
|
|
||||||
that.trigger('in:success', xhr, item, response);
|
|
||||||
that.trigger('in:complete', xhr, item, response);
|
|
||||||
});
|
|
||||||
|
|
||||||
form.abort = function() {
|
|
||||||
var xhr = { status: 0, dummy: true };
|
|
||||||
iframe.unbind('load').prop('src', 'javascript:false;');
|
|
||||||
form.replaceWith(input);
|
|
||||||
that.trigger('in:cancel', xhr, item);
|
|
||||||
that.trigger('in:complete', xhr, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
input.after(form);
|
|
||||||
form.append(input).append(iframe);
|
|
||||||
|
|
||||||
form[ 0 ].submit();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether upload successful
|
|
||||||
* @param {Number} status
|
|
||||||
* @returns {Boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_isSuccessCode: function(status) {
|
|
||||||
return (status >= 200 && status < 300) || status === 304;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms the server response
|
|
||||||
* @param {*} response
|
|
||||||
* @returns {*}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_transformResponse: function (response) {
|
|
||||||
$http.defaults.transformResponse.forEach(function (transformFn) {
|
|
||||||
response = transformFn(response);
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a item
|
|
||||||
* @param {Object} params
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function Item(params) {
|
|
||||||
// fix for old browsers
|
|
||||||
if (!Uploader.prototype.isHTML5) {
|
|
||||||
var input = angular.element(params.file);
|
|
||||||
var clone = $compile(input.clone())(params.uploader.scope);
|
|
||||||
var value = input.val();
|
|
||||||
|
|
||||||
params.file = {
|
|
||||||
lastModifiedDate: null,
|
|
||||||
size: null,
|
|
||||||
type: 'like/' + value.slice(value.lastIndexOf('.') + 1).toLowerCase(),
|
|
||||||
name: value.slice(value.lastIndexOf('/') + value.lastIndexOf('\\') + 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
params._input = input;
|
|
||||||
clone.prop('value', null); // FF fix
|
|
||||||
input.css('display', 'none').after(clone); // remove jquery dependency
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.extend(this, {
|
|
||||||
isReady: false,
|
|
||||||
isUploading: false,
|
|
||||||
isUploaded: false,
|
|
||||||
isSuccess: false,
|
|
||||||
isCancel: false,
|
|
||||||
isError: false,
|
|
||||||
progress: null,
|
|
||||||
index: null
|
|
||||||
}, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Item.prototype = {
|
|
||||||
/**
|
|
||||||
* Link to the constructor
|
|
||||||
*/
|
|
||||||
constructor: Item,
|
|
||||||
/**
|
|
||||||
* Removes a item
|
|
||||||
*/
|
|
||||||
remove: function () {
|
|
||||||
this.uploader.removeFromQueue(this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Uploads a item
|
|
||||||
*/
|
|
||||||
upload: function () {
|
|
||||||
this.uploader.uploadItem(this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Cancels uploading
|
|
||||||
*/
|
|
||||||
cancel: function() {
|
|
||||||
this.uploader.cancelItem(this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Destroys form and input
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_destroy: function() {
|
|
||||||
this._form && this._form.remove();
|
|
||||||
this._input && this._input.remove();
|
|
||||||
delete this._form;
|
|
||||||
delete this._input;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'beforeupload' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {Item} item
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_beforeupload: function (event, item) {
|
|
||||||
item.isReady = true;
|
|
||||||
item.isUploading = true;
|
|
||||||
item.isUploaded = false;
|
|
||||||
item.isSuccess = false;
|
|
||||||
item.isCancel = false;
|
|
||||||
item.isError = false;
|
|
||||||
item.progress = 0;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:progress' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {Number} progress
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_progress: function (event, item, progress) {
|
|
||||||
item.progress = progress;
|
|
||||||
item.uploader.trigger('progress', item, progress);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:success' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {*} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_success: function (event, xhr, item, response) {
|
|
||||||
item.isReady = false;
|
|
||||||
item.isUploading = false;
|
|
||||||
item.isUploaded = true;
|
|
||||||
item.isSuccess = true;
|
|
||||||
item.isCancel = false;
|
|
||||||
item.isError = false;
|
|
||||||
item.progress = 100;
|
|
||||||
item.index = null;
|
|
||||||
item.uploader.trigger('success', xhr, item, response);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:cancel' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_cancel: function(event, xhr, item) {
|
|
||||||
item.isReady = false;
|
|
||||||
item.isUploading = false;
|
|
||||||
item.isUploaded = false;
|
|
||||||
item.isSuccess = false;
|
|
||||||
item.isCancel = true;
|
|
||||||
item.isError = false;
|
|
||||||
item.progress = 0;
|
|
||||||
item.index = null;
|
|
||||||
item.uploader.trigger('cancel', xhr, item);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:error' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {*} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_error: function (event, xhr, item, response) {
|
|
||||||
item.isReady = false;
|
|
||||||
item.isUploading = false;
|
|
||||||
item.isUploaded = true;
|
|
||||||
item.isSuccess = false;
|
|
||||||
item.isCancel = false;
|
|
||||||
item.isError = true;
|
|
||||||
item.progress = 100;
|
|
||||||
item.index = null;
|
|
||||||
item.uploader.trigger('error', xhr, item, response);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:complete' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {*} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_complete: function (event, xhr, item, response) {
|
|
||||||
item.uploader.trigger('complete', xhr, item, response);
|
|
||||||
item.removeAfterUpload && item.remove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
create: function (params) {
|
|
||||||
return new Uploader(params);
|
|
||||||
},
|
|
||||||
isHTML5: Uploader.prototype.isHTML5
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}));
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,94 +0,0 @@
|
||||||
angular.module('app', ['angularFileUpload'])
|
|
||||||
|
|
||||||
// The example of the full functionality
|
|
||||||
.controller('TestController',function ($scope, FileUploader) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// create a uploader with options
|
|
||||||
|
|
||||||
var uploader = $scope.uploader = new FileUploader({
|
|
||||||
scope: $scope, // to automatically update the html. Default: $rootScope
|
|
||||||
url: '/api/containers/container1/upload',
|
|
||||||
formData: [
|
|
||||||
{ key: 'value' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// ADDING FILTERS
|
|
||||||
uploader.filters.push({
|
|
||||||
name: 'filterName',
|
|
||||||
fn: function (item, options) { // second user filter
|
|
||||||
console.info('filter2');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// REGISTER HANDLERS
|
|
||||||
// --------------------
|
|
||||||
uploader.onAfterAddingFile = function(item) {
|
|
||||||
console.info('After adding a file', item);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onAfterAddingAll = function(items) {
|
|
||||||
console.info('After adding all files', items);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onWhenAddingFileFailed = function(item, filter, options) {
|
|
||||||
console.info('When adding a file failed', item);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onBeforeUploadItem = function(item) {
|
|
||||||
console.info('Before upload', item);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onProgressItem = function(item, progress) {
|
|
||||||
console.info('Progress: ' + progress, item);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onProgressAll = function(progress) {
|
|
||||||
console.info('Total progress: ' + progress);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onSuccessItem = function(item, response, status, headers) {
|
|
||||||
console.info('Success', response, status, headers);
|
|
||||||
$scope.$broadcast('uploadCompleted', item);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onErrorItem = function(item, response, status, headers) {
|
|
||||||
console.info('Error', response, status, headers);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onCancelItem = function(item, response, status, headers) {
|
|
||||||
console.info('Cancel', response, status);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onCompleteItem = function(item, response, status, headers) {
|
|
||||||
console.info('Complete', response, status, headers);
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
uploader.onCompleteAll = function() {
|
|
||||||
console.info('Complete all');
|
|
||||||
};
|
|
||||||
// --------------------
|
|
||||||
}
|
|
||||||
).controller('FilesController', function ($scope, $http) {
|
|
||||||
|
|
||||||
$scope.load = function () {
|
|
||||||
$http.get('/api/containers/container1/files').success(function (data) {
|
|
||||||
console.log(data);
|
|
||||||
$scope.files = data;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.delete = function (index, id) {
|
|
||||||
$http.delete('/api/containers/container1/files/' + encodeURIComponent(id)).success(function (data, status, headers) {
|
|
||||||
$scope.files.splice(index, 1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.$on('uploadCompleted', function(event) {
|
|
||||||
console.log('uploadCompleted event received');
|
|
||||||
$scope.load();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,208 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html id="ng-app" ng-app="app"> <!-- id="ng-app" IE<8 -->
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>LoopBack Storage Service Demo</title>
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"/>
|
|
||||||
|
|
||||||
<!-- Fix for old browsers -->
|
|
||||||
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
|
|
||||||
|
|
||||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
|
|
||||||
|
|
||||||
<!--<script src="../bower_components/angular/angular.js"></script>-->
|
|
||||||
<script src="http://code.angularjs.org/1.4.4/angular.min.js"></script>
|
|
||||||
<script src="angular-file-upload.min.js"></script>
|
|
||||||
<script src="controllers.js"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.my-drop-zone {
|
|
||||||
border: dotted 3px lightgray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nv-file-over {
|
|
||||||
border: dotted 3px red;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default class applied to drop zones on over */
|
|
||||||
.another-file-over-class {
|
|
||||||
border: dotted 3px green;
|
|
||||||
}
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<!-- 1. nv-file-drop | nv-file-drop="options" -->
|
|
||||||
<body ng-controller="TestController" nv-file-drop uploader="uploader">
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="navbar navbar-default">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<a class="navbar-brand"
|
|
||||||
href="https://github.com/strongloop/loopback-component-storage">LoopBack
|
|
||||||
Storage Service</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-md-3">
|
|
||||||
|
|
||||||
<img ng-src="{{image}}"> </img>
|
|
||||||
|
|
||||||
<h3>Select files</h3>
|
|
||||||
|
|
||||||
<div ng-show="uploader.isHTML5">
|
|
||||||
<!-- 3. nv-file-over | nv-file-over="className" -->
|
|
||||||
<div class="well my-drop-zone" nv-file-over uploader="uploader">
|
|
||||||
Base drop zone
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Example: nv-file-drop | nv-file-drop="options" -->
|
|
||||||
<div class="well my-drop-zone" nv-file-drop="{ url: '/foo' } "
|
|
||||||
nv-file-over="another-file-over-class" uploader="uploader">
|
|
||||||
Another drop zone with its own settings
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 2. nv-file-select | nv-file-select="options" -->
|
|
||||||
Multiple
|
|
||||||
<input nv-file-select uploader="uploader" type="file" multiple/><br/>
|
|
||||||
|
|
||||||
Single
|
|
||||||
<input nv-file-select uploader="uploader" type="file"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-9" style="margin-bottom: 40px">
|
|
||||||
|
|
||||||
<h3>Upload queue</h3>
|
|
||||||
|
|
||||||
<p>Queue length: {{ uploader.queue.length }}</p>
|
|
||||||
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th width="50%">Name</th>
|
|
||||||
<th ng-show="uploader.isHTML5">Size</th>
|
|
||||||
<th ng-show="uploader.isHTML5">Progress</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="item in uploader.queue">
|
|
||||||
<td><strong>{{ item.file.name }}</strong></td>
|
|
||||||
<td ng-show="uploader.isHTML5" nowrap>{{
|
|
||||||
item.file.size/1024/1024|number:2 }} MB
|
|
||||||
</td>
|
|
||||||
<td ng-show="uploader.isHTML5">
|
|
||||||
<div class="progress" style="margin-bottom: 0;">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
|
||||||
ng-style="{ 'width': item.progress + '%' }"></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<span ng-show="item.isSuccess"><i
|
|
||||||
class="glyphicon glyphicon-ok"></i></span>
|
|
||||||
<span ng-show="item.isCancel"><i
|
|
||||||
class="glyphicon glyphicon-ban-circle"></i></span>
|
|
||||||
<span ng-show="item.isError"><i
|
|
||||||
class="glyphicon glyphicon-remove"></i></span>
|
|
||||||
</td>
|
|
||||||
<td nowrap>
|
|
||||||
<button type="button" class="btn btn-success btn-xs"
|
|
||||||
ng-click="item.upload()"
|
|
||||||
ng-disabled="item.isReady || item.isUploading || item.isSuccess">
|
|
||||||
<span class="glyphicon glyphicon-upload"></span>
|
|
||||||
Upload
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-warning btn-xs"
|
|
||||||
ng-click="item.cancel()"
|
|
||||||
ng-disabled="!item.isUploading">
|
|
||||||
<span class="glyphicon glyphicon-ban-circle"></span>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-danger btn-xs"
|
|
||||||
ng-click="item.remove()">
|
|
||||||
<span class="glyphicon glyphicon-trash"></span>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
Queue progress:
|
|
||||||
|
|
||||||
<div class="progress" style="">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
|
||||||
ng-style="{ 'width': uploader.progress + '%' }"></div>
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
<button type="button" class="btn btn-success btn-s"
|
|
||||||
ng-click="uploader.uploadAll()"
|
|
||||||
ng-disabled="!uploader.getNotUploadedItems().length">
|
|
||||||
<span class="glyphicon glyphicon-upload"></span> Upload all
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-warning btn-s"
|
|
||||||
ng-click="uploader.cancelAll()"
|
|
||||||
ng-disabled="!uploader.isUploading">
|
|
||||||
<span class="glyphicon glyphicon-ban-circle"></span> Cancel
|
|
||||||
all
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-danger btn-s"
|
|
||||||
ng-click="uploader.clearQueue()"
|
|
||||||
ng-disabled="!uploader.queue.length">
|
|
||||||
<span class="glyphicon glyphicon-trash"></span> Remove all
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-9" style="margin-bottom: 40px"
|
|
||||||
ng-controller="FilesController" data-ng-init="load()">
|
|
||||||
|
|
||||||
<h3>Files in the container</h3>
|
|
||||||
|
|
||||||
<table class="table">
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="file in files">
|
|
||||||
<td>
|
|
||||||
<a href="/api/containers/container1/download/{{file.name}}"><strong>{{
|
|
||||||
file.name }}</strong></a></td>
|
|
||||||
<td>
|
|
||||||
<td>
|
|
||||||
<button type="button" class="btn btn-danger btn-xs"
|
|
||||||
ng-click="delete($index, file.name)"
|
|
||||||
title="Delete the file">
|
|
||||||
<span class="glyphicon glyphicon-trash"></span>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"name": "loopback-example-storage",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"main": "server/server.js",
|
|
||||||
"scripts": {
|
|
||||||
"pretest": "jshint ."
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"compression": "^1.0.3",
|
|
||||||
"errorhandler": "^1.1.1",
|
|
||||||
"loopback": "^2.0.0",
|
|
||||||
"loopback-boot": "^2.0.0",
|
|
||||||
"loopback-component-explorer": "^2.1.0",
|
|
||||||
"loopback-component-storage": "^1.5.0",
|
|
||||||
"loopback-datasource-juggler": "^2.7.0",
|
|
||||||
"serve-favicon": "^2.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
module.exports = function enableAuthentication(server) {
|
|
||||||
// enable authentication
|
|
||||||
server.enableAuth();
|
|
||||||
};
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"loopback-component-explorer": {
|
|
||||||
"mountPath": "/explorer"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"legacyExplorer": false,
|
|
||||||
"restApiRoot": "/api",
|
|
||||||
"host": "0.0.0.0",
|
|
||||||
"port": 3000,
|
|
||||||
"url": "http://localhost:3000/"
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"db": {
|
|
||||||
"name": "db",
|
|
||||||
"connector": "memory"
|
|
||||||
},
|
|
||||||
"storage": {
|
|
||||||
"name": "storage",
|
|
||||||
"connector": "loopback-component-storage",
|
|
||||||
"provider": "filesystem",
|
|
||||||
"root": "./server/storage"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
{
|
|
||||||
"initial:before": {
|
|
||||||
"loopback#favicon": {},
|
|
||||||
"loopback#compress": {}
|
|
||||||
},
|
|
||||||
"initial": {
|
|
||||||
"compression": {}
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
},
|
|
||||||
"parse": {
|
|
||||||
},
|
|
||||||
"routes": {
|
|
||||||
"loopback#rest": {
|
|
||||||
"paths": ["${restApiRoot}"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"loopback#static": {
|
|
||||||
"params": "$!../client"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"final": {
|
|
||||||
"loopback#urlNotFound": {}
|
|
||||||
},
|
|
||||||
"final:after": {
|
|
||||||
"errorhandler": {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
{
|
|
||||||
"_meta": {
|
|
||||||
"sources": [
|
|
||||||
"../common/models",
|
|
||||||
"./models"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"User": {
|
|
||||||
"dataSource": "db"
|
|
||||||
},
|
|
||||||
"AccessToken": {
|
|
||||||
"dataSource": "db",
|
|
||||||
"public": false
|
|
||||||
},
|
|
||||||
"ACL": {
|
|
||||||
"dataSource": "db",
|
|
||||||
"public": false
|
|
||||||
},
|
|
||||||
"RoleMapping": {
|
|
||||||
"dataSource": "db",
|
|
||||||
"public": false
|
|
||||||
},
|
|
||||||
"Role": {
|
|
||||||
"dataSource": "db",
|
|
||||||
"public": false
|
|
||||||
},
|
|
||||||
"container": {
|
|
||||||
"dataSource": "storage",
|
|
||||||
"public": true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = function(Container) {
|
|
||||||
|
|
||||||
};
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"name": "container",
|
|
||||||
"base": "Model",
|
|
||||||
"properties": {},
|
|
||||||
"validations": [],
|
|
||||||
"relations": {},
|
|
||||||
"acls": [],
|
|
||||||
"methods": []
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"rackspace": {
|
|
||||||
"username": "your-rackspace-username",
|
|
||||||
"apiKey": "your-rackspace-api-key",
|
|
||||||
"region": "DFW"
|
|
||||||
},
|
|
||||||
"amazon": {
|
|
||||||
"key": "your-amazon-key",
|
|
||||||
"keyId": "your-amazon-key-id"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
var loopback = require('loopback');
|
|
||||||
var boot = require('loopback-boot');
|
|
||||||
|
|
||||||
var app = module.exports = loopback();
|
|
||||||
|
|
||||||
app.start = function() {
|
|
||||||
// start the web server
|
|
||||||
return app.listen(function() {
|
|
||||||
app.emit('started');
|
|
||||||
var baseUrl = app.get('url').replace(/\/$/, '');
|
|
||||||
console.log('Web server listening at: %s', baseUrl);
|
|
||||||
if (app.get('loopback-component-explorer')) {
|
|
||||||
var explorerPath = app.get('loopback-component-explorer').mountPath;
|
|
||||||
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bootstrap the application, configure models, datasources and middleware.
|
|
||||||
// Sub-apps like REST API are mounted via boot scripts.
|
|
||||||
boot(app, __dirname, function(err) {
|
|
||||||
if (err) throw err;
|
|
||||||
|
|
||||||
// start the server if `$ node server.js`
|
|
||||||
if (require.main === module)
|
|
||||||
app.start();
|
|
||||||
});
|
|
|
@ -1 +0,0 @@
|
||||||
Hello....
|
|
|
@ -1 +0,0 @@
|
||||||
Hello....
|
|
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
|
@ -1 +0,0 @@
|
||||||
Upload test
|
|
|
@ -1 +0,0 @@
|
||||||
Hello....
|
|
|
@ -1,57 +0,0 @@
|
||||||
var StorageService = require('../').StorageService;
|
|
||||||
var path = require('path');
|
|
||||||
var providers = null;
|
|
||||||
try {
|
|
||||||
providers = require('./providers-private.json');
|
|
||||||
} catch(err) {
|
|
||||||
providers = require('./providers.json');
|
|
||||||
}
|
|
||||||
|
|
||||||
function listContainersAndFiles(ss) {
|
|
||||||
ss.getContainers(function (err, containers) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log('----------- %s (%d) ---------------', ss.provider, containers.length);
|
|
||||||
containers.forEach(function (c) {
|
|
||||||
console.log('[%s] %s/', ss.provider, c.name);
|
|
||||||
c.getFiles(function (err, files) {
|
|
||||||
files.forEach(function (f) {
|
|
||||||
console.log('[%s] ... %s', ss.provider, f.name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var rs = new StorageService({
|
|
||||||
provider: 'rackspace',
|
|
||||||
username: providers.rackspace.username,
|
|
||||||
apiKey: providers.rackspace.apiKey,
|
|
||||||
region: providers.rackspace.region
|
|
||||||
});
|
|
||||||
|
|
||||||
listContainersAndFiles(rs);
|
|
||||||
|
|
||||||
var s3 = new StorageService({
|
|
||||||
provider: 'amazon',
|
|
||||||
key: providers.amazon.key,
|
|
||||||
keyId: providers.amazon.keyId
|
|
||||||
});
|
|
||||||
|
|
||||||
listContainersAndFiles(s3);
|
|
||||||
|
|
||||||
|
|
||||||
var fs = require('fs');
|
|
||||||
var path = require('path');
|
|
||||||
var stream = s3.uploadStream('con1', 'test.jpg');
|
|
||||||
fs.createReadStream(path.join(__dirname, 'test.jpg')).pipe(stream);
|
|
||||||
|
|
||||||
var local = StorageService({
|
|
||||||
provider: 'filesystem',
|
|
||||||
root: path.join(__dirname, 'storage')
|
|
||||||
});
|
|
||||||
|
|
||||||
listContainersAndFiles(local);
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"rackspace": {
|
|
||||||
"username": "your-rackspace-username",
|
|
||||||
"apiKey": "your-rackspace-api-key",
|
|
||||||
"region": "DFW"
|
|
||||||
},
|
|
||||||
"amazon": {
|
|
||||||
"key": "your-amazon-key",
|
|
||||||
"keyId": "your-amazon-key-id"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,685 +0,0 @@
|
||||||
/*
|
|
||||||
Angular File Upload v0.3.3.1
|
|
||||||
https://github.com/nervgh/angular-file-upload
|
|
||||||
*/
|
|
||||||
(function(angular, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
define('angular-file-upload', ['angular'], function(angular) {
|
|
||||||
return factory(angular);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return factory(angular);
|
|
||||||
}
|
|
||||||
}(angular || null, function(angular) {
|
|
||||||
var app = angular.module('angularFileUpload', []);
|
|
||||||
|
|
||||||
// It is attached to an element that catches the event drop file
|
|
||||||
app.directive('ngFileDrop', [ '$fileUploader', function ($fileUploader) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
// don't use drag-n-drop files in IE9, because not File API support
|
|
||||||
link: !$fileUploader.isHTML5 ? angular.noop : function (scope, element, attributes) {
|
|
||||||
element
|
|
||||||
.bind('drop', function (event) {
|
|
||||||
var dataTransfer = event.dataTransfer ?
|
|
||||||
event.dataTransfer :
|
|
||||||
event.originalEvent.dataTransfer; // jQuery fix;
|
|
||||||
if (!dataTransfer) return;
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
scope.$broadcast('file:removeoverclass');
|
|
||||||
scope.$emit('file:add', dataTransfer.files, scope.$eval(attributes.ngFileDrop));
|
|
||||||
})
|
|
||||||
.bind('dragover', function (event) {
|
|
||||||
var dataTransfer = event.dataTransfer ?
|
|
||||||
event.dataTransfer :
|
|
||||||
event.originalEvent.dataTransfer; // jQuery fix;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
dataTransfer.dropEffect = 'copy';
|
|
||||||
scope.$broadcast('file:addoverclass');
|
|
||||||
})
|
|
||||||
.bind('dragleave', function () {
|
|
||||||
scope.$broadcast('file:removeoverclass');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
// It is attached to an element which will be assigned to a class "ng-file-over" or ng-file-over="className"
|
|
||||||
app.directive('ngFileOver', function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
link: function (scope, element, attributes) {
|
|
||||||
scope.$on('file:addoverclass', function () {
|
|
||||||
element.addClass(attributes.ngFileOver || 'ng-file-over');
|
|
||||||
});
|
|
||||||
scope.$on('file:removeoverclass', function () {
|
|
||||||
element.removeClass(attributes.ngFileOver || 'ng-file-over');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// It is attached to <input type="file"> element like <ng-file-select="options">
|
|
||||||
app.directive('ngFileSelect', [ '$fileUploader', function ($fileUploader) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
link: function (scope, element, attributes) {
|
|
||||||
$fileUploader.isHTML5 || element.removeAttr('multiple');
|
|
||||||
|
|
||||||
element.bind('change', function () {
|
|
||||||
scope.$emit('file:add', $fileUploader.isHTML5 ? this.files : this, scope.$eval(attributes.ngFileSelect));
|
|
||||||
($fileUploader.isHTML5 && element.attr('multiple')) && element.prop('value', null);
|
|
||||||
});
|
|
||||||
|
|
||||||
element.prop('value', null); // FF fix
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
app.factory('$fileUploader', [ '$compile', '$rootScope', '$http', '$window', function ($compile, $rootScope, $http, $window) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a uploader
|
|
||||||
* @param {Object} params
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function Uploader(params) {
|
|
||||||
angular.extend(this, {
|
|
||||||
scope: $rootScope,
|
|
||||||
url: '/',
|
|
||||||
alias: 'file',
|
|
||||||
queue: [],
|
|
||||||
headers: {},
|
|
||||||
progress: null,
|
|
||||||
autoUpload: false,
|
|
||||||
removeAfterUpload: false,
|
|
||||||
method: 'POST',
|
|
||||||
filters: [],
|
|
||||||
formData: [],
|
|
||||||
isUploading: false,
|
|
||||||
_nextIndex: 0,
|
|
||||||
_timestamp: Date.now()
|
|
||||||
}, params);
|
|
||||||
|
|
||||||
// add the base filter
|
|
||||||
this.filters.unshift(this._filter);
|
|
||||||
|
|
||||||
this.scope.$on('file:add', function (event, items, options) {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.addToQueue(items, options);
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
this.bind('beforeupload', Item.prototype._beforeupload);
|
|
||||||
this.bind('in:progress', Item.prototype._progress);
|
|
||||||
this.bind('in:success', Item.prototype._success);
|
|
||||||
this.bind('in:cancel', Item.prototype._cancel);
|
|
||||||
this.bind('in:error', Item.prototype._error);
|
|
||||||
this.bind('in:complete', Item.prototype._complete);
|
|
||||||
this.bind('in:progress', this._progress);
|
|
||||||
this.bind('in:complete', this._complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
Uploader.prototype = {
|
|
||||||
/**
|
|
||||||
* Link to the constructor
|
|
||||||
*/
|
|
||||||
constructor: Uploader,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base filter. If returns "true" an item will be added to the queue
|
|
||||||
* @param {File|Input} item
|
|
||||||
* @returns {boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_filter: function (item) {
|
|
||||||
return angular.isElement(item) ? true : !!item.size;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a event handler
|
|
||||||
* @param {String} event
|
|
||||||
* @param {Function} handler
|
|
||||||
* @return {Function} unsubscribe function
|
|
||||||
*/
|
|
||||||
bind: function (event, handler) {
|
|
||||||
return this.scope.$on(this._timestamp + ':' + event, handler.bind(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers events
|
|
||||||
* @param {String} event
|
|
||||||
* @param {...*} [some]
|
|
||||||
*/
|
|
||||||
trigger: function (event, some) {
|
|
||||||
arguments[ 0 ] = this._timestamp + ':' + event;
|
|
||||||
this.scope.$broadcast.apply(this.scope, arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks a support the html5 uploader
|
|
||||||
* @returns {Boolean}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
isHTML5: !!($window.File && $window.FormData),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds items to the queue
|
|
||||||
* @param {FileList|File|HTMLInputElement} items
|
|
||||||
* @param {Object} [options]
|
|
||||||
*/
|
|
||||||
addToQueue: function (items, options) {
|
|
||||||
var length = this.queue.length;
|
|
||||||
var list = 'length' in items ? items : [items];
|
|
||||||
|
|
||||||
angular.forEach(list, function (file) {
|
|
||||||
// check a [File|HTMLInputElement]
|
|
||||||
var isValid = !this.filters.length ? true : this.filters.every(function (filter) {
|
|
||||||
return filter.call(this, file);
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// create new item
|
|
||||||
var item = new Item(angular.extend({
|
|
||||||
url: this.url,
|
|
||||||
alias: this.alias,
|
|
||||||
headers: angular.copy(this.headers),
|
|
||||||
formData: angular.copy(this.formData),
|
|
||||||
removeAfterUpload: this.removeAfterUpload,
|
|
||||||
method: this.method,
|
|
||||||
uploader: this,
|
|
||||||
file: file
|
|
||||||
}, options));
|
|
||||||
|
|
||||||
if (isValid) {
|
|
||||||
this.queue.push(item);
|
|
||||||
this.trigger('afteraddingfile', item);
|
|
||||||
} else {
|
|
||||||
this.trigger('whenaddingfilefailed', item);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
if (this.queue.length !== length) {
|
|
||||||
this.trigger('afteraddingall', this.queue);
|
|
||||||
this.progress = this._getTotalProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._render();
|
|
||||||
this.autoUpload && this.uploadAll();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove items from the queue. Remove last: index = -1
|
|
||||||
* @param {Item|Number} value
|
|
||||||
*/
|
|
||||||
removeFromQueue: function (value) {
|
|
||||||
var index = this.getIndexOfItem(value);
|
|
||||||
var item = this.queue[ index ];
|
|
||||||
item.isUploading && item.cancel();
|
|
||||||
this.queue.splice(index, 1);
|
|
||||||
item._destroy();
|
|
||||||
this.progress = this._getTotalProgress();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the queue
|
|
||||||
*/
|
|
||||||
clearQueue: function () {
|
|
||||||
this.queue.forEach(function (item) {
|
|
||||||
item.isUploading && item.cancel();
|
|
||||||
item._destroy();
|
|
||||||
}, this);
|
|
||||||
this.queue.length = 0;
|
|
||||||
this.progress = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a index of item from the queue
|
|
||||||
* @param {Item|Number} value
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
getIndexOfItem: function (value) {
|
|
||||||
return angular.isObject(value) ? this.queue.indexOf(value) : value;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns not uploaded items
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
getNotUploadedItems: function () {
|
|
||||||
return this.queue.filter(function (item) {
|
|
||||||
return !item.isUploaded;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns items ready for upload
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
getReadyItems: function() {
|
|
||||||
return this.queue
|
|
||||||
.filter(function(item) {
|
|
||||||
return item.isReady && !item.isUploading;
|
|
||||||
})
|
|
||||||
.sort(function(item1, item2) {
|
|
||||||
return item1.index - item2.index;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uploads a item from the queue
|
|
||||||
* @param {Item|Number} value
|
|
||||||
*/
|
|
||||||
uploadItem: function (value) {
|
|
||||||
var index = this.getIndexOfItem(value);
|
|
||||||
var item = this.queue[ index ];
|
|
||||||
var transport = this.isHTML5 ? '_xhrTransport' : '_iframeTransport';
|
|
||||||
|
|
||||||
item.index = item.index || this._nextIndex++;
|
|
||||||
item.isReady = true;
|
|
||||||
|
|
||||||
if (this.isUploading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isUploading = true;
|
|
||||||
this[ transport ](item);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels uploading of item from the queue
|
|
||||||
* @param {Item|Number} value
|
|
||||||
*/
|
|
||||||
cancelItem: function(value) {
|
|
||||||
var index = this.getIndexOfItem(value);
|
|
||||||
var item = this.queue[ index ];
|
|
||||||
var prop = this.isHTML5 ? '_xhr' : '_form';
|
|
||||||
item[prop] && item[prop].abort();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uploads all not uploaded items of queue
|
|
||||||
*/
|
|
||||||
uploadAll: function () {
|
|
||||||
var items = this.getNotUploadedItems().filter(function(item) {
|
|
||||||
return !item.isUploading;
|
|
||||||
});
|
|
||||||
items.forEach(function(item) {
|
|
||||||
item.index = item.index || this._nextIndex++;
|
|
||||||
item.isReady = true;
|
|
||||||
}, this);
|
|
||||||
items.length && this.uploadItem(items[ 0 ]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels all uploads
|
|
||||||
*/
|
|
||||||
cancelAll: function() {
|
|
||||||
this.getNotUploadedItems().forEach(function(item) {
|
|
||||||
this.cancelItem(item);
|
|
||||||
}, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates angular scope
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_render: function() {
|
|
||||||
this.scope.$$phase || this.scope.$digest();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the total progress
|
|
||||||
* @param {Number} [value]
|
|
||||||
* @returns {Number}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_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);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'in:progress' handler
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_progress: function (event, item, progress) {
|
|
||||||
var result = this._getTotalProgress(progress);
|
|
||||||
this.trigger('progressall', result);
|
|
||||||
this.progress = result;
|
|
||||||
this._render();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'in:complete' handler
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_complete: function () {
|
|
||||||
var item = this.getReadyItems()[ 0 ];
|
|
||||||
this.isUploading = false;
|
|
||||||
|
|
||||||
if (angular.isDefined(item)) {
|
|
||||||
this.uploadItem(item);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.trigger('completeall', this.queue);
|
|
||||||
this.progress = this._getTotalProgress();
|
|
||||||
this._render();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The XMLHttpRequest transport
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_xhrTransport: function (item) {
|
|
||||||
var xhr = item._xhr = new XMLHttpRequest();
|
|
||||||
var form = new FormData();
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
this.trigger('beforeupload', item);
|
|
||||||
|
|
||||||
item.formData.forEach(function(obj) {
|
|
||||||
angular.forEach(obj, function(value, key) {
|
|
||||||
form.append(key, value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
form.append(item.alias, item.file);
|
|
||||||
|
|
||||||
xhr.upload.onprogress = function (event) {
|
|
||||||
var progress = event.lengthComputable ? event.loaded * 100 / event.total : 0;
|
|
||||||
that.trigger('in:progress', item, Math.round(progress));
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onload = function () {
|
|
||||||
var response = that._transformResponse(xhr.response);
|
|
||||||
var event = that._isSuccessCode(xhr.status) ? 'success' : 'error';
|
|
||||||
that.trigger('in:' + event, xhr, item, response);
|
|
||||||
that.trigger('in:complete', xhr, item, response);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onerror = function () {
|
|
||||||
that.trigger('in:error', xhr, item);
|
|
||||||
that.trigger('in:complete', xhr, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onabort = function () {
|
|
||||||
that.trigger('in:cancel', xhr, item);
|
|
||||||
that.trigger('in:complete', xhr, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open(item.method, item.url, true);
|
|
||||||
|
|
||||||
angular.forEach(item.headers, function (value, name) {
|
|
||||||
xhr.setRequestHeader(name, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.send(form);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The IFrame transport
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_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;
|
|
||||||
|
|
||||||
item._form && item._form.replaceWith(input); // remove old form
|
|
||||||
item._form = form; // save link to new form
|
|
||||||
|
|
||||||
this.trigger('beforeupload', item);
|
|
||||||
|
|
||||||
input.prop('name', item.alias);
|
|
||||||
|
|
||||||
item.formData.forEach(function(obj) {
|
|
||||||
angular.forEach(obj, function(value, key) {
|
|
||||||
form.append(angular.element('<input type="hidden" name="' + key + '" value="' + value + '" />'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
form.prop({
|
|
||||||
action: item.url,
|
|
||||||
method: item.method,
|
|
||||||
target: iframe.prop('name'),
|
|
||||||
enctype: 'multipart/form-data',
|
|
||||||
encoding: 'multipart/form-data' // old IE
|
|
||||||
});
|
|
||||||
|
|
||||||
iframe.bind('load', function () {
|
|
||||||
// fixed angular.contents() for iframes
|
|
||||||
var html = iframe[0].contentDocument.body.innerHTML;
|
|
||||||
var xhr = { response: html, status: 200, dummy: true };
|
|
||||||
var response = that._transformResponse(xhr.response);
|
|
||||||
that.trigger('in:success', xhr, item, response);
|
|
||||||
that.trigger('in:complete', xhr, item, response);
|
|
||||||
});
|
|
||||||
|
|
||||||
form.abort = function() {
|
|
||||||
var xhr = { status: 0, dummy: true };
|
|
||||||
iframe.unbind('load').prop('src', 'javascript:false;');
|
|
||||||
form.replaceWith(input);
|
|
||||||
that.trigger('in:cancel', xhr, item);
|
|
||||||
that.trigger('in:complete', xhr, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
input.after(form);
|
|
||||||
form.append(input).append(iframe);
|
|
||||||
|
|
||||||
form[ 0 ].submit();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether upload successful
|
|
||||||
* @param {Number} status
|
|
||||||
* @returns {Boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_isSuccessCode: function(status) {
|
|
||||||
return (status >= 200 && status < 300) || status === 304;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms the server response
|
|
||||||
* @param {*} response
|
|
||||||
* @returns {*}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_transformResponse: function (response) {
|
|
||||||
$http.defaults.transformResponse.forEach(function (transformFn) {
|
|
||||||
response = transformFn(response);
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a item
|
|
||||||
* @param {Object} params
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function Item(params) {
|
|
||||||
// fix for old browsers
|
|
||||||
if (!Uploader.prototype.isHTML5) {
|
|
||||||
var input = angular.element(params.file);
|
|
||||||
var clone = $compile(input.clone())(params.uploader.scope);
|
|
||||||
var value = input.val();
|
|
||||||
|
|
||||||
params.file = {
|
|
||||||
lastModifiedDate: null,
|
|
||||||
size: null,
|
|
||||||
type: 'like/' + value.slice(value.lastIndexOf('.') + 1).toLowerCase(),
|
|
||||||
name: value.slice(value.lastIndexOf('/') + value.lastIndexOf('\\') + 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
params._input = input;
|
|
||||||
clone.prop('value', null); // FF fix
|
|
||||||
input.css('display', 'none').after(clone); // remove jquery dependency
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.extend(this, {
|
|
||||||
isReady: false,
|
|
||||||
isUploading: false,
|
|
||||||
isUploaded: false,
|
|
||||||
isSuccess: false,
|
|
||||||
isCancel: false,
|
|
||||||
isError: false,
|
|
||||||
progress: null,
|
|
||||||
index: null
|
|
||||||
}, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Item.prototype = {
|
|
||||||
/**
|
|
||||||
* Link to the constructor
|
|
||||||
*/
|
|
||||||
constructor: Item,
|
|
||||||
/**
|
|
||||||
* Removes a item
|
|
||||||
*/
|
|
||||||
remove: function () {
|
|
||||||
this.uploader.removeFromQueue(this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Uploads a item
|
|
||||||
*/
|
|
||||||
upload: function () {
|
|
||||||
this.uploader.uploadItem(this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Cancels uploading
|
|
||||||
*/
|
|
||||||
cancel: function() {
|
|
||||||
this.uploader.cancelItem(this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Destroys form and input
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_destroy: function() {
|
|
||||||
this._form && this._form.remove();
|
|
||||||
this._input && this._input.remove();
|
|
||||||
delete this._form;
|
|
||||||
delete this._input;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'beforeupload' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {Item} item
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_beforeupload: function (event, item) {
|
|
||||||
item.isReady = true;
|
|
||||||
item.isUploading = true;
|
|
||||||
item.isUploaded = false;
|
|
||||||
item.isSuccess = false;
|
|
||||||
item.isCancel = false;
|
|
||||||
item.isError = false;
|
|
||||||
item.progress = 0;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:progress' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {Number} progress
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_progress: function (event, item, progress) {
|
|
||||||
item.progress = progress;
|
|
||||||
item.uploader.trigger('progress', item, progress);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:success' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {*} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_success: function (event, xhr, item, response) {
|
|
||||||
item.isReady = false;
|
|
||||||
item.isUploading = false;
|
|
||||||
item.isUploaded = true;
|
|
||||||
item.isSuccess = true;
|
|
||||||
item.isCancel = false;
|
|
||||||
item.isError = false;
|
|
||||||
item.progress = 100;
|
|
||||||
item.index = null;
|
|
||||||
item.uploader.trigger('success', xhr, item, response);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:cancel' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_cancel: function(event, xhr, item) {
|
|
||||||
item.isReady = false;
|
|
||||||
item.isUploading = false;
|
|
||||||
item.isUploaded = false;
|
|
||||||
item.isSuccess = false;
|
|
||||||
item.isCancel = true;
|
|
||||||
item.isError = false;
|
|
||||||
item.progress = 0;
|
|
||||||
item.index = null;
|
|
||||||
item.uploader.trigger('cancel', xhr, item);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:error' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {*} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_error: function (event, xhr, item, response) {
|
|
||||||
item.isReady = false;
|
|
||||||
item.isUploading = false;
|
|
||||||
item.isUploaded = true;
|
|
||||||
item.isSuccess = false;
|
|
||||||
item.isCancel = false;
|
|
||||||
item.isError = true;
|
|
||||||
item.progress = 100;
|
|
||||||
item.index = null;
|
|
||||||
item.uploader.trigger('error', xhr, item, response);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The 'in:complete' handler
|
|
||||||
* @param {Object} event
|
|
||||||
* @param {XMLHttpRequest} xhr
|
|
||||||
* @param {Item} item
|
|
||||||
* @param {*} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_complete: function (event, xhr, item, response) {
|
|
||||||
item.uploader.trigger('complete', xhr, item, response);
|
|
||||||
item.removeAfterUpload && item.remove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
create: function (params) {
|
|
||||||
return new Uploader(params);
|
|
||||||
},
|
|
||||||
isHTML5: Uploader.prototype.isHTML5
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}));
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,97 +0,0 @@
|
||||||
angular.module('app', ['angularFileUpload'])
|
|
||||||
|
|
||||||
// The example of the full functionality
|
|
||||||
.controller('TestController',function ($scope, $fileUploader) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// create a uploader with options
|
|
||||||
var uploader = $scope.uploader = $fileUploader.create({
|
|
||||||
scope: $scope, // to automatically update the html. Default: $rootScope
|
|
||||||
url: '/api/containers/container1/upload',
|
|
||||||
formData: [
|
|
||||||
{ key: 'value' }
|
|
||||||
],
|
|
||||||
filters: [
|
|
||||||
function (item) { // first user filter
|
|
||||||
console.info('filter1');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// ADDING FILTERS
|
|
||||||
|
|
||||||
uploader.filters.push(function (item) { // second user filter
|
|
||||||
console.info('filter2');
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// REGISTER HANDLERS
|
|
||||||
|
|
||||||
uploader.bind('afteraddingfile', function (event, item) {
|
|
||||||
console.info('After adding a file', item);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('whenaddingfilefailed', function (event, item) {
|
|
||||||
console.info('When adding a file failed', item);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('afteraddingall', function (event, items) {
|
|
||||||
console.info('After adding all files', items);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('beforeupload', function (event, item) {
|
|
||||||
console.info('Before upload', item);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('progress', function (event, item, progress) {
|
|
||||||
console.info('Progress: ' + progress, item);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('success', function (event, xhr, item, response) {
|
|
||||||
console.info('Success', xhr, item, response);
|
|
||||||
$scope.$broadcast('uploadCompleted', item);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('cancel', function (event, xhr, item) {
|
|
||||||
console.info('Cancel', xhr, item);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('error', function (event, xhr, item, response) {
|
|
||||||
console.info('Error', xhr, item, response);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('complete', function (event, xhr, item, response) {
|
|
||||||
console.info('Complete', xhr, item, response);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('progressall', function (event, progress) {
|
|
||||||
console.info('Total progress: ' + progress);
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.bind('completeall', function (event, items) {
|
|
||||||
console.info('Complete all', items);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
).controller('FilesController', function ($scope, $http) {
|
|
||||||
|
|
||||||
$scope.load = function () {
|
|
||||||
$http.get('/api/containers/container1/files').success(function (data) {
|
|
||||||
console.log(data);
|
|
||||||
$scope.files = data;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.delete = function (index, id) {
|
|
||||||
$http.delete('/api/containers/container1/files/' + encodeURIComponent(id)).success(function (data, status, headers) {
|
|
||||||
$scope.files.splice(index, 1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.$on('uploadCompleted', function(event) {
|
|
||||||
console.log('uploadCompleted event received');
|
|
||||||
$scope.load();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,202 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html id="ng-app" ng-app="app"> <!-- id="ng-app" IE<8 -->
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>LoopBack Storage Service Demo</title>
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"/>
|
|
||||||
|
|
||||||
<!-- Fix for old browsers -->
|
|
||||||
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
|
|
||||||
|
|
||||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
|
|
||||||
|
|
||||||
<!--<script src="../bower_components/angular/angular.js"></script>-->
|
|
||||||
<script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
|
|
||||||
<script src="angular-file-upload.js"></script>
|
|
||||||
<script src="controllers.js"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.my-drop-zone {
|
|
||||||
border: dotted 3px lightgray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ng-file-over {
|
|
||||||
border: dotted 3px red;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default class applied to drop zones on over */
|
|
||||||
.another-file-over-class {
|
|
||||||
border: dotted 3px green;
|
|
||||||
}
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<!-- 1. ng-file-drop | ng-file-drop="options" -->
|
|
||||||
<body ng-controller="TestController" ng-file-drop>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="navbar navbar-default">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<a class="navbar-brand"
|
|
||||||
href="https://github.com/strongloop/loopback-component-storage">LoopBack
|
|
||||||
Storage Service</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-md-3">
|
|
||||||
|
|
||||||
<h3>Select files</h3>
|
|
||||||
|
|
||||||
<div ng-show="uploader.isHTML5">
|
|
||||||
<!-- 3. ng-file-over | ng-file-over="className" -->
|
|
||||||
<div class="well my-drop-zone" ng-file-over>
|
|
||||||
Base drop zone
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Example: ng-file-drop | ng-file-drop="options" -->
|
|
||||||
<div class="well my-drop-zone" ng-file-drop="{ url: '/foo' }"
|
|
||||||
ng-file-over="another-file-over-class">
|
|
||||||
Another drop zone with its own settings
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 2. ng-file-select | ng-file-select="options" -->
|
|
||||||
Multiple
|
|
||||||
<input ng-file-select type="file" multiple/><br/>
|
|
||||||
|
|
||||||
Single
|
|
||||||
<input ng-file-select type="file"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-9" style="margin-bottom: 40px">
|
|
||||||
|
|
||||||
<h3>Upload queue</h3>
|
|
||||||
|
|
||||||
<p>Queue length: {{ uploader.queue.length }}</p>
|
|
||||||
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th width="50%">Name</th>
|
|
||||||
<th ng-show="uploader.isHTML5">Size</th>
|
|
||||||
<th ng-show="uploader.isHTML5">Progress</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="item in uploader.queue">
|
|
||||||
<td><strong>{{ item.file.name }}</strong></td>
|
|
||||||
<td ng-show="uploader.isHTML5" nowrap>{{
|
|
||||||
item.file.size/1024/1024|number:2 }} MB
|
|
||||||
</td>
|
|
||||||
<td ng-show="uploader.isHTML5">
|
|
||||||
<div class="progress" style="margin-bottom: 0;">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
|
||||||
ng-style="{ 'width': item.progress + '%' }"></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<span ng-show="item.isSuccess"><i
|
|
||||||
class="glyphicon glyphicon-ok"></i></span>
|
|
||||||
<span ng-show="item.isCancel"><i
|
|
||||||
class="glyphicon glyphicon-ban-circle"></i></span>
|
|
||||||
<span ng-show="item.isError"><i
|
|
||||||
class="glyphicon glyphicon-remove"></i></span>
|
|
||||||
</td>
|
|
||||||
<td nowrap>
|
|
||||||
<button type="button" class="btn btn-success btn-xs"
|
|
||||||
ng-click="item.upload()"
|
|
||||||
ng-disabled="item.isReady || item.isUploading || item.isSuccess">
|
|
||||||
<span class="glyphicon glyphicon-upload"></span>
|
|
||||||
Upload
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-warning btn-xs"
|
|
||||||
ng-click="item.cancel()"
|
|
||||||
ng-disabled="!item.isUploading">
|
|
||||||
<span class="glyphicon glyphicon-ban-circle"></span>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-danger btn-xs"
|
|
||||||
ng-click="item.remove()">
|
|
||||||
<span class="glyphicon glyphicon-trash"></span>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
Queue progress:
|
|
||||||
|
|
||||||
<div class="progress" style="">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
|
||||||
ng-style="{ 'width': uploader.progress + '%' }"></div>
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
<button type="button" class="btn btn-success btn-s"
|
|
||||||
ng-click="uploader.uploadAll()"
|
|
||||||
ng-disabled="!uploader.getNotUploadedItems().length">
|
|
||||||
<span class="glyphicon glyphicon-upload"></span> Upload all
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-warning btn-s"
|
|
||||||
ng-click="uploader.cancelAll()"
|
|
||||||
ng-disabled="!uploader.isUploading">
|
|
||||||
<span class="glyphicon glyphicon-ban-circle"></span> Cancel
|
|
||||||
all
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-danger btn-s"
|
|
||||||
ng-click="uploader.clearQueue()"
|
|
||||||
ng-disabled="!uploader.queue.length">
|
|
||||||
<span class="glyphicon glyphicon-trash"></span> Remove all
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-9" style="margin-bottom: 40px"
|
|
||||||
ng-controller="FilesController" data-ng-init="load()">
|
|
||||||
|
|
||||||
<h3>Files in the container</h3>
|
|
||||||
|
|
||||||
<table class="table">
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="file in files">
|
|
||||||
<td>
|
|
||||||
<a href="/api/containers/container1/download/{{file.name}}"><strong>{{
|
|
||||||
file.name }}</strong></a></td>
|
|
||||||
<td>
|
|
||||||
<td>
|
|
||||||
<button type="button" class="btn btn-danger btn-xs"
|
|
||||||
ng-click="delete($index, file.name)"
|
|
||||||
title="Delete the file">
|
|
||||||
<span class="glyphicon glyphicon-trash"></span>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1 +0,0 @@
|
||||||
Hello....
|
|
|
@ -1 +0,0 @@
|
||||||
Hello....
|
|
|
@ -1 +0,0 @@
|
||||||
Hello....
|
|
|
@ -1,78 +0,0 @@
|
||||||
var StorageService = require('../').StorageService;
|
|
||||||
var providers = null;
|
|
||||||
try {
|
|
||||||
providers = require('./providers-private.json');
|
|
||||||
} catch(err) {
|
|
||||||
providers = require('./providers.json');
|
|
||||||
}
|
|
||||||
var express = require('express');
|
|
||||||
var app = express();
|
|
||||||
|
|
||||||
app.set('port', process.env.PORT || 3000);
|
|
||||||
app.set('views', __dirname + '/views');
|
|
||||||
app.set('view engine', 'ejs');
|
|
||||||
|
|
||||||
var handler = new StorageService(
|
|
||||||
{
|
|
||||||
provider: 'amazon',
|
|
||||||
key: providers.amazon.key,
|
|
||||||
keyId: providers.amazon.keyId
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/', function(req, res, next) {
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
|
||||||
var form = "<html><body><h1>Storage Service Demo</h1>" +
|
|
||||||
"<a href='/download'>List all containers</a><p>" +
|
|
||||||
"Upload to container con1: <p>" +
|
|
||||||
"<form method='POST' enctype='multipart/form-data' action='/upload/con1'>"
|
|
||||||
+ "File to upload: <input type=file name=uploadedFiles multiple=true><br>"
|
|
||||||
+ "Notes about the file: <input type=text name=note><br>"
|
|
||||||
+ "<input type=submit value=Upload></form>" +
|
|
||||||
"</body></html>";
|
|
||||||
res.send(form);
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/upload/:container', function(req, res, next) {
|
|
||||||
handler.upload(req, res, function(err, result) {
|
|
||||||
if (!err) {
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.status(200).send(result);
|
|
||||||
} else {
|
|
||||||
res.status(500).send(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/download', function(req, res, next) {
|
|
||||||
handler.getContainers(function(err, containers) {
|
|
||||||
var html = "<html><body><h1>Containers</h1><ul>";
|
|
||||||
containers.forEach(function(f) {
|
|
||||||
html += "<li><a href='/download/" + f.name + "'>" + f.name + "</a></li>"
|
|
||||||
});
|
|
||||||
html += "</ul><p><a href='/'>Home</a></p></body></html>";
|
|
||||||
res.status(200).send(html);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/download/:container', function(req, res, next) {
|
|
||||||
handler.getFiles(req.params.container, function(err, files) {
|
|
||||||
var html = "<html><body><h1>Files in container " + req.params.container + "</h1><ul>";
|
|
||||||
files.forEach(function(f) {
|
|
||||||
html += "<li><a href='/download/" + f.container + "/" + f.name + "'>" + f.container + "/" + f.name + "</a></li>"
|
|
||||||
});
|
|
||||||
html += "</ul><p><a href='/'>Home</a></p></body></html>";
|
|
||||||
res.status(200).send(html);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/download/:container/:file', function(req, res, next) {
|
|
||||||
handler.download(req.params.container, req.params.file, res, function(err, result) {
|
|
||||||
if (err) {
|
|
||||||
res.status(500).send(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(app.get('port'));
|
|
||||||
console.log('http://127.0.0.1:' + app.get('port'));
|
|
|
@ -1,72 +0,0 @@
|
||||||
var StorageService = require('../').StorageService;
|
|
||||||
|
|
||||||
var express = require('express');
|
|
||||||
var app = express();
|
|
||||||
|
|
||||||
app.set('port', process.env.PORT || 3000);
|
|
||||||
app.set('views', __dirname + '/views');
|
|
||||||
app.set('view engine', 'ejs');
|
|
||||||
|
|
||||||
// Create the container
|
|
||||||
var mkdirp = require('mkdirp');
|
|
||||||
mkdirp.sync('/tmp/storage/con1');
|
|
||||||
|
|
||||||
var handler = new StorageService({provider: 'filesystem', root: '/tmp/storage'});
|
|
||||||
|
|
||||||
app.get('/', function(req, res, next) {
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
|
||||||
var form = "<html><body><h1>Storage Service Demo</h1>" +
|
|
||||||
"<a href='/download'>List all containers</a><p>" +
|
|
||||||
"Upload to container con1: <p>" +
|
|
||||||
"<form method='POST' enctype='multipart/form-data' action='/upload/con1'>"
|
|
||||||
+ "File to upload: <input type=file name=uploadedFiles multiple=true><br>"
|
|
||||||
+ "Notes about the file: <input type=text name=note><br>"
|
|
||||||
+ "<input type=submit value=Upload></form>" +
|
|
||||||
"</body></html>";
|
|
||||||
res.send(form);
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/upload/:container', function(req, res, next) {
|
|
||||||
handler.upload(req, res, function(err, result) {
|
|
||||||
if (!err) {
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.status(200).send(result);
|
|
||||||
} else {
|
|
||||||
res.status(500).send(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/download', function(req, res, next) {
|
|
||||||
handler.getContainers(function(err, containers) {
|
|
||||||
var html = "<html><body><h1>Containers</h1><ul>";
|
|
||||||
containers.forEach(function(f) {
|
|
||||||
html += "<li><a href='/download/" + f.name + "'>" + f.name + "</a></li>"
|
|
||||||
});
|
|
||||||
html += "</ul><p><a href='/'>Home</a></p></body></html>";
|
|
||||||
res.status(200).send(html);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/download/:container', function(req, res, next) {
|
|
||||||
handler.getFiles(req.params.container, function(err, files) {
|
|
||||||
var html = "<html><body><h1>Files in container " + req.params.container + "</h1><ul>";
|
|
||||||
files.forEach(function(f) {
|
|
||||||
html += "<li><a href='/download/" + f.container + "/" + f.name + "'>" + f.container + "/" + f.name + "</a></li>"
|
|
||||||
});
|
|
||||||
html += "</ul><p><a href='/'>Home</a></p></body></html>";
|
|
||||||
res.status(200).send(html);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/download/:container/:file', function(req, res, next) {
|
|
||||||
handler.download(req.params.container, req.params.file, res, function(err, result) {
|
|
||||||
if (err) {
|
|
||||||
res.status(500).send(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(app.get('port'));
|
|
||||||
console.log('http://127.0.0.1:' + app.get('port'));
|
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
@ -158,7 +158,7 @@ describe('storage service', function () {
|
||||||
|
|
||||||
request('http://localhost:3000')
|
request('http://localhost:3000')
|
||||||
.post('/containers/album1/upload')
|
.post('/containers/album1/upload')
|
||||||
.attach('image', path.join(__dirname, '../example/test.jpg'))
|
.attach('image', path.join(__dirname, './fixtures/test.jpg'))
|
||||||
.set('Accept', 'application/json')
|
.set('Accept', 'application/json')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, function (err, res) {
|
.expect(200, function (err, res) {
|
||||||
|
@ -174,7 +174,7 @@ describe('storage service', function () {
|
||||||
|
|
||||||
request('http://localhost:3000')
|
request('http://localhost:3000')
|
||||||
.post('/imageContainers/album1/upload')
|
.post('/imageContainers/album1/upload')
|
||||||
.attach('image', path.join(__dirname, '../example/test.jpg'))
|
.attach('image', path.join(__dirname, './fixtures/test.jpg'))
|
||||||
.set('Accept', 'application/json')
|
.set('Accept', 'application/json')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, function (err, res) {
|
.expect(200, function (err, res) {
|
||||||
|
@ -189,7 +189,7 @@ describe('storage service', function () {
|
||||||
|
|
||||||
request('http://localhost:3000')
|
request('http://localhost:3000')
|
||||||
.post('/imageContainers/album1/upload')
|
.post('/imageContainers/album1/upload')
|
||||||
.attach('image', path.join(__dirname, '../example/app.js'))
|
.attach('image', path.join(__dirname, './fixtures/app.js'))
|
||||||
.set('Accept', 'application/json')
|
.set('Accept', 'application/json')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, function (err, res) {
|
.expect(200, function (err, res) {
|
||||||
|
@ -203,7 +203,7 @@ describe('storage service', function () {
|
||||||
|
|
||||||
request('http://localhost:3000')
|
request('http://localhost:3000')
|
||||||
.post('/imageContainers/album1/upload')
|
.post('/imageContainers/album1/upload')
|
||||||
.attach('image', path.join(__dirname, '../example/largeImage.jpg'))
|
.attach('image', path.join(__dirname, './fixtures/largeImage.jpg'))
|
||||||
.set('Accept', 'application/json')
|
.set('Accept', 'application/json')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, function (err, res) {
|
.expect(200, function (err, res) {
|
||||||
|
|
Loading…
Reference in New Issue