2005-03-11 21:42:48 -05:00
|
|
|
require File.dirname(__FILE__) + '/tag_helper'
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
module ActionView
|
|
|
|
module Helpers
|
|
|
|
# You must call <%= define_javascript_functions %> in your application before using these helpers.
|
|
|
|
module JavascriptHelper
|
2005-03-12 12:00:03 -05:00
|
|
|
# Returns a link that'll trigger a javascript +function+ using the onclick handler and return false after the fact.
|
|
|
|
#
|
|
|
|
# Examples:
|
|
|
|
# link_to_function "Greeting", "alert('Hello world!')"
|
|
|
|
# link_to_function(image_tag("delete"), "if confirm('Really?'){ do_delete(); }")
|
2005-03-11 21:59:12 -05:00
|
|
|
def link_to_function(name, function, html_options = {})
|
|
|
|
content_tag(
|
|
|
|
"a", name,
|
|
|
|
html_options.symbolize_keys.merge(:href => "#", :onclick => "#{function}; return false;")
|
|
|
|
)
|
|
|
|
end
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-12 12:00:03 -05:00
|
|
|
# Returns a link to a remote action defined by <tt>options[:url]</tt> (using the url_for format) that's called in the background
|
|
|
|
# using XMLHttpRequest. The result of that request can then be inserted into a DOM object who's id can be specified
|
|
|
|
# with <tt>options[:update]</tt>. Usually, the result would be a partial prepared by the controller with either render_partial
|
|
|
|
# or render_partial_collection.
|
|
|
|
#
|
|
|
|
# Examples:
|
|
|
|
# link_to_remote "Delete this post", :update => "posts", :url => { :action => "destroy", :id => post.id }
|
|
|
|
# link_to_remote(image_tag("refresh"), :update => "emails", :url => { :action => "list_emails" })
|
2005-03-14 07:47:38 -05:00
|
|
|
#
|
|
|
|
# Asynchronous requests may be made by specifying a callback function
|
|
|
|
# to invoke when the request finishes.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# link_to_remote word,
|
|
|
|
# :url => { :action => "undo", :n => word_counter },
|
|
|
|
# :before => "if(!prepareForUndo()) return false",
|
|
|
|
# :complete => "undoRequestCompleted(request)"
|
|
|
|
#
|
|
|
|
# The complete list of callbacks that may be specified are:
|
|
|
|
#
|
|
|
|
# * uninitialized
|
|
|
|
# * loading
|
|
|
|
# * loaded
|
|
|
|
# * interactive
|
|
|
|
# * complete
|
2005-03-13 13:06:58 -05:00
|
|
|
def link_to_remote(name, options = {}, html_options = {})
|
|
|
|
link_to_function(name, remote_function(options), html_options)
|
2005-03-11 21:59:12 -05:00
|
|
|
end
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
def form_remote_tag(options = {})
|
|
|
|
options[:form] = true
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
options[:html] ||= { }
|
|
|
|
options[:html][:onsubmit] = "#{remote_function(options)}; return false;"
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
tag("form", options[:html], true)
|
|
|
|
end
|
|
|
|
|
|
|
|
def define_javascript_functions
|
|
|
|
<<-EOF
|
|
|
|
<script language="JavaScript">
|
2005-03-13 11:35:15 -05:00
|
|
|
/* Convenience form methods */
|
|
|
|
Field = {
|
|
|
|
clear: function() {
|
|
|
|
for(i = 0; i < arguments.length; i++) { o(arguments[i]).value = ''; }
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
focus: function(id) {
|
|
|
|
o(id).focus();
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
present: function() {
|
2005-03-13 13:06:58 -05:00
|
|
|
for(i = 0; i < arguments.length; i++) { if (o(arguments[i]).value == '') { return false; } }
|
2005-03-13 11:35:15 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
/* XMLHttpRequest Methods */
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
function update_with_response() {
|
2005-03-13 10:47:06 -05:00
|
|
|
var container = o(arguments[0]);
|
|
|
|
var url = arguments[1];
|
|
|
|
var parameters = arguments[2];
|
2005-03-14 07:47:38 -05:00
|
|
|
var async = arguments[3];
|
|
|
|
|
|
|
|
if (async) {
|
|
|
|
xml_request(url, parameters, true,
|
|
|
|
{ complete: function(request) {
|
|
|
|
container.innerHTML = request.responseText }
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
container.innerHTML = xml_request(url, parameters);
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
}
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
function xml_request() {
|
|
|
|
var url = arguments[0];
|
|
|
|
var parameters = arguments[1];
|
|
|
|
var async = arguments[2];
|
2005-03-14 07:47:38 -05:00
|
|
|
var callbacks = arguments[3];
|
2005-03-11 21:59:12 -05:00
|
|
|
var type = parameters ? "POST" : "GET";
|
2005-03-13 10:47:06 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
req = xml_http_request_object();
|
|
|
|
req.open(type, url, async);
|
2005-03-14 07:47:38 -05:00
|
|
|
|
|
|
|
if (async) {
|
|
|
|
invoke_callback = function(which) {
|
|
|
|
if(callbacks && callbacks[which]) callbacks[which](req)
|
|
|
|
}
|
|
|
|
|
|
|
|
req.onreadystatechange = function() {
|
|
|
|
switch(req.readyState) {
|
|
|
|
case 0: invoke_callback('uninitialized'); break
|
|
|
|
case 1: invoke_callback('loading'); break
|
|
|
|
case 2: invoke_callback('loaded'); break
|
|
|
|
case 3: invoke_callback('interactive'); break
|
|
|
|
case 4: invoke_callback('complete'); break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-13 13:06:58 -05:00
|
|
|
req.send(parameters ? parameters + "&_=" : parameters);
|
2005-03-13 10:47:06 -05:00
|
|
|
|
2005-03-14 07:47:38 -05:00
|
|
|
if(!async) return req.responseText;
|
2005-03-11 21:59:12 -05:00
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
function xml_http_request_object() {
|
|
|
|
var req = false;
|
|
|
|
try {
|
|
|
|
req = new ActiveXObject("Msxml2.XMLHTTP");
|
|
|
|
} catch (e) {
|
|
|
|
try {
|
|
|
|
req = new ActiveXObject("Microsoft.XMLHTTP");
|
|
|
|
} catch (E) {
|
|
|
|
req = false;
|
|
|
|
}
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
if (!req && typeof XMLHttpRequest!='undefined') {
|
|
|
|
req = new XMLHttpRequest();
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
return req;
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
/* Common methods ------------------------------ */
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
function toggle_display_by_id(id) {
|
|
|
|
o(id).style.display = (o(id).style.display == "none") ? "" : "none";
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-13 11:35:15 -05:00
|
|
|
function toggle_display() {
|
|
|
|
for(i = 0; i < arguments.length; i++) {
|
|
|
|
o(arguments[i]).style.display = (o(arguments[i]).style.display == "none") ? "" : "none";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
function o(id) {
|
|
|
|
return document.getElementById(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Serialize a form by Sam Stephenson ------------------------------ */
|
|
|
|
|
|
|
|
Form = {
|
|
|
|
Serializers: {
|
|
|
|
input: function(element) {
|
|
|
|
switch (element.type.toLowerCase()) {
|
|
|
|
case 'hidden':
|
|
|
|
case 'text':
|
|
|
|
return Form.Serializers.textarea(element);
|
|
|
|
case 'checkbox':
|
|
|
|
case 'radio':
|
|
|
|
return Form.Serializers.inputSelector(element);
|
|
|
|
}
|
|
|
|
},
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
inputSelector: function(element) {
|
|
|
|
if (element.checked)
|
|
|
|
return [element.name, element.value];
|
|
|
|
},
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
textarea: function(element) {
|
|
|
|
return [element.name, element.value];
|
|
|
|
},
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
select: function(element) {
|
|
|
|
var index = element.selectedIndex;
|
|
|
|
return [element.name, element.options[index].value];
|
|
|
|
}
|
|
|
|
},
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
serialize: function(form) {
|
|
|
|
var elements = Form.getFormElements(form);
|
|
|
|
var queryComponents = new Array();
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
for (var i = 0; i < elements.length; i++) {
|
|
|
|
var element = elements[i];
|
|
|
|
var method = element.tagName.toLowerCase();
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
var parameter = Form.Serializers[method](element);
|
|
|
|
if (parameter) {
|
|
|
|
var queryComponent = encodeURIComponent(parameter[0]) + '=' +
|
|
|
|
encodeURIComponent(parameter[1]);
|
|
|
|
queryComponents.push(queryComponent);
|
|
|
|
}
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
return queryComponents.join('&');
|
|
|
|
},
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
getFormElements: function(form) {
|
|
|
|
var elements = new Array();
|
|
|
|
for (tagName in Form.Serializers) {
|
|
|
|
var tagElements = form.getElementsByTagName(tagName);
|
|
|
|
for (var j = 0; j < tagElements.length; j++)
|
|
|
|
elements.push(tagElements[j]);
|
|
|
|
}
|
|
|
|
return elements;
|
|
|
|
}
|
2005-03-11 21:42:48 -05:00
|
|
|
}
|
2005-03-11 21:59:12 -05:00
|
|
|
</script>
|
|
|
|
EOF
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2005-03-14 07:47:38 -05:00
|
|
|
def build_callbacks(options)
|
|
|
|
callbacks = nil
|
|
|
|
%w{uninitialized loading loaded interactive complete}.each do |cb|
|
|
|
|
cb = cb.to_sym
|
|
|
|
if options[cb]
|
|
|
|
callbacks ? callbacks << "," : callbacks = "{"
|
|
|
|
callbacks <<
|
|
|
|
"#{cb}:function(request){#{options[cb].gsub(/"/){'\"'}}}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
callbacks << "}" if callbacks
|
|
|
|
callbacks
|
|
|
|
end
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
def remote_function(options)
|
2005-03-14 07:47:38 -05:00
|
|
|
callbacks = build_callbacks(options)
|
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
function = options[:update] ?
|
2005-03-14 07:47:38 -05:00
|
|
|
"update_with_response('#{options[:update]}', " :
|
|
|
|
"xml_request("
|
|
|
|
|
|
|
|
function << "'#{url_for(options[:url])}'"
|
|
|
|
function << ', Form.serialize(this)' if options[:form]
|
|
|
|
function << ', nil' if !options[:form] && callbacks
|
|
|
|
function << ", true, " << callbacks if callbacks
|
|
|
|
function << ')'
|
2005-03-11 21:59:12 -05:00
|
|
|
|
2005-03-13 11:35:15 -05:00
|
|
|
function = "#{options[:before]}; #{function}" if options[:before]
|
|
|
|
function = "#{function}; #{options[:after]}" if options[:after]
|
2005-03-13 10:47:06 -05:00
|
|
|
function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
|
2005-03-11 21:42:48 -05:00
|
|
|
|
2005-03-11 21:59:12 -05:00
|
|
|
return function
|
|
|
|
end
|
2005-03-11 21:42:48 -05:00
|
|
|
end
|
2005-03-11 21:59:12 -05:00
|
|
|
end
|
2005-03-14 07:47:38 -05:00
|
|
|
end
|