%#
%# COPYRIGHT:
%#
-%# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
%# <sales@bestpractical.com>
%#
%# (Except where explicitly superseded by other copyright notices)
<%ONCE>
use Regexp::Common qw(URI);
+my $escaper = sub {
+ my $content = shift;
+ RT::Interface::Web::EscapeHTML( \$content );
+ return $content;
+};
+
my %actions = (
default => sub {
my %args = @_;
- return $args{value};
+ return $escaper->($args{value});
},
url => sub {
my %args = @_;
- my $result = qq{[<a target="new" href="$args{value}">}. loc('Open URL') .qq{</a>]};
- return $args{value} . qq{ <span class="clickylink">$result</span>};
+ my $post = "";
+ $post = ")" if $args{value} !~ /\(/ and $args{value} =~ s/\)$//;
+ $args{value} = $escaper->($args{value}) unless $args{html};
+ my $result = qq{[<a target="_blank" href="$args{value}">}. loc('Open URL') .qq{</a>]};
+ return $args{value} . qq{ <span class="clickylink">$result</span>$post};
},
url_overwrite => sub {
my %args = @_;
- my $result = qq{<a target="new" href="$args{'value'}">};
- $result .= qq{$args{'value'}</a>};
- return qq{<span class="clickylink">$result</span>};
+ my $post = "";
+ $post = ")" if $args{value} !~ /\(/ and $args{value} =~ s/\)$//;
+ $args{value} = $escaper->($args{value}) unless $args{html};
+ my $result = qq{<a target="_blank" href="$args{value}">$args{value}</a>};
+ return qq{<span class="clickylink">$result</span>$post};
},
);
my @types = (
{
name => "httpurl",
- regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#\S+)?/,
+ regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#[^\s<]+)?(?<![.?!,;:])/,
action => "url",
},
{
name => "httpurl_overwrite",
- regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#\S+)?/,
+ regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#[^\s<]+)?(?<![.?!,;:])/,
action => "url_overwrite",
},
);
}
};
-my $escaper = sub {
- my $content = shift;
- RT::Interface::Web::EscapeUTF8( \$content );
- return $content;
-};
+my $cache; # only defined via callback
# Hook to add more Clicky types
# XXX Have to have Page argument, as Mason gets caller wrong in Callback?
types => \@types,
actions => \%actions,
handle => \$handle,
+ cache => \$cache,
);
</%ARGS>
<%INIT>
return unless defined $$content;
+if ( defined $cache ) {
+ my $cached_content = $cache->(fetch => $content);
+ if ( $cached_content ) {
+ RT->Logger->debug("Found MakeClicky cache");
+ $$content = $cached_content;
+ return;
+ }
+}
+
unless ( $regexp ) {
- RT::Interface::Web::EscapeUTF8( $content ) unless $html;
+ RT::Interface::Web::EscapeHTML( $content ) unless $html;
return;
}
my $pos = 0;
while ( $$content =~ /($regexp)/gsio ) {
my $match = $1;
- next if $` =~ /href=(?:"|")$/;
+ next if $` =~ /\w+=(?:"|")$/;
my $skipped_len = pos($$content) - $pos - length($match);
if ( $skipped_len > 0 ) {
my $plain;
$pos += length($plain);
}
my $plain = $handle->(
- %ARGS,
+ %ARGS,
value => $match,
all_matches => [ $1, $2, $3, $4, $5, $6, $7, $8, $9 ],
);
($pos == length $$content) || $html;
pos($$content) = 0;
+$cache->(store => $content) if defined $cache;
</%INIT>
-<%doc>
-
-MakeClicky detects various formats of data in headers and email
-messages, and extends them with supporting links. By default, RT
-provides two formats:
-
- * 'httpurl': detects http:// and https:// URLs and adds '[Open URL]'
- link after the URL.
-
- * 'httpurl_overwrite': also detects URLs as 'httpurl' format, but
- replace URL with link.
-
-To extend this with your own types of data, use the callback.
-It will be provided with:
-
- * 'types': An array reference of hash references. Modify this array
- reference to add your own types; the first matching type will be
- used. Each hashref should contain:
- - 'name': The name of the data format; this is used in the
- configuration file to enable the format.
- - 'regex': A regular expression to match against
- - 'action': The name of the action to run (see "actions", below)
-
- * 'actions': A hash reference of 'actions'. Modify this hash
- reference to change or add action types. Values are subroutine
- references which will get called when needed. They should return
- the modified string. Note that subroutine must escape HTML.
-
- * 'handler': A reference to a subroutine reference; modify it if you
- have to. This can be used to add pre- or post-processing around
- all actions.
-
-Read more about writing new actions in docs/extending/clickable_links.pod
-
-</%doc>