1 %# BEGIN BPS TAGGED BLOCK {{{
5 %# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
6 %# <sales@bestpractical.com>
8 %# (Except where explicitly superseded by other copyright notices)
13 %# This work is made available to you under the terms of Version 2 of
14 %# the GNU General Public License. A copy of that license should have
15 %# been provided with this software, but in any event can be snarfed
18 %# This work is distributed in the hope that it will be useful, but
19 %# WITHOUT ANY WARRANTY; without even the implied warranty of
20 %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 %# General Public License for more details.
23 %# You should have received a copy of the GNU General Public License
24 %# along with this program; if not, write to the Free Software
25 %# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 %# 02110-1301 or visit their web page on the internet at
27 %# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
30 %# CONTRIBUTION SUBMISSION POLICY:
32 %# (The following paragraph is not intended to limit the rights granted
33 %# to you to modify and distribute this software under the terms of
34 %# the GNU General Public License and is only of importance to you if
35 %# you choose to contribute your changes and enhancements to the
36 %# community by submitting them to Best Practical Solutions, LLC.)
38 %# By intentionally submitting any modifications, corrections or
39 %# derivatives to this work, or any other work intended for use with
40 %# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 %# you are the copyright holder for those contributions and you grant
42 %# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43 %# royalty-free, perpetual, license to use, copy, create derivative
44 %# works based on those contributions, and sublicense and distribute
45 %# those contributions and any derivatives thereof.
47 %# END BPS TAGGED BLOCK }}}
49 use Regexp::Common qw(URI);
53 RT::Interface::Web::EscapeHTML( \$content );
60 return $escaper->($args{value});
65 $post = ")" if $args{value} !~ /\(/ and $args{value} =~ s/\)$//;
66 $args{value} = $escaper->($args{value});
67 my $result = qq{[<a target="_blank" href="$args{value}">}. loc('Open URL') .qq{</a>]};
68 return $args{value} . qq{ <span class="clickylink">$result</span>$post};
70 url_overwrite => sub {
73 $post = ")" if $args{value} !~ /\(/ and $args{value} =~ s/\)$//;
74 $args{value} = $escaper->($args{value});
75 my $result = qq{<a target="_blank" href="$args{value}">$args{value}</a>};
76 return qq{<span class="clickylink">$result</span>$post};
83 regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#[^\s<]+)?(?<![.?!,;:])/,
87 name => "httpurl_overwrite",
88 regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#[^\s<]+)?(?<![.?!,;:])/,
89 action => "url_overwrite",
95 for my $rec( @types ) {
96 return $rec->{action}->(
98 all_matches => [ $args{value}, $1, $2, $3, $4, $5, $6, $7, $8, $9 ],
99 ) if $args{value} =~ $rec->{regex};
103 my $cache; # only defined via callback
105 # Hook to add more Clicky types
106 # XXX Have to have Page argument, as Mason gets caller wrong in Callback?
107 # This happens as we are in <%ONCE> block
109 CallbackPage => "/Elements/MakeClicky",
111 actions => \%actions,
119 $active{$_}++ for RT->Config->Get('Active_MakeClicky');
120 @types = grep $active{$_->{name}}, @types;
122 # Build up the whole match
123 my $regexp = join "|", map $_->{regex}, @types;
125 # Make sure we have a default
126 $actions{default} ||= sub {};
128 # Anchor the regexes and look up the actions
129 foreach my $type ( @types ) {
130 $type->{regex} = qr/^$type->{regex}$/;
131 $type->{action} = $actions{$type->{action}} || $actions{default};
140 return unless defined $$content;
141 if ( defined $cache ) {
142 my $cached_content = $cache->(fetch => $content);
143 if ( $cached_content ) {
144 RT->Logger->debug("Found MakeClicky cache");
145 $$content = $cached_content;
151 RT::Interface::Web::EscapeHTML( $content ) unless $html;
156 while ( $$content =~ /($regexp)/gsio ) {
158 next if $` =~ /\w+=(?:"|")$/;
159 my $skipped_len = pos($$content) - $pos - length($match);
160 if ( $skipped_len > 0 ) {
163 $plain = substr( $$content, $pos, $skipped_len );
166 $plain = $escaper->( substr( $$content, $pos, $skipped_len ) )
168 substr( $$content, $pos, $skipped_len ) = $plain;
169 $pos += length($plain);
171 my $plain = $handle->(
174 all_matches => [ $1, $2, $3, $4, $5, $6, $7, $8, $9 ],
176 substr( $$content, $pos, length($match) ) = $plain;
177 pos($$content) = ( $pos += length($plain) );
180 substr( $$content, $pos ) = $escaper->( substr( $$content, $pos ) ) unless
181 ($pos == length $$content) || $html;
184 $cache->(store => $content) if defined $cache;