radiant-assets-extension 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: