blueimp-file-upload-rails 8.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b724168c1d92965dbcb096ab2f8dd47b7ad1013e
4
+ data.tar.gz: fd6d388cf58a4b2342e8526955600d54ed407ee8
5
+ SHA512:
6
+ metadata.gz: 1ca334804763e0de86cecc121e9b28041c95461f1552308c2952229ce17698875ff0797334fa0d6eecfbe225f02f062642f2fb293090755894616aeb90b354a2
7
+ data.tar.gz: 4eb64c449e6ab193ea97dcb6176a40c02dbdefafc6dc7c6df57c20941863d4deedcd4d7d54b105af6b2adc4a005bf26bfa2b6480b7200a971d6d0a8e13d6fec8
@@ -0,0 +1,36 @@
1
+ module Blueimp
2
+ module FileUpload
3
+ module File
4
+ extend ActiveSupport::Concern
5
+ BLUEIMP_PARAMS = [:name, :size, :url, :thumbnail_url, :delete_url, :delete_type]
6
+
7
+ def as_json(options = {})
8
+ {}.tap do |json|
9
+ BLUEIMP_PARAMS.each do |param|
10
+ raise "Blueimp::FileUpload::File requires a method '#{param}'" if !respond_to?(param)
11
+ json[param] = send param
12
+ end
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def from_params(params)
18
+ { :files => from_param(params[:files]) }
19
+ end
20
+
21
+ def from_param(param)
22
+ param = [param] unless param.kind_of?(Array)
23
+
24
+ [].tap do |list|
25
+ param.each do |p|
26
+ list << new.tap do |file|
27
+ file.name = p.original_filename
28
+ file.contents = p.read
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ <%= form_tag action, :multipart => true, :class => "fileupload" do %>
2
+ <div class="row fileupload-buttonbar">
3
+ <div class="span7">
4
+ <span class="btn btn-success fileinput-button">
5
+ <i class="icon-plus icon-white"></i>
6
+ <span>Add files...</span>
7
+ <input type="file" name="files[]" multiple>
8
+ </span>
9
+ <button type="submit" class="btn btn-primary start">
10
+ <i class="icon-upload icon-white"></i>
11
+ <span>Start upload</span>
12
+ </button>
13
+ <button type="reset" class="btn btn-warning cancel">
14
+ <i class="icon-ban-circle icon-white"></i>
15
+ <span>Cancel upload</span>
16
+ </button>
17
+ <button type="button" class="btn btn-danger delete">
18
+ <i class="icon-trash icon-white"></i>
19
+ <span>Delete</span>
20
+ </button>
21
+ <input type="checkbox" class="toggle">
22
+ <span class="fileupload-loading"></span>
23
+ </div>
24
+ <div class="span5 fileupload-progress fade">
25
+ <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
26
+ <div class="bar" style="width: 0%;"></div>
27
+ </div>
28
+ <div class="progress-extended">&nbsp;</div>
29
+ </div>
30
+ </div>
31
+ <table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
32
+ <% end %>
@@ -0,0 +1,67 @@
1
+ <script id="template-upload" type="text/x-tmpl">
2
+ {% for (var i=0, file; file=o.files[i]; i++) { %}
3
+ <tr class="template-upload fade">
4
+ <td>
5
+ <span class="preview"></span>
6
+ </td>
7
+ <td>
8
+ <p class="name">{%=file.name%}</p>
9
+ {% if (file.error) { %}
10
+ <div><span class="label label-important">Error</span> {%=file.error%}</div>
11
+ {% } %}
12
+ </td>
13
+ <td>
14
+ <p class="size">{%=o.formatFileSize(file.size)%}</p>
15
+ {% if (!o.files.error) { %}
16
+ <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar" style="width:0%;"></div></div>
17
+ {% } %}
18
+ </td>
19
+ <td>
20
+ {% if (!o.files.error && !i && !o.options.autoUpload) { %}
21
+ <button class="btn btn-primary start">
22
+ <i class="icon-upload icon-white"></i>
23
+ <span>Start</span>
24
+ </button>
25
+ {% } %}
26
+ {% if (!i) { %}
27
+ <button class="btn btn-warning cancel">
28
+ <i class="icon-ban-circle icon-white"></i>
29
+ <span>Cancel</span>
30
+ </button>
31
+ {% } %}
32
+ </td>
33
+ </tr>
34
+ {% } %}
35
+ </script>
36
+
37
+ <script id="template-download" type="text/x-tmpl">
38
+ {% for (var i=0, file; file=o.files[i]; i++) { %}
39
+ <tr class="template-download fade">
40
+ <td>
41
+ <span class="preview">
42
+ {% if (file.thumbnail_url) { %}
43
+ <a href="{%=file.url%}" title="{%=file.name%}" class="gallery" download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
44
+ {% } %}
45
+ </span>
46
+ </td>
47
+ <td>
48
+ <p class="name">
49
+ <a href="{%=file.url%}" title="{%=file.name%}" class="{%=file.thumbnail_url?'gallery':''%}" download="{%=file.name%}">{%=file.name%}</a>
50
+ </p>
51
+ {% if (file.error) { %}
52
+ <div><span class="label label-important">Error</span> {%=file.error%}</div>
53
+ {% } %}
54
+ </td>
55
+ <td>
56
+ <span class="size">{%=o.formatFileSize(file.size)%}</span>
57
+ </td>
58
+ <td>
59
+ <button class="btn btn-danger delete" data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}"{% if (file.delete_with_credentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
60
+ <i class="icon-trash icon-white"></i>
61
+ <span>Delete</span>
62
+ </button>
63
+ <input type="checkbox" name="delete" value="1" class="toggle">
64
+ </td>
65
+ </tr>
66
+ {% } %}
67
+ </script>
@@ -0,0 +1,15 @@
1
+ # This is a generated file.
2
+ require "blueimp-file-upload-rails/version"
3
+ require "blueimp-load-image-rails"
4
+ require "blueimp-templates-rails"
5
+ require "blueimp-canvas-to-blob-rails"
6
+ require "jquery-ui-rails"
7
+
8
+ module Blueimp
9
+ module FileUpload
10
+ module Rails
11
+ class Engine < ::Rails::Engine
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # This is a generated file.
2
+ module Blueimp
3
+ module FileUpload
4
+ module Rails
5
+ class Version
6
+ class << self
7
+ def to_s
8
+ "8.5.0"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,51 @@
1
+ //= require jquery.ui.widget
2
+ //= require blueimp-templates
3
+ //= require blueimp-load-image
4
+ //= require blueimp-canvas-to-blob
5
+ //= require jquery.iframe-transport
6
+ //= require jquery.fileupload
7
+ //= require jquery.fileupload-process
8
+ //= require jquery.fileupload-image
9
+ //= require jquery.fileupload-audio
10
+ //= require jquery.fileupload-video
11
+ //= require jquery.fileupload-validate
12
+ //= require jquery.fileupload-ui
13
+
14
+ $(function () {
15
+ $(".fileupload").each(function() {
16
+ var fileupload = this;
17
+ var $fileupload = $(this);
18
+ var url = $fileupload.data("url");
19
+
20
+ if (!url || $.trim(url) == "") {
21
+ url = $fileupload.attr("action");
22
+ }
23
+
24
+ $fileupload.fileupload({ url: url });
25
+
26
+ // Load existing files:
27
+ $fileupload.addClass("fileupload-processing");
28
+ $.ajax({
29
+ url: $fileupload.fileupload("option", "url"),
30
+ dataType: "json",
31
+ context: fileupload
32
+ }).always(function () {
33
+ $(this).removeClass("fileupload-processing");
34
+ }).done(function (result) {
35
+ $(this).fileupload("option", "done")
36
+ .call(this, null, {result: result});
37
+ });
38
+
39
+ // Show the blueimp Gallery as lightbox when clicking on image links:
40
+ $(".files", fileupload).on("click", ".gallery", function (event) {
41
+ // The :even filter removes duplicate links (thumbnail and file name links):
42
+ if (blueimp.Gallery($(".gallery", fileupload).filter(":even"), {
43
+ index: this
44
+ })) {
45
+ // Prevent the default link action on
46
+ // successful Gallery initialization:
47
+ event.preventDefault();
48
+ }
49
+ });
50
+ });
51
+ });
@@ -0,0 +1,118 @@
1
+ /*
2
+ * jQuery postMessage Transport Plugin 1.1.1
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2011, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint unparam: true, nomen: true */
13
+ /*global define, window, document */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define(['jquery'], factory);
20
+ } else {
21
+ // Browser globals:
22
+ factory(window.jQuery);
23
+ }
24
+ }(function ($) {
25
+ 'use strict';
26
+
27
+ var counter = 0,
28
+ names = [
29
+ 'accepts',
30
+ 'cache',
31
+ 'contents',
32
+ 'contentType',
33
+ 'crossDomain',
34
+ 'data',
35
+ 'dataType',
36
+ 'headers',
37
+ 'ifModified',
38
+ 'mimeType',
39
+ 'password',
40
+ 'processData',
41
+ 'timeout',
42
+ 'traditional',
43
+ 'type',
44
+ 'url',
45
+ 'username'
46
+ ],
47
+ convert = function (p) {
48
+ return p;
49
+ };
50
+
51
+ $.ajaxSetup({
52
+ converters: {
53
+ 'postmessage text': convert,
54
+ 'postmessage json': convert,
55
+ 'postmessage html': convert
56
+ }
57
+ });
58
+
59
+ $.ajaxTransport('postmessage', function (options) {
60
+ if (options.postMessage && window.postMessage) {
61
+ var iframe,
62
+ loc = $('<a>').prop('href', options.postMessage)[0],
63
+ target = loc.protocol + '//' + loc.host,
64
+ xhrUpload = options.xhr().upload;
65
+ return {
66
+ send: function (_, completeCallback) {
67
+ counter += 1;
68
+ var message = {
69
+ id: 'postmessage-transport-' + counter
70
+ },
71
+ eventName = 'message.' + message.id;
72
+ iframe = $(
73
+ '<iframe style="display:none;" src="' +
74
+ options.postMessage + '" name="' +
75
+ message.id + '"></iframe>'
76
+ ).bind('load', function () {
77
+ $.each(names, function (i, name) {
78
+ message[name] = options[name];
79
+ });
80
+ message.dataType = message.dataType.replace('postmessage ', '');
81
+ $(window).bind(eventName, function (e) {
82
+ e = e.originalEvent;
83
+ var data = e.data,
84
+ ev;
85
+ if (e.origin === target && data.id === message.id) {
86
+ if (data.type === 'progress') {
87
+ ev = document.createEvent('Event');
88
+ ev.initEvent(data.type, false, true);
89
+ $.extend(ev, data);
90
+ xhrUpload.dispatchEvent(ev);
91
+ } else {
92
+ completeCallback(
93
+ data.status,
94
+ data.statusText,
95
+ {postmessage: data.result},
96
+ data.headers
97
+ );
98
+ iframe.remove();
99
+ $(window).unbind(eventName);
100
+ }
101
+ }
102
+ });
103
+ iframe[0].contentWindow.postMessage(
104
+ message,
105
+ target
106
+ );
107
+ }).appendTo(document.body);
108
+ },
109
+ abort: function () {
110
+ if (iframe) {
111
+ iframe.remove();
112
+ }
113
+ }
114
+ };
115
+ }
116
+ });
117
+
118
+ }));
@@ -0,0 +1,87 @@
1
+ /*
2
+ * jQuery XDomainRequest Transport Plugin 1.1.3
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2011, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ *
11
+ * Based on Julian Aubourg's ajaxHooks xdr.js:
12
+ * https://github.com/jaubourg/ajaxHooks/
13
+ */
14
+
15
+ /*jslint unparam: true */
16
+ /*global define, window, XDomainRequest */
17
+
18
+ (function (factory) {
19
+ 'use strict';
20
+ if (typeof define === 'function' && define.amd) {
21
+ // Register as an anonymous AMD module:
22
+ define(['jquery'], factory);
23
+ } else {
24
+ // Browser globals:
25
+ factory(window.jQuery);
26
+ }
27
+ }(function ($) {
28
+ 'use strict';
29
+ if (window.XDomainRequest && !$.support.cors) {
30
+ $.ajaxTransport(function (s) {
31
+ if (s.crossDomain && s.async) {
32
+ if (s.timeout) {
33
+ s.xdrTimeout = s.timeout;
34
+ delete s.timeout;
35
+ }
36
+ var xdr;
37
+ return {
38
+ send: function (headers, completeCallback) {
39
+ var addParamChar = /\?/.test(s.url) ? '&' : '?';
40
+ function callback(status, statusText, responses, responseHeaders) {
41
+ xdr.onload = xdr.onerror = xdr.ontimeout = $.noop;
42
+ xdr = null;
43
+ completeCallback(status, statusText, responses, responseHeaders);
44
+ }
45
+ xdr = new XDomainRequest();
46
+ // XDomainRequest only supports GET and POST:
47
+ if (s.type === 'DELETE') {
48
+ s.url = s.url + addParamChar + '_method=DELETE';
49
+ s.type = 'POST';
50
+ } else if (s.type === 'PUT') {
51
+ s.url = s.url + addParamChar + '_method=PUT';
52
+ s.type = 'POST';
53
+ } else if (s.type === 'PATCH') {
54
+ s.url = s.url + addParamChar + '_method=PATCH';
55
+ s.type = 'POST';
56
+ }
57
+ xdr.open(s.type, s.url);
58
+ xdr.onload = function () {
59
+ callback(
60
+ 200,
61
+ 'OK',
62
+ {text: xdr.responseText},
63
+ 'Content-Type: ' + xdr.contentType
64
+ );
65
+ };
66
+ xdr.onerror = function () {
67
+ callback(404, 'Not Found');
68
+ };
69
+ if (s.xdrTimeout) {
70
+ xdr.ontimeout = function () {
71
+ callback(0, 'timeout');
72
+ };
73
+ xdr.timeout = s.xdrTimeout;
74
+ }
75
+ xdr.send((s.hasContent && s.data) || null);
76
+ },
77
+ abort: function () {
78
+ if (xdr) {
79
+ xdr.onerror = $.noop();
80
+ xdr.abort();
81
+ }
82
+ }
83
+ };
84
+ }
85
+ });
86
+ }
87
+ }));
@@ -0,0 +1,397 @@
1
+ /*
2
+ * jQuery File Upload AngularJS Plugin 1.4.0
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint nomen: true, unparam: true */
13
+ /*global define, angular */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ 'angular',
22
+ './jquery.fileupload-image',
23
+ './jquery.fileupload-audio',
24
+ './jquery.fileupload-video',
25
+ './jquery.fileupload-validate'
26
+ ], factory);
27
+ } else {
28
+ factory();
29
+ }
30
+ }(function () {
31
+ 'use strict';
32
+
33
+ angular.module('blueimp.fileupload', [])
34
+
35
+ // The fileUpload service provides configuration options
36
+ // for the fileUpload directive and default handlers for
37
+ // File Upload events:
38
+ .provider('fileUpload', function () {
39
+ var scopeApply = function () {
40
+ var scope = angular.element(this)
41
+ .fileupload('option', 'scope')();
42
+ if (!scope.$$phase) {
43
+ scope.$apply();
44
+ }
45
+ },
46
+ $config;
47
+ $config = this.defaults = {
48
+ handleResponse: function (e, data) {
49
+ var files = data.result && data.result.files;
50
+ if (files) {
51
+ data.scope().replace(data.files, files);
52
+ } else if (data.errorThrown ||
53
+ data.textStatus === 'error') {
54
+ data.files[0].error = data.errorThrown ||
55
+ data.textStatus;
56
+ }
57
+ },
58
+ add: function (e, data) {
59
+ var scope = data.scope();
60
+ data.process(function () {
61
+ return scope.process(data);
62
+ }).always(
63
+ function () {
64
+ var file = data.files[0],
65
+ submit = function () {
66
+ return data.submit();
67
+ },
68
+ i;
69
+ for (i = 0; i < data.files.length; i += 1) {
70
+ data.files[i]._index = i;
71
+ }
72
+ file.$cancel = function () {
73
+ scope.clear(data.files);
74
+ return data.abort();
75
+ };
76
+ file.$state = function () {
77
+ return data.state();
78
+ };
79
+ file.$progress = function () {
80
+ return data.progress();
81
+ };
82
+ file.$response = function () {
83
+ return data.response();
84
+ };
85
+ if (file.$state() === 'rejected') {
86
+ file._$submit = submit;
87
+ } else {
88
+ file.$submit = submit;
89
+ }
90
+ scope.$apply(function () {
91
+ var method = scope.option('prependFiles') ?
92
+ 'unshift' : 'push';
93
+ Array.prototype[method].apply(
94
+ scope.queue,
95
+ data.files
96
+ );
97
+ if (file.$submit &&
98
+ (scope.option('autoUpload') ||
99
+ data.autoUpload) &&
100
+ data.autoUpload !== false) {
101
+ file.$submit();
102
+ }
103
+ });
104
+ }
105
+ );
106
+ },
107
+ progress: function (e, data) {
108
+ data.scope().$apply();
109
+ },
110
+ done: function (e, data) {
111
+ var that = this;
112
+ data.scope().$apply(function () {
113
+ data.handleResponse.call(that, e, data);
114
+ });
115
+ },
116
+ fail: function (e, data) {
117
+ var that = this;
118
+ if (data.errorThrown === 'abort') {
119
+ return;
120
+ }
121
+ if (data.dataType &&
122
+ data.dataType.indexOf('json') === data.dataType.length - 4) {
123
+ try {
124
+ data.result = angular.fromJson(data.jqXHR.responseText);
125
+ } catch (ignore) {}
126
+ }
127
+ data.scope().$apply(function () {
128
+ data.handleResponse.call(that, e, data);
129
+ });
130
+ },
131
+ stop: scopeApply,
132
+ processstart: scopeApply,
133
+ processstop: scopeApply,
134
+ getNumberOfFiles: function () {
135
+ return this.scope().queue.length;
136
+ },
137
+ dataType: 'json',
138
+ prependFiles: true,
139
+ autoUpload: false
140
+ };
141
+ this.$get = [
142
+ function () {
143
+ return {
144
+ defaults: $config
145
+ };
146
+ }
147
+ ];
148
+ })
149
+
150
+ // Format byte numbers to readable presentations:
151
+ .provider('formatFileSizeFilter', function () {
152
+ var $config = {
153
+ // Byte units following the IEC format
154
+ // http://en.wikipedia.org/wiki/Kilobyte
155
+ units: [
156
+ {size: 1000000000, suffix: ' GB'},
157
+ {size: 1000000, suffix: ' MB'},
158
+ {size: 1000, suffix: ' KB'}
159
+ ]
160
+ };
161
+ this.defaults = $config;
162
+ this.$get = function () {
163
+ return function (bytes) {
164
+ if (!angular.isNumber(bytes)) {
165
+ return '';
166
+ }
167
+ var unit = true,
168
+ i = 0,
169
+ prefix,
170
+ suffix;
171
+ while (unit) {
172
+ unit = $config.units[i];
173
+ prefix = unit.prefix || '';
174
+ suffix = unit.suffix || '';
175
+ if (i === $config.units.length - 1 || bytes >= unit.size) {
176
+ return prefix + (bytes / unit.size).toFixed(2) + suffix;
177
+ }
178
+ i += 1;
179
+ }
180
+ };
181
+ };
182
+ })
183
+
184
+ // The FileUploadController initializes the fileupload widget and
185
+ // provides scope methods to control the File Upload functionality:
186
+ .controller('FileUploadController', [
187
+ '$scope', '$element', '$attrs', '$window', 'fileUpload',
188
+ function ($scope, $element, $attrs, $window, fileUpload) {
189
+ var uploadMethods = {
190
+ progress: function () {
191
+ return $element.fileupload('progress');
192
+ },
193
+ active: function () {
194
+ return $element.fileupload('active');
195
+ },
196
+ option: function (option, data) {
197
+ return $element.fileupload('option', option, data);
198
+ },
199
+ add: function (data) {
200
+ return $element.fileupload('add', data);
201
+ },
202
+ send: function (data) {
203
+ return $element.fileupload('send', data);
204
+ },
205
+ process: function (data) {
206
+ return $element.fileupload('process', data);
207
+ },
208
+ processing: function (data) {
209
+ return $element.fileupload('processing', data);
210
+ }
211
+ };
212
+ $scope.disabled = !$window.jQuery.support.fileInput;
213
+ $scope.queue = $scope.queue || [];
214
+ $scope.clear = function (files) {
215
+ var queue = this.queue,
216
+ i = queue.length,
217
+ file = files,
218
+ length = 1;
219
+ if (angular.isArray(files)) {
220
+ file = files[0];
221
+ length = files.length;
222
+ }
223
+ while (i) {
224
+ i -= 1;
225
+ if (queue[i] === file) {
226
+ return queue.splice(i, length);
227
+ }
228
+ }
229
+ };
230
+ $scope.replace = function (oldFiles, newFiles) {
231
+ var queue = this.queue,
232
+ file = oldFiles[0],
233
+ i,
234
+ j;
235
+ for (i = 0; i < queue.length; i += 1) {
236
+ if (queue[i] === file) {
237
+ for (j = 0; j < newFiles.length; j += 1) {
238
+ queue[i + j] = newFiles[j];
239
+ }
240
+ return;
241
+ }
242
+ }
243
+ };
244
+ $scope.applyOnQueue = function (method) {
245
+ var list = this.queue.slice(0),
246
+ i,
247
+ file;
248
+ for (i = 0; i < list.length; i += 1) {
249
+ file = list[i];
250
+ if (file[method]) {
251
+ file[method]();
252
+ }
253
+ }
254
+ };
255
+ $scope.submit = function () {
256
+ this.applyOnQueue('$submit');
257
+ };
258
+ $scope.cancel = function () {
259
+ this.applyOnQueue('$cancel');
260
+ };
261
+ // Add upload methods to the scope:
262
+ angular.extend($scope, uploadMethods);
263
+ // The fileupload widget will initialize with
264
+ // the options provided via "data-"-parameters,
265
+ // as well as those given via options object:
266
+ $element.fileupload(angular.extend(
267
+ {scope: function () {
268
+ return $scope;
269
+ }},
270
+ fileUpload.defaults
271
+ )).on('fileuploadadd', function (e, data) {
272
+ data.scope = $scope.option('scope');
273
+ }).on([
274
+ 'fileuploadadd',
275
+ 'fileuploadsubmit',
276
+ 'fileuploadsend',
277
+ 'fileuploaddone',
278
+ 'fileuploadfail',
279
+ 'fileuploadalways',
280
+ 'fileuploadprogress',
281
+ 'fileuploadprogressall',
282
+ 'fileuploadstart',
283
+ 'fileuploadstop',
284
+ 'fileuploadchange',
285
+ 'fileuploadpaste',
286
+ 'fileuploaddrop',
287
+ 'fileuploaddragover',
288
+ 'fileuploadchunksend',
289
+ 'fileuploadchunkdone',
290
+ 'fileuploadchunkfail',
291
+ 'fileuploadchunkalways',
292
+ 'fileuploadprocessstart',
293
+ 'fileuploadprocess',
294
+ 'fileuploadprocessdone',
295
+ 'fileuploadprocessfail',
296
+ 'fileuploadprocessalways',
297
+ 'fileuploadprocessstop'
298
+ ].join(' '), function (e, data) {
299
+ $scope.$emit(e.type, data);
300
+ }).on('remove', function () {
301
+ // Remove upload methods from the scope,
302
+ // when the widget is removed:
303
+ var method;
304
+ for (method in uploadMethods) {
305
+ if (uploadMethods.hasOwnProperty(method)) {
306
+ delete $scope[method];
307
+ }
308
+ }
309
+ });
310
+ // Observe option changes:
311
+ $scope.$watch(
312
+ $attrs.fileUpload,
313
+ function (newOptions) {
314
+ if (newOptions) {
315
+ $element.fileupload('option', newOptions);
316
+ }
317
+ }
318
+ );
319
+ }
320
+ ])
321
+
322
+ // Provide File Upload progress feedback:
323
+ .controller('FileUploadProgressController', [
324
+ '$scope', '$attrs', '$parse',
325
+ function ($scope, $attrs, $parse) {
326
+ var fn = $parse($attrs.fileUploadProgress),
327
+ update = function () {
328
+ var progress = fn($scope);
329
+ if (!progress || !progress.total) {
330
+ return;
331
+ }
332
+ $scope.num = Math.floor(
333
+ progress.loaded / progress.total * 100
334
+ );
335
+ };
336
+ update();
337
+ $scope.$watch(
338
+ $attrs.fileUploadProgress + '.loaded',
339
+ function (newValue, oldValue) {
340
+ if (newValue !== oldValue) {
341
+ update();
342
+ }
343
+ }
344
+ );
345
+ }
346
+ ])
347
+
348
+ // Display File Upload previews:
349
+ .controller('FileUploadPreviewController', [
350
+ '$scope', '$element', '$attrs', '$parse',
351
+ function ($scope, $element, $attrs, $parse) {
352
+ var fn = $parse($attrs.fileUploadPreview),
353
+ file = fn($scope);
354
+ if (file.preview) {
355
+ $element.append(file.preview);
356
+ }
357
+ }
358
+ ])
359
+
360
+ .directive('fileUpload', function () {
361
+ return {
362
+ controller: 'FileUploadController'
363
+ };
364
+ })
365
+
366
+ .directive('fileUploadProgress', function () {
367
+ return {
368
+ controller: 'FileUploadProgressController'
369
+ };
370
+ })
371
+
372
+ .directive('fileUploadPreview', function () {
373
+ return {
374
+ controller: 'FileUploadPreviewController'
375
+ };
376
+ })
377
+
378
+ // Enhance the HTML5 download attribute to
379
+ // allow drag&drop of files to the desktop:
380
+ .directive('download', function () {
381
+ return function (scope, elm) {
382
+ elm.on('dragstart', function (e) {
383
+ try {
384
+ e.originalEvent.dataTransfer.setData(
385
+ 'DownloadURL',
386
+ [
387
+ 'application/octet-stream',
388
+ elm.prop('download'),
389
+ elm.prop('href')
390
+ ].join(':')
391
+ );
392
+ } catch (ignore) {}
393
+ });
394
+ };
395
+ });
396
+
397
+ }));