radiant-assets-extension 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,28 @@
1
1
  class Admin::AssetsController < Admin::ResourceController
2
2
  paginate_models
3
3
  helper :assets
4
+
5
+ def create
6
+ # HACK: depends on javascript being present and packaging each file
7
+ # in its own request
8
+ # TODO: handle non-js situations with several files in one request
9
+ @asset = Asset.create! :upload => Array(params[:asset][:upload]).first
10
+ @asset.save!
11
+ render_hacky_json(:markup => @template.asset_listing(@asset))
12
+ rescue => e
13
+ logger.warn(e.to_s)
14
+ render_hacky_json(:markup => "Error: #{e.to_s}")
15
+ end
16
+
17
+ private
18
+ # HACK: sending JSON as text/html
19
+ # (https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
20
+ # jquery.fileupload makes use of iframes for browsers like Microsoft
21
+ # Internet Explorer and Opera, which do not yet support XMLHTTPRequest
22
+ # uploads. They will only register a load event if the Content-type of the
23
+ # response is set to text/plain or text/html, not if it is set to
24
+ # application/json.
25
+ def render_hacky_json(data)
26
+ render :json => data, :content_type => 'text/html'
27
+ end
4
28
  end
@@ -1,4 +1,4 @@
1
- module AssetsHelper
1
+ module AssetsHelper
2
2
  def asset_listing(asset)
3
3
  icon(asset) +
4
4
  content_tag(:span, asset.to_s, :class=>'title')
@@ -40,9 +40,7 @@ module AssetsHelper
40
40
  end
41
41
 
42
42
  def video_player(asset)
43
- content_tag :video, :controls => 'controls' do
44
- content_tag :source, '', :src => @asset.upload.url, :type => @asset.upload.mime_type
45
- end
43
+ %Q{<video src="#{asset.upload.url}" type="#{asset.upload.mime_type}" controls="controls">}
46
44
  end
47
45
 
48
46
  def audio_player(asset)
@@ -58,10 +56,7 @@ module AssetsHelper
58
56
  end
59
57
 
60
58
  def view_toggle
61
- if list_view?
62
- link_to 'Grid view', admin_assets_path(:view => 'grid')
63
- else
64
- link_to 'List view', admin_assets_path(:view => 'list')
65
- end
59
+ other = list_view? ? 'grid' : 'list'
60
+ link_to "Switch to #{other} view", admin_assets_path(:view => other)
66
61
  end
67
62
  end
data/app/models/asset.rb CHANGED
@@ -10,8 +10,8 @@ class Asset < ActiveRecord::Base
10
10
  # HACK: relying on extension instead of using analyser and upload.format
11
11
  # analyser can throw us into very long loop when trying to identify
12
12
  # non-image files like word docs
13
- upload.ext.to_sym
14
- rescue UnableToHandle
13
+ upload.ext && upload.ext.to_sym
14
+ rescue Dragonfly::FunctionManager::UnableToHandle
15
15
  :generic
16
16
  end
17
17
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  <h1>Edit Asset</h1>
4
4
 
5
- <% form_for [:admin, @asset], :html => {'data-onsubmit_status' => onsubmit_status(@asset)} do |f| %>
5
+ <% form_for [:admin, @asset], :html => {:multipart => true, 'data-onsubmit_status' => onsubmit_status(@asset)} do |f| %>
6
6
  <div class="form_area">
7
7
  <p class="title">
8
8
  Caption: <%= f.text_field :caption %>
@@ -16,8 +16,7 @@
16
16
  <% end %>
17
17
  </tbody>
18
18
  </table>
19
- <!-- FIXME: doesn't work at the moment -->
20
- <!-- <%= f.file_field :upload %> -->
19
+ <%= f.file_field :upload %>
21
20
  <%= display(@asset) %>
22
21
  </div>
23
22
  <p class="buttons">
@@ -7,7 +7,7 @@
7
7
  <div id="actions">
8
8
  <%= pagination_for(@assets) %>
9
9
  <ul>
10
- <li class="new"><%= link_to 'Upload New Asset', new_admin_asset_path %></li>
10
+ <li class="new"><%= link_to 'Upload New Assets', new_admin_asset_path %></li>
11
11
  <li><%= view_toggle %></li>
12
12
  </ul>
13
13
  </div>
@@ -1,8 +1,45 @@
1
- <h1>Upload New Asset</h1>
1
+ <% include_stylesheet 'admin/extensions/assets/assets' %>
2
+
3
+ <h1>Upload New Assets</h1>
4
+ <table id="files">
5
+ <tbody></tbody>
6
+ </table>
7
+
8
+ <p>You can select multiple files</p>
2
9
  <% form_for [:admin, @asset], :html => {:multipart => true, 'data-onsubmit_status'=>'Uploading Asset&#8230;'} do |f| %>
3
- <%= f.file_field :upload %>
4
- <p class="buttons">
10
+ <%= f.file_field :upload, :multiple => true %>
11
+
12
+ <!-- <p class="buttons">
5
13
  <%= f.submit 'Upload Asset', :class=>'button' %>
6
14
  or <%= link_to 'Cancel', admin_assets_path %>
7
- </p>
15
+ </p> -->
8
16
  <% end %>
17
+
18
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
19
+ <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"></script>
20
+ <% include_stylesheet 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/themes/base/jquery-ui.css' %>
21
+ <script type="text/javascript">jQuery.noConflict();</script>
22
+ <script src="/jquery.fileupload/jquery.fileupload.js" type="text/javascript"></script>
23
+ <script src="/jquery.fileupload/jquery.fileupload-ui.js" type="text/javascript"></script>
24
+ <% include_stylesheet '/jquery.fileupload/jquery.fileupload-ui.css' %>
25
+ <script type="text/javascript">
26
+ (function($) {
27
+ $(function () {
28
+ $('form.new_asset').fileUploadUI({
29
+ uploadTable: $('#files'),
30
+ downloadTable: $('#files'),
31
+ buildUploadRow: function (files, index) {
32
+ return $('<tr><td>' + files[index].name + '<\/td>' +
33
+ '<td class="file_upload_progress"><div><\/div><\/td>' +
34
+ '<td class="file_upload_cancel">' +
35
+ '<button class="ui-state-default ui-corner-all" title="Cancel">' +
36
+ '<span class="ui-icon ui-icon-cancel">Cancel<\/span>' +
37
+ '<\/button><\/td><\/tr>');
38
+ },
39
+ buildDownloadRow: function (file) {
40
+ return $('<tr><td>' + file.markup + '<\/td><\/tr>');
41
+ }
42
+ });
43
+ });
44
+ }(jQuery));
45
+ </script>
@@ -1,3 +1,3 @@
1
1
  module RadiantAssetsExtension
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
@@ -2,7 +2,7 @@ namespace :radiant do
2
2
  namespace :extensions do
3
3
  namespace :assets do
4
4
 
5
- desc "Runs the migration of the Images extension"
5
+ desc "Runs the migration of the Assets extension"
6
6
  task :migrate => :environment do
7
7
  require 'radiant/extension_migrator'
8
8
  if ENV["VERSION"]
@@ -14,10 +14,10 @@ namespace :radiant do
14
14
  end
15
15
  end
16
16
 
17
- desc "Copies public assets of the Images to the instance public/ directory."
17
+ desc "Copies public assets of the Assets extension to the instance public/ directory."
18
18
  task :update => :environment do
19
19
  is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
20
- puts "Copying assets from ImagesExtension"
20
+ puts "Copying assets from AssetsExtension"
21
21
  Dir[AssetsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
22
22
  path = file.sub(AssetsExtension.root, '')
23
23
  directory = File.dirname(path)
@@ -25,7 +25,7 @@ namespace :radiant do
25
25
  cp file, RAILS_ROOT + path, :verbose => false
26
26
  end
27
27
  unless AssetsExtension.root.starts_with? RAILS_ROOT # don't need to copy vendored tasks
28
- puts "Copying rake tasks from ImagesExtension"
28
+ puts "Copying rake tasks from AssetsExtension"
29
29
  local_tasks_path = File.join(RAILS_ROOT, %w(lib tasks))
30
30
  mkdir_p local_tasks_path, :verbose => false
31
31
  Dir[File.join AssetsExtension.root, %w(lib tasks *.rake)].each do |file|
@@ -0,0 +1 @@
1
+ .DS_Store
@@ -0,0 +1,74 @@
1
+ .file_upload {
2
+ position: relative;
3
+ overflow: hidden;
4
+ direction: ltr;
5
+ cursor: pointer;
6
+ text-align: center;
7
+ color: #333;
8
+ font-weight: bold;
9
+ -moz-border-radius: 10px;
10
+ -webkit-border-radius: 10px;
11
+ border-radius: 10px;
12
+ width: 200px;
13
+ height: 30px;
14
+ line-height: 30px;
15
+ background: palegreen;
16
+ border: 1px solid limegreen;
17
+ }
18
+
19
+ .file_upload_small {
20
+ width: 200px;
21
+ height: 30px;
22
+ line-height: 30px;
23
+ font-size: auto;
24
+ background: palegreen;
25
+ border: 1px solid limegreen;
26
+ }
27
+
28
+ .file_upload_large {
29
+ width: 100%;
30
+ height: 150px;
31
+ line-height: 150px;
32
+ font-size: 20px;
33
+ background: palegreen;
34
+ border: 1px solid limegreen;
35
+ }
36
+
37
+ .file_upload_highlight {
38
+ background: lawngreen;
39
+ }
40
+
41
+ .file_upload input {
42
+ position: absolute;
43
+ top: 0;
44
+ right: 0;
45
+ margin: 0;
46
+ border: 300px solid transparent;
47
+ opacity: 0;
48
+ -ms-filter: 'alpha(opacity=0)';
49
+ filter: alpha(opacity=0);
50
+ -o-transform: translate(-300px, -300px) scale(10);
51
+ -moz-transform: translate(-800px, 0) scale(10);
52
+ cursor: pointer;
53
+ }
54
+
55
+ .file_upload iframe, .file_upload button {
56
+ display: none;
57
+ }
58
+
59
+ .file_upload_preview img {
60
+ width: 80px;
61
+ }
62
+
63
+ .file_upload_progress .ui-progressbar-value {
64
+ background: url(pbar-ani.gif);
65
+ }
66
+
67
+ .file_upload_progress div {
68
+ width: 150px;
69
+ height: 15px;
70
+ }
71
+
72
+ .file_upload_cancel button {
73
+ cursor: pointer;
74
+ }
@@ -0,0 +1,308 @@
1
+ /*
2
+ * jQuery File Upload User Interface Plugin 3.6
3
+ *
4
+ * Copyright 2010, Sebastian Tschan, AQUANTUM
5
+ * Licensed under the MIT license:
6
+ * http://creativecommons.org/licenses/MIT/
7
+ *
8
+ * https://blueimp.net
9
+ * http://www.aquantum.de
10
+ */
11
+
12
+ /*jslint browser: true */
13
+ /*global jQuery, FileReader, URL */
14
+
15
+ (function ($) {
16
+
17
+ var undef = 'undefined',
18
+ func = 'function',
19
+ UploadHandler,
20
+ methods,
21
+
22
+ LocalImage = function (file, imageTypes) {
23
+ var img,
24
+ fileReader;
25
+ if (!imageTypes.test(file.type)) {
26
+ return null;
27
+ }
28
+ img = document.createElement('img');
29
+ if (typeof URL !== undef && typeof URL.createObjectURL === func) {
30
+ img.src = URL.createObjectURL(file);
31
+ img.onload = function () {
32
+ URL.revokeObjectURL(this.src);
33
+ };
34
+ return img;
35
+ }
36
+ if (typeof FileReader !== undef) {
37
+ fileReader = new FileReader();
38
+ if (typeof fileReader.readAsDataURL === func) {
39
+ fileReader.onload = function (e) {
40
+ img.src = e.target.result;
41
+ };
42
+ fileReader.readAsDataURL(file);
43
+ return img;
44
+ }
45
+ }
46
+ return null;
47
+ };
48
+
49
+ UploadHandler = function (container, options) {
50
+ var uploadHandler = this,
51
+ dragOverTimeout,
52
+ isDropZoneEnlarged;
53
+
54
+ this.dropZone = container;
55
+ this.imageTypes = /^image\/(gif|jpeg|png)$/;
56
+ this.previewSelector = '.file_upload_preview';
57
+ this.progressSelector = '.file_upload_progress div';
58
+ this.cancelSelector = '.file_upload_cancel button';
59
+ this.cssClassSmall = 'file_upload_small';
60
+ this.cssClassLarge = 'file_upload_large';
61
+ this.cssClassHighlight = 'file_upload_highlight';
62
+ this.dropEffect = 'highlight';
63
+ this.uploadTable = this.downloadTable = null;
64
+
65
+ this.buildUploadRow = this.buildDownloadRow = function () {
66
+ return null;
67
+ };
68
+
69
+ this.addNode = function (parentNode, node, callBack) {
70
+ if (node) {
71
+ node.css('display', 'none').appendTo(parentNode).fadeIn(function () {
72
+ if (typeof callBack === func) {
73
+ try {
74
+ callBack();
75
+ } catch (e) {
76
+ // Fix endless exception loop:
77
+ $(this).stop();
78
+ throw e;
79
+ }
80
+ }
81
+ });
82
+ } else if (typeof callBack === func) {
83
+ callBack();
84
+ }
85
+ };
86
+
87
+ this.removeNode = function (node, callBack) {
88
+ if (node) {
89
+ node.fadeOut(function () {
90
+ $(this).remove();
91
+ if (typeof callBack === func) {
92
+ try {
93
+ callBack();
94
+ } catch (e) {
95
+ // Fix endless exception loop:
96
+ $(this).stop();
97
+ throw e;
98
+ }
99
+ }
100
+ });
101
+ } else if (typeof callBack === func) {
102
+ callBack();
103
+ }
104
+ };
105
+
106
+ this.onAbort = function (event, files, index, xhr, handler) {
107
+ handler.removeNode(handler.uploadRow);
108
+ };
109
+
110
+ this.cancelUpload = function (event, files, index, xhr, handler) {
111
+ var readyState = xhr.readyState;
112
+ xhr.abort();
113
+ // If readyState is below 2, abort() has no effect:
114
+ if (isNaN(readyState) || readyState < 2) {
115
+ handler.onAbort(event, files, index, xhr, handler);
116
+ }
117
+ };
118
+
119
+ this.initProgressBar = function (node, value) {
120
+ if (typeof node.progressbar === func) {
121
+ return node.progressbar({
122
+ value: value
123
+ });
124
+ } else {
125
+ var progressbar = $('<progress value="' + value + '" max="100"/>').appendTo(node);
126
+ progressbar.progressbar = function (key, value) {
127
+ progressbar.attr('value', value);
128
+ };
129
+ return progressbar;
130
+ }
131
+ };
132
+
133
+ this.initUploadRow = function (event, files, index, xhr, handler, callBack) {
134
+ var uploadRow = handler.uploadRow = handler.buildUploadRow(files, index, handler);
135
+ if (uploadRow) {
136
+ handler.progressbar = handler.initProgressBar(
137
+ uploadRow.find(handler.progressSelector),
138
+ (xhr.upload ? 0 : 100)
139
+ );
140
+ uploadRow.find(handler.cancelSelector).click(function (e) {
141
+ handler.cancelUpload(e, files, index, xhr, handler);
142
+ });
143
+ uploadRow.find(handler.previewSelector).each(function () {
144
+ $(this).append(new LocalImage(files[index], handler.imageTypes));
145
+ });
146
+ }
147
+ handler.addNode(
148
+ (typeof handler.uploadTable === func ? handler.uploadTable(handler) : handler.uploadTable),
149
+ uploadRow,
150
+ callBack
151
+ );
152
+ };
153
+
154
+ this.initUpload = function (event, files, index, xhr, handler, callBack) {
155
+ handler.initUploadRow(event, files, index, xhr, handler, function () {
156
+ if (typeof handler.beforeSend === func) {
157
+ handler.beforeSend(event, files, index, xhr, handler, callBack);
158
+ } else {
159
+ callBack();
160
+ }
161
+ });
162
+ };
163
+
164
+ this.onProgress = function (event, files, index, xhr, handler) {
165
+ if (handler.progressbar) {
166
+ handler.progressbar.progressbar(
167
+ 'value',
168
+ parseInt(event.loaded / event.total * 100, 10)
169
+ );
170
+ }
171
+ };
172
+
173
+ this.parseResponse = function (xhr) {
174
+ if (typeof xhr.responseText !== undef) {
175
+ return $.parseJSON(xhr.responseText);
176
+ } else {
177
+ // Instead of an XHR object, an iframe is used for legacy browsers:
178
+ return $.parseJSON(xhr.contents().text());
179
+ }
180
+ };
181
+
182
+ this.initDownloadRow = function (event, files, index, xhr, handler, callBack) {
183
+ var json, downloadRow;
184
+ try {
185
+ json = handler.response = handler.parseResponse(xhr);
186
+ downloadRow = handler.downloadRow = handler.buildDownloadRow(json, handler);
187
+ handler.addNode(
188
+ (typeof handler.downloadTable === func ? handler.downloadTable(handler) : handler.downloadTable),
189
+ downloadRow,
190
+ callBack
191
+ );
192
+ } catch (e) {
193
+ if (typeof handler.onError === func) {
194
+ handler.originalEvent = event;
195
+ handler.onError(e, files, index, xhr, handler);
196
+ } else {
197
+ throw e;
198
+ }
199
+ }
200
+ };
201
+
202
+ this.onLoad = function (event, files, index, xhr, handler) {
203
+ handler.removeNode(handler.uploadRow, function () {
204
+ handler.initDownloadRow(event, files, index, xhr, handler, function () {
205
+ if (typeof handler.onComplete === func) {
206
+ handler.onComplete(event, files, index, xhr, handler);
207
+ }
208
+ });
209
+ });
210
+ };
211
+
212
+ this.dropZoneEnlarge = function () {
213
+ if (!isDropZoneEnlarged) {
214
+ if (typeof uploadHandler.dropZone.switchClass === func) {
215
+ uploadHandler.dropZone.switchClass(
216
+ uploadHandler.cssClassSmall,
217
+ uploadHandler.cssClassLarge
218
+ );
219
+ } else {
220
+ uploadHandler.dropZone.addClass(uploadHandler.cssClassLarge);
221
+ uploadHandler.dropZone.removeClass(uploadHandler.cssClassSmall);
222
+ }
223
+ isDropZoneEnlarged = true;
224
+ }
225
+ };
226
+
227
+ this.dropZoneReduce = function () {
228
+ if (typeof uploadHandler.dropZone.switchClass === func) {
229
+ uploadHandler.dropZone.switchClass(
230
+ uploadHandler.cssClassLarge,
231
+ uploadHandler.cssClassSmall
232
+ );
233
+ } else {
234
+ uploadHandler.dropZone.addClass(uploadHandler.cssClassSmall);
235
+ uploadHandler.dropZone.removeClass(uploadHandler.cssClassLarge);
236
+ }
237
+ isDropZoneEnlarged = false;
238
+ };
239
+
240
+ this.onDocumentDragEnter = function (event) {
241
+ uploadHandler.dropZoneEnlarge();
242
+ };
243
+
244
+ this.onDocumentDragOver = function (event) {
245
+ if (dragOverTimeout) {
246
+ clearTimeout(dragOverTimeout);
247
+ }
248
+ dragOverTimeout = setTimeout(function () {
249
+ uploadHandler.dropZoneReduce();
250
+ }, 200);
251
+ };
252
+
253
+ this.onDragEnter = this.onDragLeave = function (event) {
254
+ uploadHandler.dropZone.toggleClass(uploadHandler.cssClassHighlight);
255
+ };
256
+
257
+ this.onDrop = function (event) {
258
+ if (dragOverTimeout) {
259
+ clearTimeout(dragOverTimeout);
260
+ }
261
+ if (uploadHandler.dropEffect && typeof uploadHandler.dropZone.effect === func) {
262
+ uploadHandler.dropZone.effect(uploadHandler.dropEffect, function () {
263
+ uploadHandler.dropZone.removeClass(uploadHandler.cssClassHighlight);
264
+ uploadHandler.dropZoneReduce();
265
+ });
266
+ } else {
267
+ uploadHandler.dropZone.removeClass(uploadHandler.cssClassHighlight);
268
+ uploadHandler.dropZoneReduce();
269
+ }
270
+ };
271
+
272
+ $.extend(this, options);
273
+ };
274
+
275
+ methods = {
276
+ init : function (options) {
277
+ return this.each(function () {
278
+ $(this).fileUpload(new UploadHandler($(this), options));
279
+ });
280
+ },
281
+
282
+ option: function (option, value, namespace) {
283
+ if (typeof option === undef || (typeof option === 'string' && typeof value === undef)) {
284
+ return $(this).fileUpload('option', option, value, namespace);
285
+ }
286
+ return this.each(function () {
287
+ $(this).fileUpload('option', option, value, namespace);
288
+ });
289
+ },
290
+
291
+ destroy : function (namespace) {
292
+ return this.each(function () {
293
+ $(this).fileUpload('destroy', namespace);
294
+ });
295
+ }
296
+ };
297
+
298
+ $.fn.fileUploadUI = function (method) {
299
+ if (methods[method]) {
300
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
301
+ } else if (typeof method === 'object' || !method) {
302
+ return methods.init.apply(this, arguments);
303
+ } else {
304
+ $.error('Method ' + method + ' does not exist on jQuery.fileUploadUI');
305
+ }
306
+ };
307
+
308
+ }(jQuery));
@@ -0,0 +1,629 @@
1
+ /*
2
+ * jQuery File Upload Plugin 3.7.1
3
+ *
4
+ * Copyright 2010, Sebastian Tschan, AQUANTUM
5
+ * Licensed under the MIT license:
6
+ * http://creativecommons.org/licenses/MIT/
7
+ *
8
+ * https://blueimp.net
9
+ * http://www.aquantum.de
10
+ */
11
+
12
+ /*jslint browser: true */
13
+ /*global File, FileReader, FormData, unescape, jQuery */
14
+
15
+ (function ($) {
16
+
17
+ var defaultNamespace = 'file_upload',
18
+ undef = 'undefined',
19
+ func = 'function',
20
+ num = 'number',
21
+ FileUpload,
22
+ methods,
23
+
24
+ MultiLoader = function (callBack, numberComplete) {
25
+ var loaded = 0;
26
+ this.complete = function () {
27
+ loaded += 1;
28
+ if (loaded === numberComplete) {
29
+ callBack();
30
+ }
31
+ };
32
+ };
33
+
34
+ FileUpload = function (container) {
35
+ var fileUpload = this,
36
+ uploadForm,
37
+ fileInput,
38
+ settings = {
39
+ namespace: defaultNamespace,
40
+ uploadFormFilter: function (index) {
41
+ return true;
42
+ },
43
+ fileInputFilter: function (index) {
44
+ return true;
45
+ },
46
+ cssClass: defaultNamespace,
47
+ dragDropSupport: true,
48
+ dropZone: container,
49
+ url: function (form) {
50
+ return form.attr('action');
51
+ },
52
+ method: function (form) {
53
+ return form.attr('method');
54
+ },
55
+ fieldName: function (input) {
56
+ return input.attr('name');
57
+ },
58
+ formData: function (form) {
59
+ return form.serializeArray();
60
+ },
61
+ multipart: true,
62
+ multiFileRequest: false,
63
+ withCredentials: false,
64
+ forceIframeUpload: false
65
+ },
66
+ documentListeners = {},
67
+ dropZoneListeners = {},
68
+ protocolRegExp = /^http(s)?:\/\//,
69
+ optionsReference,
70
+
71
+ isXHRUploadCapable = function () {
72
+ return typeof XMLHttpRequest !== undef && typeof File !== undef && (
73
+ !settings.multipart || typeof FormData !== undef || typeof FileReader !== undef
74
+ );
75
+ },
76
+
77
+ initEventHandlers = function () {
78
+ if (settings.dragDropSupport) {
79
+ if (typeof settings.onDocumentDragEnter === func) {
80
+ documentListeners['dragenter.' + settings.namespace] = function (e) {
81
+ settings.onDocumentDragEnter(e);
82
+ };
83
+ }
84
+ if (typeof settings.onDocumentDragLeave === func) {
85
+ documentListeners['dragleave.' + settings.namespace] = function (e) {
86
+ settings.onDocumentDragLeave(e);
87
+ };
88
+ }
89
+ documentListeners['dragover.' + settings.namespace] = fileUpload.onDocumentDragOver;
90
+ documentListeners['drop.' + settings.namespace] = fileUpload.onDocumentDrop;
91
+ $(document).bind(documentListeners);
92
+ if (typeof settings.onDragEnter === func) {
93
+ dropZoneListeners['dragenter.' + settings.namespace] = function (e) {
94
+ settings.onDragEnter(e);
95
+ };
96
+ }
97
+ if (typeof settings.onDragLeave === func) {
98
+ dropZoneListeners['dragleave.' + settings.namespace] = function (e) {
99
+ settings.onDragLeave(e);
100
+ };
101
+ }
102
+ dropZoneListeners['dragover.' + settings.namespace] = fileUpload.onDragOver;
103
+ dropZoneListeners['drop.' + settings.namespace] = fileUpload.onDrop;
104
+ settings.dropZone.bind(dropZoneListeners);
105
+ }
106
+ fileInput.bind('change.' + settings.namespace, fileUpload.onChange);
107
+ },
108
+
109
+ removeEventHandlers = function () {
110
+ $.each(documentListeners, function (key, value) {
111
+ $(document).unbind(key, value);
112
+ });
113
+ $.each(dropZoneListeners, function (key, value) {
114
+ settings.dropZone.unbind(key, value);
115
+ });
116
+ fileInput.unbind('change.' + settings.namespace);
117
+ },
118
+
119
+ initUploadEventHandlers = function (files, index, xhr, settings) {
120
+ if (typeof settings.onProgress === func) {
121
+ xhr.upload.onprogress = function (e) {
122
+ settings.onProgress(e, files, index, xhr, settings);
123
+ };
124
+ }
125
+ if (typeof settings.onLoad === func) {
126
+ xhr.onload = function (e) {
127
+ settings.onLoad(e, files, index, xhr, settings);
128
+ };
129
+ }
130
+ if (typeof settings.onAbort === func) {
131
+ xhr.onabort = function (e) {
132
+ settings.onAbort(e, files, index, xhr, settings);
133
+ };
134
+ }
135
+ if (typeof settings.onError === func) {
136
+ xhr.onerror = function (e) {
137
+ settings.onError(e, files, index, xhr, settings);
138
+ };
139
+ }
140
+ },
141
+
142
+ getUrl = function (settings) {
143
+ if (typeof settings.url === func) {
144
+ return settings.url(settings.uploadForm || uploadForm);
145
+ }
146
+ return settings.url;
147
+ },
148
+
149
+ getMethod = function (settings) {
150
+ if (typeof settings.method === func) {
151
+ return settings.method(settings.uploadForm || uploadForm);
152
+ }
153
+ return settings.method;
154
+ },
155
+
156
+ getFieldName = function (settings) {
157
+ if (typeof settings.fieldName === func) {
158
+ return settings.fieldName(settings.fileInput || fileInput);
159
+ }
160
+ return settings.fieldName;
161
+ },
162
+
163
+ getFormData = function (settings) {
164
+ var formData;
165
+ if (typeof settings.formData === func) {
166
+ return settings.formData(settings.uploadForm || uploadForm);
167
+ } else if ($.isArray(settings.formData)) {
168
+ return settings.formData;
169
+ } else if (settings.formData) {
170
+ formData = [];
171
+ $.each(settings.formData, function (name, value) {
172
+ formData.push({name: name, value: value});
173
+ });
174
+ return formData;
175
+ }
176
+ return [];
177
+ },
178
+
179
+ isSameDomain = function (url) {
180
+ if (protocolRegExp.test(url)) {
181
+ var host = location.host,
182
+ indexStart = location.protocol.length + 2,
183
+ index = url.indexOf(host, indexStart),
184
+ pathIndex = index + host.length;
185
+ if ((index === indexStart || index === url.indexOf('@', indexStart) + 1) &&
186
+ (url.length === pathIndex || $.inArray(url.charAt(pathIndex), ['/', '?', '#']) !== -1)) {
187
+ return true;
188
+ }
189
+ return false;
190
+ }
191
+ return true;
192
+ },
193
+
194
+ nonMultipartUpload = function (file, xhr, sameDomain) {
195
+ if (sameDomain) {
196
+ xhr.setRequestHeader('X-File-Name', unescape(encodeURIComponent(file.name)));
197
+ }
198
+ xhr.setRequestHeader('Content-Type', file.type);
199
+ xhr.send(file);
200
+ },
201
+
202
+ formDataUpload = function (files, xhr, settings) {
203
+ var formData = new FormData(),
204
+ i;
205
+ $.each(getFormData(settings), function (index, field) {
206
+ formData.append(field.name, field.value);
207
+ });
208
+ for (i = 0; i < files.length; i += 1) {
209
+ formData.append(getFieldName(settings), files[i]);
210
+ }
211
+ xhr.send(formData);
212
+ },
213
+
214
+ loadFileContent = function (file, callBack) {
215
+ var fileReader = new FileReader();
216
+ fileReader.onload = function (e) {
217
+ file.content = e.target.result;
218
+ callBack();
219
+ };
220
+ fileReader.readAsBinaryString(file);
221
+ },
222
+
223
+ buildMultiPartFormData = function (boundary, files, filesFieldName, fields) {
224
+ var doubleDash = '--',
225
+ crlf = '\r\n',
226
+ formData = '';
227
+ $.each(fields, function (index, field) {
228
+ formData += doubleDash + boundary + crlf +
229
+ 'Content-Disposition: form-data; name="' +
230
+ unescape(encodeURIComponent(field.name)) +
231
+ '"' + crlf + crlf +
232
+ unescape(encodeURIComponent(field.value)) + crlf;
233
+ });
234
+ $.each(files, function (index, file) {
235
+ formData += doubleDash + boundary + crlf +
236
+ 'Content-Disposition: form-data; name="' +
237
+ unescape(encodeURIComponent(filesFieldName)) +
238
+ '"; filename="' + unescape(encodeURIComponent(file.name)) + '"' + crlf +
239
+ 'Content-Type: ' + file.type + crlf + crlf +
240
+ file.content + crlf;
241
+ });
242
+ formData += doubleDash + boundary + doubleDash + crlf;
243
+ return formData;
244
+ },
245
+
246
+ fileReaderUpload = function (files, xhr, settings) {
247
+ var boundary = '----MultiPartFormBoundary' + (new Date()).getTime(),
248
+ loader,
249
+ i;
250
+ xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
251
+ loader = new MultiLoader(function () {
252
+ xhr.sendAsBinary(buildMultiPartFormData(
253
+ boundary,
254
+ files,
255
+ getFieldName(settings),
256
+ getFormData(settings)
257
+ ));
258
+ }, files.length);
259
+ for (i = 0; i < files.length; i += 1) {
260
+ loadFileContent(files[i], loader.complete);
261
+ }
262
+ },
263
+
264
+ upload = function (files, index, xhr, settings) {
265
+ var url = getUrl(settings),
266
+ sameDomain = isSameDomain(url),
267
+ filesToUpload;
268
+ initUploadEventHandlers(files, index, xhr, settings);
269
+ xhr.open(getMethod(settings), url, true);
270
+ if (sameDomain) {
271
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
272
+ } else if (settings.withCredentials) {
273
+ xhr.withCredentials = true;
274
+ }
275
+ if (!settings.multipart) {
276
+ nonMultipartUpload(files[index], xhr, sameDomain);
277
+ } else {
278
+ if (typeof index === num) {
279
+ filesToUpload = [files[index]];
280
+ } else {
281
+ filesToUpload = files;
282
+ }
283
+ if (typeof FormData !== undef) {
284
+ formDataUpload(filesToUpload, xhr, settings);
285
+ } else if (typeof FileReader !== undef) {
286
+ fileReaderUpload(filesToUpload, xhr, settings);
287
+ } else {
288
+ $.error('Browser does neither support FormData nor FileReader interface');
289
+ }
290
+ }
291
+ },
292
+
293
+ handleUpload = function (event, files, input, form, index) {
294
+ var xhr = new XMLHttpRequest(),
295
+ uploadSettings = $.extend({}, settings);
296
+ uploadSettings.fileInput = input;
297
+ uploadSettings.uploadForm = form;
298
+ if (typeof uploadSettings.initUpload === func) {
299
+ uploadSettings.initUpload(
300
+ event,
301
+ files,
302
+ index,
303
+ xhr,
304
+ uploadSettings,
305
+ function () {
306
+ upload(files, index, xhr, uploadSettings);
307
+ }
308
+ );
309
+ } else {
310
+ upload(files, index, xhr, uploadSettings);
311
+ }
312
+ },
313
+
314
+ handleFiles = function (event, files, input, form) {
315
+ var i;
316
+ if (settings.multiFileRequest) {
317
+ handleUpload(event, files, input, form);
318
+ } else {
319
+ for (i = 0; i < files.length; i += 1) {
320
+ handleUpload(event, files, input, form, i);
321
+ }
322
+ }
323
+ },
324
+
325
+ legacyUploadFormDataInit = function (input, form, settings) {
326
+ var formData = getFormData(settings);
327
+ form.find(':input').not(':disabled')
328
+ .attr('disabled', true)
329
+ .addClass(settings.namespace + '_disabled');
330
+ $.each(formData, function (index, field) {
331
+ $('<input type="hidden"/>')
332
+ .attr('name', field.name)
333
+ .val(field.value)
334
+ .addClass(settings.namespace + '_form_data')
335
+ .appendTo(form);
336
+ });
337
+ input
338
+ .attr('name', getFieldName(settings))
339
+ .appendTo(form);
340
+ },
341
+
342
+ legacyUploadFormDataReset = function (input, form, settings) {
343
+ input.detach();
344
+ form.find('.' + settings.namespace + '_disabled')
345
+ .removeAttr('disabled')
346
+ .removeClass(settings.namespace + '_disabled');
347
+ form.find('.' + settings.namespace + '_form_data').remove();
348
+ },
349
+
350
+ legacyUpload = function (input, form, iframe, settings) {
351
+ var originalAction = form.attr('action'),
352
+ originalMethod = form.attr('method'),
353
+ originalTarget = form.attr('target');
354
+ iframe
355
+ .unbind('abort')
356
+ .bind('abort', function (e) {
357
+ iframe.readyState = 0;
358
+ // javascript:false as iframe src prevents warning popups on HTTPS in IE6
359
+ // concat is used here to prevent the "Script URL" JSLint error:
360
+ iframe.unbind('load').attr('src', 'javascript'.concat(':false;'));
361
+ if (typeof settings.onAbort === func) {
362
+ settings.onAbort(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);
363
+ }
364
+ })
365
+ .unbind('load')
366
+ .bind('load', function (e) {
367
+ iframe.readyState = 4;
368
+ if (typeof settings.onLoad === func) {
369
+ settings.onLoad(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);
370
+ }
371
+ // Fix for IE endless progress bar activity bug (happens on form submits to iframe targets):
372
+ $('<iframe src="javascript:false;" style="display:none"></iframe>').appendTo(form).remove();
373
+ });
374
+ form
375
+ .attr('action', getUrl(settings))
376
+ .attr('method', getMethod(settings))
377
+ .attr('target', iframe.attr('name'));
378
+ legacyUploadFormDataInit(input, form, settings);
379
+ iframe.readyState = 2;
380
+ form.get(0).submit();
381
+ legacyUploadFormDataReset(input, form, settings);
382
+ form
383
+ .attr('action', originalAction)
384
+ .attr('method', originalMethod)
385
+ .attr('target', originalTarget);
386
+ },
387
+
388
+ handleLegacyUpload = function (event, input, form) {
389
+ // javascript:false as iframe src prevents warning popups on HTTPS in IE6:
390
+ var iframe = $('<iframe src="javascript:false;" style="display:none" name="iframe_' +
391
+ settings.namespace + '_' + (new Date()).getTime() + '"></iframe>'),
392
+ uploadSettings = $.extend({}, settings);
393
+ uploadSettings.fileInput = input;
394
+ uploadSettings.uploadForm = form;
395
+ iframe.readyState = 0;
396
+ iframe.abort = function () {
397
+ iframe.trigger('abort');
398
+ };
399
+ iframe.bind('load', function () {
400
+ iframe.unbind('load');
401
+ if (typeof uploadSettings.initUpload === func) {
402
+ uploadSettings.initUpload(
403
+ event,
404
+ [{name: input.val(), type: null, size: null}],
405
+ 0,
406
+ iframe,
407
+ uploadSettings,
408
+ function () {
409
+ legacyUpload(input, form, iframe, uploadSettings);
410
+ }
411
+ );
412
+ } else {
413
+ legacyUpload(input, form, iframe, uploadSettings);
414
+ }
415
+ }).appendTo(form);
416
+ },
417
+
418
+ initUploadForm = function () {
419
+ uploadForm = (container.is('form') ? container : container.find('form'))
420
+ .filter(settings.uploadFormFilter);
421
+ },
422
+
423
+ initFileInput = function () {
424
+ fileInput = uploadForm.find('input:file')
425
+ .filter(settings.fileInputFilter);
426
+ },
427
+
428
+ replaceFileInput = function (input) {
429
+ var inputClone = input.clone(true);
430
+ $('<form/>').append(inputClone).get(0).reset();
431
+ input.after(inputClone).detach();
432
+ initFileInput();
433
+ };
434
+
435
+ this.onDocumentDragOver = function (e) {
436
+ if (typeof settings.onDocumentDragOver === func &&
437
+ settings.onDocumentDragOver(e) === false) {
438
+ return false;
439
+ }
440
+ e.preventDefault();
441
+ };
442
+
443
+ this.onDocumentDrop = function (e) {
444
+ if (typeof settings.onDocumentDrop === func &&
445
+ settings.onDocumentDrop(e) === false) {
446
+ return false;
447
+ }
448
+ e.preventDefault();
449
+ };
450
+
451
+ this.onDragOver = function (e) {
452
+ if (typeof settings.onDragOver === func &&
453
+ settings.onDragOver(e) === false) {
454
+ return false;
455
+ }
456
+ var dataTransfer = e.originalEvent.dataTransfer;
457
+ if (dataTransfer) {
458
+ dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy';
459
+ }
460
+ e.preventDefault();
461
+ };
462
+
463
+ this.onDrop = function (e) {
464
+ if (typeof settings.onDrop === func &&
465
+ settings.onDrop(e) === false) {
466
+ return false;
467
+ }
468
+ var dataTransfer = e.originalEvent.dataTransfer;
469
+ if (dataTransfer && dataTransfer.files && isXHRUploadCapable()) {
470
+ handleFiles(e, dataTransfer.files);
471
+ }
472
+ e.preventDefault();
473
+ };
474
+
475
+ this.onChange = function (e) {
476
+ if (typeof settings.onChange === func &&
477
+ settings.onChange(e) === false) {
478
+ return false;
479
+ }
480
+ var input = $(e.target),
481
+ form = $(e.target.form);
482
+ if (form.length === 1) {
483
+ input.data(defaultNamespace + '_form', form);
484
+ replaceFileInput(input);
485
+ } else {
486
+ form = input.data(defaultNamespace + '_form');
487
+ }
488
+ if (!settings.forceIframeUpload && e.target.files && isXHRUploadCapable()) {
489
+ handleFiles(e, e.target.files, input, form);
490
+ } else {
491
+ handleLegacyUpload(e, input, form);
492
+ }
493
+ };
494
+
495
+ this.init = function (options) {
496
+ if (options) {
497
+ $.extend(settings, options);
498
+ optionsReference = options;
499
+ }
500
+ initUploadForm();
501
+ initFileInput();
502
+ if (container.data(settings.namespace)) {
503
+ $.error('FileUpload with namespace "' + settings.namespace + '" already assigned to this element');
504
+ return;
505
+ }
506
+ container
507
+ .data(settings.namespace, fileUpload)
508
+ .addClass(settings.cssClass);
509
+ settings.dropZone.not(container).addClass(settings.cssClass);
510
+ initEventHandlers();
511
+ };
512
+
513
+ this.options = function (options) {
514
+ var oldCssClass,
515
+ oldDropZone,
516
+ uploadFormFilterUpdate,
517
+ fileInputFilterUpdate;
518
+ if (typeof options === undef) {
519
+ return $.extend({}, settings);
520
+ }
521
+ if (optionsReference) {
522
+ $.extend(optionsReference, options);
523
+ }
524
+ removeEventHandlers();
525
+ $.each(options, function (name, value) {
526
+ switch (name) {
527
+ case 'namespace':
528
+ $.error('The FileUpload namespace cannot be updated.');
529
+ return;
530
+ case 'uploadFormFilter':
531
+ uploadFormFilterUpdate = true;
532
+ fileInputFilterUpdate = true;
533
+ break;
534
+ case 'fileInputFilter':
535
+ fileInputFilterUpdate = true;
536
+ break;
537
+ case 'cssClass':
538
+ oldCssClass = settings.cssClass;
539
+ break;
540
+ case 'dropZone':
541
+ oldDropZone = settings.dropZone;
542
+ break;
543
+ }
544
+ settings[name] = value;
545
+ });
546
+ if (uploadFormFilterUpdate) {
547
+ initUploadForm();
548
+ }
549
+ if (fileInputFilterUpdate) {
550
+ initFileInput();
551
+ }
552
+ if (typeof oldCssClass !== undef) {
553
+ container
554
+ .removeClass(oldCssClass)
555
+ .addClass(settings.cssClass);
556
+ (oldDropZone ? oldDropZone : settings.dropZone).not(container)
557
+ .removeClass(oldCssClass);
558
+ settings.dropZone.not(container).addClass(settings.cssClass);
559
+ } else if (oldDropZone) {
560
+ oldDropZone.not(container).removeClass(settings.cssClass);
561
+ settings.dropZone.not(container).addClass(settings.cssClass);
562
+ }
563
+ initEventHandlers();
564
+ };
565
+
566
+ this.option = function (name, value) {
567
+ var options;
568
+ if (typeof value === undef) {
569
+ return settings[name];
570
+ }
571
+ options = {};
572
+ options[name] = value;
573
+ fileUpload.options(options);
574
+ };
575
+
576
+ this.destroy = function () {
577
+ removeEventHandlers();
578
+ container
579
+ .removeData(settings.namespace)
580
+ .removeClass(settings.cssClass);
581
+ settings.dropZone.not(container).removeClass(settings.cssClass);
582
+ };
583
+ };
584
+
585
+ methods = {
586
+ init : function (options) {
587
+ return this.each(function () {
588
+ (new FileUpload($(this))).init(options);
589
+ });
590
+ },
591
+
592
+ option: function (option, value, namespace) {
593
+ namespace = namespace ? namespace : defaultNamespace;
594
+ var fileUpload = $(this).data(namespace);
595
+ if (fileUpload) {
596
+ if (typeof option === 'string') {
597
+ return fileUpload.option(option, value);
598
+ }
599
+ return fileUpload.options(option);
600
+ } else {
601
+ $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
602
+ }
603
+ },
604
+
605
+ destroy : function (namespace) {
606
+ namespace = namespace ? namespace : defaultNamespace;
607
+ return this.each(function () {
608
+ var fileUpload = $(this).data(namespace);
609
+ if (fileUpload) {
610
+ fileUpload.destroy();
611
+ } else {
612
+ $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
613
+ }
614
+ });
615
+
616
+ }
617
+ };
618
+
619
+ $.fn.fileUpload = function (method) {
620
+ if (methods[method]) {
621
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
622
+ } else if (typeof method === 'object' || !method) {
623
+ return methods.init.apply(this, arguments);
624
+ } else {
625
+ $.error('Method ' + method + ' does not exist on jQuery.fileUpload');
626
+ }
627
+ };
628
+
629
+ }(jQuery));
@@ -19,7 +19,6 @@ table.index .size {
19
19
 
20
20
  #assets .icon {
21
21
  display: block;
22
- float: left;
23
22
  text-align: center;
24
23
  background: #ccc;
25
24
  text-transform: uppercase;
@@ -36,6 +35,7 @@ table#assets .icon, table#assets .thumbnail {
36
35
 
37
36
  table#assets .icon {
38
37
  font-size: 75%;
38
+ float: left;
39
39
  }
40
40
 
41
41
  #assets, #assets li {
@@ -46,6 +46,7 @@ table#assets .icon {
46
46
  }
47
47
 
48
48
  #assets li {
49
+ background: #ccc;
49
50
  float: left;
50
51
  margin-right: 1px;
51
52
  margin-bottom: 1px;
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: radiant-assets-extension
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Gerrit Kaiser
@@ -88,6 +88,11 @@ files:
88
88
  - lib/radiant-assets-extension/s3_store.rb
89
89
  - lib/radiant-assets-extension/version.rb
90
90
  - lib/tasks/assets_extension_tasks.rake
91
+ - public/jquery.fileupload/.gitignore
92
+ - public/jquery.fileupload/jquery.fileupload-ui.css
93
+ - public/jquery.fileupload/jquery.fileupload-ui.js
94
+ - public/jquery.fileupload/jquery.fileupload.js
95
+ - public/jquery.fileupload/pbar-ani.gif
91
96
  - public/stylesheets/admin/extensions/assets/assets.css
92
97
  - radiant-assets-extension.gemspec
93
98
  - spec/spec.opts
@@ -96,7 +101,7 @@ has_rdoc: true
96
101
  homepage: http://ext.radiantcms.org/extensions/269-assets
97
102
  licenses: []
98
103
 
99
- post_install_message: "\n Add this to your radiant project with:\n config.gem 'radiant-assets-extension', :version => '0.0.4'\n "
104
+ post_install_message: "\n Add this to your radiant project with:\n config.gem 'radiant-assets-extension', :version => '0.0.5'\n "
100
105
  rdoc_options: []
101
106
 
102
107
  require_paths: