Permalink
Browse files

captcha refresh

Optional global config to pull in that creates the
[captcha-refresh] tag to ask for a new captcha image
if it can't be read.
  • Loading branch information...
1 parent 4acb1f0 commit 5a1ba34afdfb5623c83aacd1e4ed116421a4bd54 @msjohns1 msjohns1 committed Dec 10, 2012
Showing with 174 additions and 0 deletions.
  1. +3 −0 code/SystemTag/captcha.coretag
  2. +171 −0 eg/captcha_refresh.cfg
View
3 code/SystemTag/captcha.coretag
@@ -96,6 +96,9 @@ sub {
}
}
else {
+ # Used for [captcha-refresh] if requested
+ $::Instance->{last_captcha_build_opt} = { %$opt };
+
my $save_u = umask($::Variable->{CAPTCHA_UMASK} || 2);
if($opt->{reset}) {
View
171 eg/captcha_refresh.cfg
@@ -0,0 +1,171 @@
+# captcha refresh: Provide a refresh feature to use in conjunction with the
+# stock [captcha] tag by Mark Johnson <mark(at)endpoint(dot)com>
+#
+# To use:
+#
+# 1. Put this in, or include from, interchange.cfg and restart.
+#
+# 2. Place call to [captcha-refresh] where you would like to see the
+# refresh link appear. See documentation within usertag defintion below.
+#
+# 3. The captcha-refresh process couples tag and actionmap definitions.
+# Ensure there is no conflict with the actionmap name and any existing
+# custom maps for your implementation.
+
+UserTag captcha-refresh addAttr
+UserTag captcha-refresh Routine <<EOR
+use 5.10.0;
+sub {
+ my $opt = shift;
+ my %cache = %{
+ delete ($opt->{use_last}) && $::Instance->{last_captcha_build_opt} || {}
+ };
+
+ my $anc = delete ($opt->{anchor}) || 'refresh image';
+ my $img_id = delete $opt->{img_id};
+ my $js_func_name = delete ($opt->{js_func_name}) || 'captcha_refresh';
+
+ my @uri = (delete ($opt->{am}) || 'captcha-refresh');
+
+ my %unq_keys;
+ @unq_keys{ keys %cache, keys %$opt } = ();
+ push (@uri,
+ join (
+ '=',
+ ($_, $::Tag->filter(urlencode => ($opt->{$_} // $cache{$_} // '')))
+ )
+ )
+ for keys %unq_keys;
+
+ my $url = $::Tag->area({ href => join ('/', @uri) });
+
+ my $script = qq{
+ <a href="#captcha" onclick="$js_func_name()">$anc</a>
+ <script>
+ function $js_func_name() {
+ var ajax = new XMLHttpRequest();
+
+ ajax.onreadystatechange = function() {
+ if (ajax.readyState == 4 && ajax.status == 200) {
+ document.getElementById('$img_id').src = ajax.responseText;
+ }
+ }
+
+ ajax.open('GET','$url',true);
+ ajax.send();
+ return;
+ }
+ </script>
+ };
+
+ return $script;
+}
+EOR
+
+CodeDef captcha-refresh ActionMap
+CodeDef captcha-refresh Routine <<EOR
+sub {
+ my (undef, %opt) = split (m{[/=]+}, shift);
+ $_ = $::Tag->filter(urldecode => $_)
+ for values %opt;
+
+ # Always name_only since we're updating the img's src param
+ $opt{name_only} = 1;
+
+ my $doc = Vend::Document->new;
+ $doc->hot(1);
+ $doc->write($::Tag->captcha(\%opt));
+ return 0;
+}
+EOR
+
+UserTag captcha-refresh Documentation <<EOD
+=head1 NAME
+
+Captcha refresh
+
+=head1 DESCRIPTION
+
+Given a call to [captcha] to generate a check image, place a subsequent call
+to [captcha-refresh] where you would like to insert a hyperlink to refresh the
+image. The call will bundle the necessary parameters to duplicate the
+appropriate call to [captcha] into an AJAX GET back to the complementary
+captcha-refresh actionmap. The actionmap will build the new image and return
+the new URL to the image, to which the original <img> tag's src field will be
+set.
+
+As long as the [captcha-refresh] call is processed after the most recent call
+to [captcha] itself, the calling parameters for the latter call can be easily
+tied to the refresh request and not need to be duplicated. The calling order
+can always be enforced via the use of [output] or, if simpler, using scratch
+to store the [captcha] results and display later in the page.
+
+=over 4
+
+=item B<img_id> (required)
+
+The refresh code needs to be able to reference the original image so that the
+newly formed captcha image can overwrite the previous, discarded one. Thus,
+your captcha image must include an "id" attribute in the <img> tag, and that
+value must be included in this param.
+
+=item B<use_last>
+
+When true, the code will pull in the attribute list of the last non-check call
+to [captcha]. In order to refresh the image under the same terms as the
+original, the code needs access to the calling params used. These can either
+be duplicated in the call to [captcha-refresh] or referenced via B<use_last>
+
+=item B<anchor>
+
+Value to use for the link itself. Defaults to 'refresh image'. To use an
+image, supply the entire <img> tag.
+
+=item B<am>
+
+Alternate actionmap name to use to refresh the captcha image. Default is
+'captcha-refresh' and is included in the .cfg build file for this tag.
+
+=item B<js_func_name>
+
+Name of javascript function built from this tag to handle the refresh request
+and image update. Default is 'captcha_refresh'. Should only need to change if
+there is a conflict with an existing JS function.
+
+=back
+
+You can also provide any of the options defined for [captcha] itself, which
+will be necessary without use of the B<use_last> option. If B<use_last> and
+explicit [captcha] options are combined, options set in [captcha-refresh] will
+override those derived from the B<use_last> call.
+
+=head1 EXAMPLE
+
+ <form action="[area @@MV_PAGE@@]" method="post">
+ ...
+ <input name="mv_captcha_guess" size="6" autocomplete="off" />
+ <img
+ id="captcha_image"
+ style="vertical-align: middle"
+ src="[captcha
+ function=image
+ length=6
+ image_location=captcha
+ image_path=/images/captcha
+ name_only=1
+ ]"
+ />
+ &nbsp;
+ [captcha-refresh
+ img_id=captcha_image
+ use_last=1
+ ]
+ ...
+ <input type="submit" value="Submit" />
+
+=head1 AUTHOR
+
+Mark Johnson <mark(at)endpoint(dot)com>
+
+=cut
+EOD

0 comments on commit 5a1ba34

Please sign in to comment.