Permalink
Browse files

use postMessage and display upload elements on host page

  • Loading branch information...
Nico
Nico committed Feb 20, 2012
1 parent ff44268 commit 9e2c2d00cc8f408f2525f22f77a9dcead42d9da3
View

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -1,3 +1,60 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
+jQuery ->
+
+ xhrUploadProgressSupported = () ->
+ xhr = new XMLHttpRequest()
+ xhr && ('upload' of xhr) && ('onprogress' of xhr.upload)
+
+ randomString = (length) ->
+ chars = '0123456789abcdefghiklmnopqrstuvwxyz'
+ sRnd = ''
+ for i in [0...length]
+ randomPoz = Math.floor Math.random() * chars.length
+ sRnd += chars.substring randomPoz,randomPoz+1
+
+ sRnd
+
+ # Can only track progress if size property is present on files.
+ progressSupported = xhrUploadProgressSupported()
+
+ $('#uploading_files').on 'click', '.uploading_file .remove_link', (e) ->
+ uuid = $(this).parent().attr('id')
+ $(this).parent().remove()
+ $('#uploader iframe')[0].contentWindow.postMessage({ eventType: 'abort upload', uuid: uuid }, 'http://do2-media.s3.amazonaws.com');
+
+ window.addEventListener "message", (event) ->
+ if event.origin != "http://do2-media.s3.amazonaws.com"
+ return
+
+ eventType = event.data.eventType;
+ delete event.data.eventType;
+
+ data = event.data
+
+ switch eventType
+
+ when 'upload done'
+
+ $(".uploading_file##{data.uuid}").remove()
+
+ $.ajax $('#uploader iframe').data('create-resource-url'),
+ type: 'POST',
+ data: data
+
+
+ when 'add upload'
+
+ if progressSupported
+ uploadPercent = "<br/><progress value='0' max='100' class='upload_progress_bar'>0</progress> <span class='upload_percentage'>0</span> %";
+ $('#uploading_files').append("<p class='uploading_file'>#{data.file_name + uploadPercent} <a href='#' class='remove_link'>X<a/></p>");
+ else
+ $('#uploading_files').append("<p class='uploading_file'>#{data.file_name}<br/><img src='img/uploading.gif'/></p>");
+
+ $('.uploading_file').last().attr 'id', data.uuid
+
+
+ when 'upload progress'
+
+ if progressSupported
+ $(".uploading_file##{data.uuid}").find('.upload_percentage').html(data.progress)
+ $(".uploading_file##{data.uuid}").find('.upload_progress_bar').val(data.progress)
+
@@ -26,4 +26,37 @@ h1{
min-height: 300px;
padding: 10px;
border-radius: 7px;
+}
+
+
+progress{
+ width: 200px;
+}
+
+#drag_text{
+ position: absolute;
+ z-index: 0;
+ top:0;
+ left:0;
+ width: 500px;
+ padding-top:100px;
+ text-align: center;
+ font-size: 2em;
+ font-weight: bold;
+ color: #ddd;
+ font-style:italic;
+}
+
+#uploading_files, #file_upload{
+ position: relative;
+ z-index: 1;
+}
+
+#drag_remark{
+ font-size: 0.5em;
+}
+
+.remove_link{
+ color: red;
+ text-decoration: none;
}
@@ -2,72 +2,23 @@
class UploadsController < ApplicationController
def index
-
- #uploader_html = render_to_string( partial: 'uploads/uploader',
- # locals: { after_upload_url: url_for(controller: controller_name, action: create) } )
- #ensure_s3_connection!
- #AWS::S3::S3Object.store(
- # 'uploader/uploader.html',
- # uploader_html,
- # S3_CONFIG['bucket_name'],
- # :access => :public_read
- #)
-
-
- # raise s3_signature(path: folder)
-
- folder = 'uploaded_files'
- @frame_params = (["key=#{s3_key(folder)}",
- "AWSAccessKeyId=#{S3_CONFIG['access_key_id']}",
- "policy=#{s3_policy(path: folder)}",
- "signature=#{s3_signature(path: folder)}"].join('&')).gsub('=', '%3D')
- end
-
-
- def s3_bucket_url
- "http://#{S3_CONFIG['bucket_name']}.s3.amazonaws.com/"
- end
-
-
- def s3_key path
- "#{path}/${filename}"
- end
-
-
- def s3_policy options = {}
- options[:content_type] ||= ''
- options[:acl] ||= 'public-read'
- options[:max_file_size] ||= 20.megabyte
- options[:path] ||= ''
-
- Base64.encode64(
- "{'expiration': '#{10.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')}',
- 'conditions': [
- {'bucket': '#{S3_CONFIG['bucket_name']}'},
- ['starts-with', '$key', '#{options[:path]}'],
- {'acl': '#{options[:acl]}'},
- {'success_action_status': '201'},
- ['content-length-range', 0, #{options[:max_file_size]}],
- ['starts-with', '#{options[:content_type]}', '']
- ]
- }").gsub(/\n|\r/, '')
- end
-
-
- def s3_signature options = {}
- Base64.encode64(
- OpenSSL::HMAC.digest(
- OpenSSL::Digest::Digest.new('sha1'),
- S3_CONFIG['secret_access_key'], s3_policy(options))).gsub("\n","")
+ uploader_html = render_to_string( partial: 'uploads/uploader' )
+ ensure_s3_connection!
+ AWS::S3::S3Object.store(
+ 'uploader/uploader.html',
+ uploader_html,
+ S3_CONFIG['bucket_name'],
+ :access => :public_read
+ )
end
def create
- @upload = Upload.new(params[:upload])
+ @upload = Upload.new(params[:upload] || params.delete_if{ |p| !Upload.attribute_names.include?(p) })
if @upload.save
- render text: 'Upload created!', status: 201
+ render nothing: true
+ #render js: "$('#uploading_files').html('Test')", status: 201
end
-
headers['Access-Control-Allow-Origin'] = 'http://do2-media.s3.amazonaws.com'
headers['Access-Control-Allow-Methods'] = '*'
end
@@ -1,5 +1,26 @@
module UploadsHelper
+
+ def s3_uploader options = {}
+ options[:uploader_path] ||= 'uploader/uploader.html'
+ options[:uploaded_files_path] ||= "#{controller_name}/:uuid"
+ options[:create_resource_url] ||= url_for(only_path: false)
+ options[:resource_name] ||= controller_name.singularize
+
+ upload_params = { key: s3_key(options[:uploaded_files_path]),
+ AWSAccessKeyId: S3_CONFIG['access_key_id'],
+ _policy: s3_policy(path: options[:uploaded_files_path]),
+ _signature: s3_signature(path: options[:uploaded_files_path]) }.to_query
+
+ content_tag :iframe, '',
+ src: "http://#{S3_CONFIG['bucket_name']}.s3.amazonaws.com/#{options[:uploader_path]}?#{upload_params}",
+ frameborder: 0,
+ height: options[:iframe_height] || 60,
+ width: options[:iframe_width] || 500,
+ data: { create_resource_url: options[:create_resource_url] }
+ end
+
+
def s3_bucket_url
"http://#{S3_CONFIG['bucket_name']}.s3.amazonaws.com/"
end
@@ -20,11 +41,11 @@ def s3_policy options = {}
"{'expiration': '#{10.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')}',
'conditions': [
{'bucket': '#{S3_CONFIG['bucket_name']}'},
- ['starts-with', '$key', '#{options[:path]}'],
+ ['starts-with', '$key', ''],
{'acl': '#{options[:acl]}'},
{'success_action_status': '201'},
['content-length-range', 0, #{options[:max_file_size]}],
- ['starts-with', '#{options[:content_type]}', '']
+ ['starts-with','$Content-Type','']
]
}").gsub(/\n|\r/, '')
end
@@ -37,4 +58,5 @@ def s3_signature options = {}
S3_CONFIG['secret_access_key'], s3_policy(options))).gsub("\n","")
end
+
end
View
@@ -1,2 +1,4 @@
class Upload < ActiveRecord::Base
+
+
end
@@ -19,7 +19,6 @@
color:#666666;
margin:0;
padding:0;
- height: 300px;
}
progress{
@@ -31,7 +30,7 @@
z-index: 0;
top:0;
left:0;
- width: 500px;
+
padding-top:100px;
text-align: center;
font-size: 2em;
@@ -75,81 +74,89 @@
%input{:type => :file, :name => 'file', multiple: ''}
- #uploading_files
-
:javascript
$(function() {
- //alert(location.href.replace(/%2F/g, '/').replace(/%3D/g, '='))
- var params = location.href.replace(/%3D/g, '=').split('?')[1].split('&');
+
+ var params = unescape(location.href).split('?')[1].split('&');
+
+ var createResourceUrl;
+
+ var jqXHR = new Array();
+
+ //// Can only track progress if size property is present on files.
+ //var progressSupported = xhrUploadProgressSupported();
for (x in params){
- $('#file_upload input[name=' + params[x].split('=')[0] + ']').val(params[x].substring(params[x].search('=')+1));
+ key = params[x].split('=')[0]
+ val = params[x].substring(params[x].search('=')+1);
+ $('#file_upload input[name=' + key.replace(/^_/,'') + ']').val(val);
}
+
// Opera doesn't handle multiple files properly so use single file selection there
if (navigator.appName == 'Opera') {
$('#file_upload').find('input:file').each(function () {
$(this).removeAttr('multiple')
- // Fix for Opera, which ignores just removing the multiple attribute:
- .replaceWith($(this).clone(true));
+ // Fix for Opera, which ignores just removing the multiple attribute:
+ .replaceWith($(this).clone(true));
});
}
- function xhrUploadProgressSupported(){
- var xhr = new XMLHttpRequest();
- return !! (xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
+ function randomString(length) {
+ var chars = 'abcdefghiklmnopqrstuvwxyz';
+ var sRnd = '';
+ for (var i=0; i<length; i++){
+ var randomPoz = Math.floor(Math.random() * chars.length);
+ sRnd += chars.substring(randomPoz,randomPoz+1);
+ }
+ return sRnd;
}
+ window.addEventListener("message", function (e) {
+ if (e.origin !== "http://localhost:3000")
+ return;
+ jqXHR[e.data.uuid].abort();
+ });
+
$('#file_upload').fileupload({
dropZone: $(document.body),
url: "#{s3_bucket_url}",
formData: function (form) {
- return form.serializeArray();
+ data = form.serializeArray();
+ if ('type' in this.files[0])
+ data.push({ name: 'Content-Type', value: this.files[0].type })
+ data[0].value = data[0].value.replace(':uuid', this.context)
+ return data;
},
fail: function(e, data) {
//
},
add: function (e, data) {
- // Can only track progress if size property is present on files.
-
- progressSupported = xhrUploadProgressSupported();
- $.each(data.files, function (index, file) {
- if( progressSupported ){
- var uploadPercent = "<br/><progress value='0' max='100' class='upload_progress_bar'>0</progress> <span class='upload_percentage'>0</span>" + '%';
- $('#uploading_files').append("<p class='uploading_file'>" + file.name + uploadPercent + " <a href='#' class='remove_link'>X<a/></p>");
- } else
- $('#uploading_files').append("<p class='uploading_file'>" + file.name + "<br/><img src='img/uploading.gif'/></p>");
- });
-
- data.context = $('.uploading_file').last();
- data.jqXHR = data.submit();
-
- $('.uploading_file .remove_link').last().click(function (e) {
- data.jqXHR.abort();
- data.context.hide()
- });
+ postData = { eventType: 'add upload' }
+ postData.uuidInKey = $('#file_upload input[name=key]').val().search(':uuid') != -1;
+ postData.file_name = data.files[0].name
+ postData.uuid = randomString(20);
+
+ window.parent.postMessage(postData, 'http://localhost:3000');
+
+ data.context = postData.uuid;
+ jqXHR[postData.uuid] = data.submit();
+
},
progress: function (e, data) {
- if( xhrUploadProgressSupported() ){
- var progress = parseInt(data.loaded / data.total * 100, 10);
- data.context.find('.upload_percentage').html(progress);
- data.context.find('.upload_progress_bar').val(progress);
- }
+ window.parent.postMessage({ eventType: 'upload progress',
+ uuid: data.context,
+ progress: parseInt(data.loaded / data.total * 100, 10) },
+ 'http://localhost:3000');
},
done: function (e, data) {
- data.context.hide();
var file = data.files[0];
- //var params = { file_name: file.name }
- //if ('size' in file)
- // params.file_size = file.size;
- //if ('type' in file)
- // params.file_type = file.type;
- //$.ajax('#{after_upload_url}',
- // { type: 'POST',
- // data: "upload[file_name]=" + encodeURIComponent(file.name) } )
+ var postData = { eventType: 'upload done', uuid: data.context };
+ postData.file_name = file.name;
+ postData.s3_key = $('#file_upload input[name=key]').val().replace('/${filename}', '').replace(':uuid', data.context);
+ if( 'size' in file ) postData.file_size = file.size;
+ if( 'type' in file ) postData.file_type = file.type;
+ window.parent.postMessage(postData, 'http://localhost:3000');
},
- stop: function(e){
- $('.uploading_file').remove()
- }
});
});
Oops, something went wrong.

0 comments on commit 9e2c2d0

Please sign in to comment.