aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG3
-rwxr-xr-xactionpack/lib/action_controller.rb2
-rwxr-xr-xactionpack/lib/action_controller/base.rb14
-rw-r--r--actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb28
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/javascripts/prototype.js71
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/templates/style.css21
7 files changed, 128 insertions, 16 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 2d39682253..f124a935c0 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,8 @@
*SVN*
+* Added support for upload progress indicators in Apache and lighttpd 1.4.x (won't work in WEBrick or lighttpd 1.3.x) #1475 [Sean Treadway]
+ See http://sean.treadway.info/files/howto-upload-progress-2.mov for example.
+
* Added support for graceful error handling of Ajax calls #1217 [Jamis Buck/Thomas Fuchs]. Example:
link_to_remote(
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index deead18b5a..7cc0d605ae 100755
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -48,6 +48,7 @@ require 'action_controller/cgi_process'
require 'action_controller/caching'
require 'action_controller/components'
require 'action_controller/verification'
+require 'action_controller/upload_progress'
require 'action_controller/streaming'
require 'action_controller/auto_complete'
@@ -69,6 +70,7 @@ ActionController::Base.class_eval do
include ActionController::Caching
include ActionController::Components
include ActionController::Verification
+ include ActionController::UploadProgress
include ActionController::Streaming
include ActionController::AutoComplete
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index bd0e78719d..2e0d554a55 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -508,12 +508,24 @@ module ActionController #:nodoc:
return result
end
- # Clears the rendered results, allowing for another render or redirect to be performed.
+ # Clears the rendered results, allowing for another render to be performed.
def erase_render_results #:nodoc:
@response.body = nil
@performed_render = false
end
+ # Clears the redirected results from the headers, resetting the status to 200 and returns
+ # the URL that was used to redirect or nil if there was no redirected URL
+ # Note that +redirect_to+ will change the body of the response to indicate a redirection.
+ # The response body is not reset here, see +erase_render_results+
+ def erase_redirect_results #:nodoc:
+ @performed_redirect = false
+ response.redirected_to = nil
+ response.redirected_to_method_params = nil
+ response.headers['Status'] = DEFAULT_RENDER_STATUS_CODE
+ response.headers.delete('location')
+ end
+
def rewrite_options(options)
if defaults = default_url_options(options)
defaults.merge(options)
diff --git a/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb b/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb
index 5cb13c2456..b2194eb07b 100644
--- a/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb
+++ b/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb
@@ -6,6 +6,8 @@ class CGI #:nodoc:
# Handles multipart forms (in particular, forms that involve file uploads).
# Reads query parameters in the @params field, and cookies into @cookies.
def initialize_query()
+ @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] || env_table['COOKIE']))
+
if boundary = multipart_form_boundary
@multipart = true
@params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
@@ -13,8 +15,6 @@ class CGI #:nodoc:
@multipart = false
@params = CGI::parse(read_query_params || "")
end
-
- @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] || env_table['COOKIE']))
end
private
@@ -28,16 +28,32 @@ class CGI #:nodoc:
end
end
+ def read_params_from_query
+ if defined? MOD_RUBY
+ Apache::request.args || ''
+ else
+ # fixes CGI querystring parsing for POSTs
+ if env_table['QUERY_STRING'].blank? && !env_table['REQUEST_URI'].blank?
+ env_table['QUERY_STRING'] = env_table['REQUEST_URI'].split('?', 2)[1] || ''
+ end
+ env_table['QUERY_STRING']
+ end
+ end
+
+ def read_params_from_post
+ stdinput.binmode if stdinput.respond_to?(:binmode)
+ content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) || ''
+ env_table['RAW_POST_DATA'] = content.split("&_").first.to_s.freeze # &_ is a fix for Safari Ajax postings that always append \000
+ end
+
def read_query_params
case env_table['REQUEST_METHOD'].to_s.upcase
when 'CMD'
read_from_cmdline
when 'POST', 'PUT'
- stdinput.binmode if stdinput.respond_to?(:binmode)
- content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) || ''
- env_table['RAW_POST_DATA'] = content.split("&_").first.to_s.freeze # &_ is a fix for Safari Ajax postings that always append \000
+ read_params_from_post
else # when 'GET', 'HEAD', 'DELETE', 'OPTIONS'
- (defined?(MOD_RUBY) ? Apache::request.args : env_table['QUERY_STRING']) || ''
+ read_params_from_query
end
end
end # module QueryExtension
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index 6495ebf655..a0a4076103 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -124,7 +124,7 @@ module ActionView
code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
content_tag("script", code, options[:html_options] || {})
end
-
+
# Returns a form tag that will submit using XMLHttpRequest in the background instead of the regular
# reloading POST arrangement. Even though it's using Javascript to serialize the form elements, the form submission
# will work just like a regular submission as viewed by the receiving side (all elements available in @params).
@@ -373,6 +373,7 @@ module ActionView
js_options['asynchronous'] = options[:type] != :synchronous
js_options['method'] = method_option_to_s(options[:method]) if options[:method]
js_options['insertion'] = "Insertion.#{options[:position].to_s.camelize}" if options[:position]
+ js_options['script'] = options[:script] == true if options[:script]
if options[:form]
js_options['parameters'] = 'Form.serialize(this)'
@@ -382,7 +383,7 @@ module ActionView
options_for_javascript(js_options)
end
-
+
def method_option_to_s(method)
(method.is_a?(String) and !method.index("'").nil?) ? method : "'#{method}'"
end
diff --git a/actionpack/lib/action_view/helpers/javascripts/prototype.js b/actionpack/lib/action_view/helpers/javascripts/prototype.js
index 02d103498e..0d23a344d9 100644
--- a/actionpack/lib/action_view/helpers/javascripts/prototype.js
+++ b/actionpack/lib/action_view/helpers/javascripts/prototype.js
@@ -254,6 +254,7 @@ Ajax.Updater.prototype = (new Ajax.Base()).extend({
failure: container.failure ? $(container.failure) : null
}
+ this.script_re = /<script.*?>((?:\n|.)*?)<\/script>/im;
this.setOptions(options);
if (this.options.asynchronous) {
@@ -271,23 +272,79 @@ Ajax.Updater.prototype = (new Ajax.Base()).extend({
var receiver =
(this.request.transport.status == 200) ?
this.containers.success : this.containers.failure;
+
+ var response = this.request.transport.responseText.replace(
+ this.script_re, '');
+
+ var scripts = this.request.transport.responseText.match(
+ this.script_re);
if (receiver) {
if (this.options.insertion) {
- new this.options.insertion(receiver,
- this.request.transport.responseText);
+ new this.options.insertion(receiver, response);
} else {
- receiver.innerHTML = this.request.transport.responseText;
+ receiver.innerHTML = response;
}
}
-
- if (this.request.transport.status == 200 && this.onComplete) {
- setTimeout((function() {this.onComplete(
- this.request.transport)}).bind(this), 10);
+
+ if (this.request.transport.status == 200) {
+ if (this.onComplete) {
+ setTimeout((function() {this.onComplete(
+ this.request.transport)}).bind(this), 10);
+ }
+ if (this.options.script && scripts) {
+ setTimeout((function() { eval(scripts[1]) }).bind(this), 10);
+ }
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({
+ initialize: function(container, url, options) {
+ this.setOptions(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = 1;
+
+ this.updater = {};
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Ajax.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
}
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
+
});
+/*--------------------------------------------------------------------------*/
+
document.getElementsByClassName = function(className) {
var children = document.getElementsByTagName('*') || document.all;
var elements = new Array();
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/style.css b/railties/lib/rails_generator/generators/components/scaffold/templates/style.css
index d17eda753b..7910083322 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/style.css
+++ b/railties/lib/rails_generator/generators/components/scaffold/templates/style.css
@@ -51,3 +51,24 @@ a:hover { color: #fff; background-color:#000; }
font-size: 12px;
list-style: square;
}
+
+div.uploadStatus {
+ margin: 5px;
+}
+
+div.progressBar {
+ margin: 5px;
+}
+
+div.progressBar div.border {
+ background-color: #fff;
+ border: 1px solid grey;
+ width: 100%;
+}
+
+div.progressBar div.background {
+ background-color: #333;
+ height: 18px;
+ width: 0%;
+}
+