On Fri, 25 Aug 2006, Bull, John wrote:
> I'm getting closer. I removed the multiple component roots, but am
> still getting the following error message
>
> "The requested URL /ajax/ajax.comp/ajax/index.html:my_ajax_test was not
> found on this server."
>
> The prototype library is calling back to this url which isn't valid.
> What else am I doing wrong?
I think it is just assumptions about the setup on my part again.
My normal setup is inside apache <Location> directives, which sends
everything with that prefix to mod_perl/Mason without validating files (or
adding /index.html to directory requests, as noticed in another recent
thread).
If you are using <Files> or <FilesMatch> in your httpd.conf, then apache
will notice that the above URL is invalid and reject it before sending it
to mod_perl/Mason.
Since one cannot call methods directly, and I wanted to be able to use
method for my ajax calls, ajax.comp is attempting to call itself with the
real destination appended to the URL, which it can find in
$ENV{PATH_INFO}. But that's probably a bit sloppy, since mod_perl2
doesn't necessary setup the %ENV stuff, and it does not necessary work
with a <Files> type configuration, as you notice.
So I have attached an improved version, which should work with multiple
comp_roots, and <Files> directives. Remember, the ajax component itself
needs to be accessible, so you might need to rename it to ajax.html if you
have <FilesMatch *.html> in your config. Let me know how this one works.
~ John Williams
<%doc>
This component simplifies using AJAX with Mason components.
It inserts the javascript to use the prototype.js library, and
allows you to call mason methods as well as components.
It relies on prototype.js, so you must include that script in any page
of any page which uses this (or an autohandler thereof).
(Most of the ideas herein are plagurized from Myghty and RubyOnRails.)
Brief Example:
<div id="me">Full</div>
<input type=button value="Drink Me!"
onClick="<& /ajax, comp=>'SELF:drink', update=>'me' &>">
<%method drink>empty</%method>
Parameters:
comp : (required) This is the component or method which will be called
by the ajax library.
update : DOM id to update. If given the output of the above comp will
be placed in the given element.
throbber : The URL of a throbber image to show while the request is
begin processed by the server. A value of 'auto' or '1' will
use '/images/throbber.gif' as the default.
(Does not currently work with the 'position' parameter.)
position : Where in the above element to put the content.
default is to replace the element content.
"before" will add the content before the element.
"top" will add the content at the top/beginning of the element.
"bottom" will add the content at the bottom/end of the element.
"after" will add the content after the element.
form : the name of a form to serialize and pass to the above comp.
parameters : query string or hash of values to pass to the above comp.
parameters starting with _ are passed verbatim, so you can put
executable javascript there
e.g. parameters=>{ a => 'string' } --> 'url?a=string'
parameters=>{ _a => '1+2' } --> 'url?a=' + escape( 1+2 )
BTW, do not pass anything in parameters named "comp". It confuses us.
Except for the 'comp' parameter, you can define attributes in the
component's <%attr> section instead of passing them explicitly to ajax.
This allows some better encapsulation and more automagic usage.
For example, if you know the component is always going to update a
certain div, you can define that in an attribute, so you do not have
to pass the update parameter. Explicit parameters will override attributes.
Inherited attributes are not considered for parameters.
Security:
This component has the potential to bypass any access controls you have
setup in your httpd.conf or anywhere else, and allow the user to access
any component or method on your site. If that is what you want, just
set the 'security' flag below to 0.
Otherwise you must explicitly enable each component for ajax access
by setting its 'ajax' attribute. This can of course also be done in
any component it inherits from to give access to a group of components.
Here is a more-or-less complete example. Please supply your own copy of
prototype.js and throbber.gif.
<script language=javascript src="prototype.js"></script>
<form name=xxx>
Test Text: <input type=text name=test><br>
<input type=button value="Click Me!"
onclick="<& /ajax, comp=>'SELF:my_ajax_test' &>">
</form>
<p>
<div id=target style="border: thin black solid;">
nothing yet
</div>
<%method my_ajax_test>
<%attr>
ajax => 1
update => 'target'
throbber => 1
form => 'xxx'
</%attr>
% sleep 2; # let the throbber throb
Hi there! It works. <br>
test param = <% $ARGS{test} %>
</%method>
TODO:
Make auto-throbber work with 'position'.
</%doc>
<%flags>
inherit=>undef
security=>1
</%flags>
<%args>
$comp => undef # what to call: name of mason comp/method, or component
object
$update => undef # dom id to update
$position => undef # where to put the content [before,top,bottom,after]
$form => undef # form to serialize into parameters
$parameters => '' # query string or hash of values to pass to $comp
</%args>
<%init>
if ( $ARGS{_comp} && !$comp ) {
my $ajax_comp = delete $ARGS{_comp};
# Security check
if (eval {$m->current_comp->flag('security')}) {
my $compref = $m->fetch_comp($ajax_comp);
if ($compref && !$compref->attr_if_exists('ajax')) {
$m->print('Security Violation! Component non
ajax-accessible.');
$m->abort;
}
}
return $m->comp($ajax_comp,%ARGS)
}
die("'comp' is a required parameter!") unless $comp;
# escape a string for safe usage inside javascript
my $escape_js = sub {
local $_ = shift;
return undef unless defined;
s/&/&/g;
s/\\/\\\\/g;
s/</</g;
s/>/>/g;
s/"/\\"/g;
s/'/\\'/g;
s/\r?\n/\\n/g;
return $_;
};
my $ref = ref $comp;
my $compref;
# need fully qualified name for comp/method
if ($ref =~ m'^HTML::Mason::') { # Mason component object
$compref = $comp;
$comp = $compref->path;
} else {
# this may not be considering the previous base_comp properly
$comp =~ s/^SELF(?=:)/$m->caller->path/e;
$comp =~ s/^PARENT(?=:)/$m->caller->parent->path/e;
$compref = $m->fetch_comp($comp);
$comp = $compref->path;
}
# we can pull arguments from the comp's %attr section.
# we do *not* want to look at inherited attributes
my $compattrs = $compref->attributes || {};
while( my($k,$v) = each(%$compattrs) ) {
next if $k eq 'ajax'; # reserved for security
next if $ARGS{$k}; # explicit args take precedence
$ARGS{$k} = $v;
# fixup args section
$update = $v if $k eq 'update';
$position = $v if $k eq 'position';
$form = $v if $k eq 'form';
$parameters = $v if $k eq 'parameters';
}
my $url = $m->current_comp->path;
my $args = '';
my $tp = $parameters;
$parameters = '_comp='.$m->interp->apply_escapes($comp,'u');
if (ref $tp eq 'HASH') {
for (keys %$tp) {
my $value = $tp->{$_};
my $safevalue = &$escape_js($value);
$parameters .= '&' if $parameters;
if (s/^_//) {
$parameters .= $m->interp->apply_escapes($_,'u')."=' +
escape( $value ) + '";
} else {
$parameters .=
$m->interp->apply_escapes($_,'u').'='.$m->interp->apply_escapes($value,'u')
}
}
}
if ($form) {
$parameters = '&'.$parameters if $parameters;
$parameters = qq{' + Form.serialize( $form ) + '}.$parameters;
}
if ($position) {
$args .= ' , ' if $args;
$args .= 'insertion: Insertion.'.ucfirst($position);
}
for (keys %ARGS) {
next unless defined $ARGS{$_};
my $value = $ARGS{$_};
my $safevalue = &$escape_js($value);
if (m/^(method|postBody|requestHeaders)$/) {
# string values
$args .= ' , ' if $args;
$args .= qq{ $_: '$value' };
} elsif
(m/^(asynchronous|evalScripts|onSuccess|onFailure|onException|onComplete|onLoading|onLoaded|onInteractive|on\d\d\d)$/)
{
# verbatim values
$args .= ' , ' if $args;
$args .= qq{ $_: $value };
}
}
$args .= ' , ' if $args;
if ($update) {
my $throbber = &$escape_js($ARGS{throbber});
if (!$position && $throbber) {
$throbber = '/images/throbber.gif' if $throbber eq '1' ||
$throbber eq 'auto';
$m->print(qq{ Element.update( '$update', '<img
src=\\'$throbber\\'>' ); });
}
$m->print(qq{ new Ajax.Updater('$update', '$url', { $args parameters:
'$parameters' } )});
} else {
$m->print(qq{ new Ajax.Request( '$url', { $args parameters:
'$parameters' } )});
}
return;
</%init>
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Mason-users mailing list
Mason-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mason-users