@flowjs/ng-flow
Version:
Flow.js html5 file upload extension on angular.js framework
289 lines (274 loc) • 8.14 kB
JavaScript
/**
* @description
* var app = angular.module('App', ['flow.provider'], function(flowFactoryProvider){
* flowFactoryProvider.defaults = {target: '/'};
* });
* @name flowFactoryProvider
*/
angular.module('flow.provider', [])
.provider('flowFactory', function() {
'use strict';
/**
* Define the default properties for flow.js
* @name flowFactoryProvider.defaults
* @type {Object}
*/
this.defaults = {};
/**
* Flow, MaybeFlow or NotFlow
* @name flowFactoryProvider.factory
* @type {function}
* @return {Flow}
*/
this.factory = function (options) {
return new Flow(options);
};
/**
* Define the default events
* @name flowFactoryProvider.events
* @type {Array}
* @private
*/
this.events = [];
/**
* Add default events
* @name flowFactoryProvider.on
* @function
* @param {string} event
* @param {Function} callback
*/
this.on = function (event, callback) {
this.events.push([event, callback]);
};
this.$get = function() {
var fn = this.factory;
var defaults = this.defaults;
var events = this.events;
return {
'create': function(opts) {
// combine default options with global options and options
var flow = fn(angular.extend({}, defaults, opts));
angular.forEach(events, function (event) {
flow.on(event[0], event[1]);
});
return flow;
}
};
};
});
angular.module('flow.init', ['flow.provider'])
.controller('flowCtrl', ['$scope', '$attrs', '$parse', 'flowFactory',
function ($scope, $attrs, $parse, flowFactory) {
var options = angular.extend({}, $scope.$eval($attrs.flowInit));
// use existing flow object or create a new one
var flow = $scope.$eval($attrs.flowObject) || flowFactory.create(options);
var catchAllHandler = function(eventName){
var args = Array.prototype.slice.call(arguments);
args.shift();
var event = $scope.$broadcast.apply($scope, ['flow::' + eventName, flow].concat(args));
if ({
'progress':1, 'filesSubmitted':1, 'fileSuccess': 1, 'fileError': 1, 'complete': 1
}[eventName]) {
$scope.$applyAsync();
}
if (event.defaultPrevented) {
return false;
}
};
flow.on('catchAll', catchAllHandler);
$scope.$on('$destroy', function(){
flow.off('catchAll', catchAllHandler);
});
$scope.$flow = flow;
if ($attrs.hasOwnProperty('flowName')) {
$parse($attrs.flowName).assign($scope, flow);
$scope.$on('$destroy', function () {
$parse($attrs.flowName).assign($scope);
});
}
}])
.directive('flowInit', [function() {
return {
scope: true,
controller: 'flowCtrl'
};
}]);
angular.module('flow.btn', ['flow.init'])
.directive('flowBtn', [function() {
return {
'restrict': 'EA',
'scope': false,
'require': '^flowInit',
'link': function(scope, element, attrs) {
var isDirectory = attrs.hasOwnProperty('flowDirectory');
var isSingleFile = attrs.hasOwnProperty('flowSingleFile');
var inputAttrs = attrs.hasOwnProperty('flowAttrs') && scope.$eval(attrs.flowAttrs);
scope.$flow.assignBrowse(element, isDirectory, isSingleFile, inputAttrs);
}
};
}]);
angular.module('flow.dragEvents', ['flow.init'])
/**
* @name flowPreventDrop
* Prevent loading files then dropped on element
*/
.directive('flowPreventDrop', function() {
return {
'scope': false,
'link': function(scope, element, attrs) {
element.bind('drop dragover', function (event) {
event.preventDefault();
});
}
};
})
/**
* @name flowDragEnter
* executes `flowDragEnter` and `flowDragLeave` events
*/
.directive('flowDragEnter', ['$timeout', function($timeout) {
return {
'scope': false,
'link': function(scope, element, attrs) {
var promise;
var enter = false;
element.bind('dragover', function (event) {
if (!isFileDrag(event)) {
return ;
}
if (!enter) {
scope.$apply(attrs.flowDragEnter);
enter = true;
}
$timeout.cancel(promise);
event.preventDefault();
});
element.bind('dragleave drop', function (event) {
$timeout.cancel(promise);
promise = $timeout(function () {
scope.$eval(attrs.flowDragLeave);
promise = null;
enter = false;
}, 100);
});
function isFileDrag(dragEvent) {
var fileDrag = false;
var dataTransfer = dragEvent.dataTransfer || dragEvent.originalEvent.dataTransfer;
angular.forEach(dataTransfer && dataTransfer.types, function(val) {
if (val === 'Files') {
fileDrag = true;
}
});
return fileDrag;
}
}
};
}]);
angular.module('flow.drop', ['flow.init'])
.directive('flowDrop', function() {
return {
'scope': false,
'require': '^flowInit',
'link': function(scope, element, attrs) {
if (attrs.flowDropEnabled) {
scope.$watch(attrs.flowDropEnabled, function (value) {
if (value) {
assignDrop();
} else {
unAssignDrop();
}
});
} else {
assignDrop();
}
function assignDrop() {
scope.$flow.assignDrop(element);
}
function unAssignDrop() {
scope.$flow.unAssignDrop(element);
}
}
};
});
!function (angular) {'use strict';
var module = angular.module('flow.events', ['flow.init']);
var events = {
fileSuccess: ['$file', '$message'],
fileProgress: ['$file'],
fileAdded: ['$file', '$event'],
filesAdded: ['$files', '$event'],
filesSubmitted: ['$files', '$event'],
fileRetry: ['$file'],
fileRemoved: ['$file'],
fileError: ['$file', '$message'],
uploadStart: [],
complete: [],
progress: [],
error: ['$message', '$file']
};
angular.forEach(events, function (eventArgs, eventName) {
var name = 'flow' + capitaliseFirstLetter(eventName);
if (name == 'flowUploadStart') {
name = 'flowUploadStarted';// event alias
}
module.directive(name, [function() {
return {
require: '^flowInit',
controller: ['$scope', '$attrs', function ($scope, $attrs) {
$scope.$on('flow::' + eventName, function () {
var funcArgs = Array.prototype.slice.call(arguments);
var event = funcArgs.shift();// remove angular event
// remove flow object and ignore event if it is from parent directive
if ($scope.$flow !== funcArgs.shift()) {
return ;
}
var args = {};
angular.forEach(eventArgs, function(value, key) {
args[value] = funcArgs[key];
});
if ($scope.$eval($attrs[name], args) === false) {
event.preventDefault();
}
});
}]
};
}]);
});
function capitaliseFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
}(angular);
angular.module('flow.img', ['flow.init'])
.directive('flowImg', [function() {
return {
'scope': false,
'require': '^flowInit',
'link': function(scope, element, attrs) {
var file = attrs.flowImg;
scope.$watch(file, function (file) {
if (!file) {
return ;
}
var fileReader = new FileReader();
fileReader.readAsDataURL(file.file);
fileReader.onload = function (event) {
scope.$apply(function () {
attrs.$set('src', event.target.result);
});
};
});
}
};
}]);
angular.module('flow.transfers', ['flow.init'])
.directive('flowTransfers', [function() {
return {
'scope': true,
'require': '^flowInit',
'link': function(scope) {
scope.transfers = scope.$flow.files;
}
};
}]);
angular.module('flow', ['flow.provider', 'flow.init', 'flow.events', 'flow.btn',
'flow.drop', 'flow.transfers', 'flow.img', 'flow.dragEvents']);