Added support for upload progress indicators in Apache and lighttpd 1.4.x...

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]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1552 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 96e590ca
*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(
......
......@@ -48,6 +48,7 @@
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 @@
include ActionController::Caching
include ActionController::Components
include ActionController::Verification
include ActionController::UploadProgress
include ActionController::Streaming
include ActionController::AutoComplete
end
......@@ -508,12 +508,24 @@ def render_to_string(options = {}) #:doc:
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)
......
......@@ -6,6 +6,8 @@ module QueryExtension
# 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 @@ def initialize_query()
@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 @@ def multipart_form_boundary
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
......
......@@ -124,7 +124,7 @@ def periodically_call_remote(options = {})
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 @@ def options_for_ajax(options)
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 @@ def options_for_ajax(options)
options_for_javascript(js_options)
end
def method_option_to_s(method)
(method.is_a?(String) and !method.index("'").nil?) ? method : "'#{method}'"
end
......
......@@ -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();
......
......@@ -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%;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册