diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 1230fb3a2..254198e2c 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -2,6 +2,7 @@ - fixed #10654: Story Archive: Search not working properly - fixed search indexer concatenates keywords to content. - fixed Index Story fields for Search (headline, subtitle, location, byline, highlights, story) + - fixed #10619: Pagination macro 7.7.16 - fixed #10590: Session::DateTime->secondsToInterval doesn't allow 7 weeks diff --git a/lib/WebGUI/Asset/Post.pm b/lib/WebGUI/Asset/Post.pm index 081ffd21a..b1a2beb02 100644 --- a/lib/WebGUI/Asset/Post.pm +++ b/lib/WebGUI/Asset/Post.pm @@ -652,7 +652,9 @@ sub getSynopsisAndContent { unless ($synopsis) { my @content; if( $body =~ /\^\-\;/ ) { - @content = split(/\^\-\;/, $body ,2); + my @pieces = WebGUI::HTML::splitSeparator($body); + $content[0] = shift @pieces; + $content[1] = join '', @pieces; } elsif( $body =~ /
/ ) { @content = WebGUI::HTML::splitTag($body); diff --git a/lib/WebGUI/Asset/Wobject/Article.pm b/lib/WebGUI/Asset/Wobject/Article.pm index 938320c07..285d4c32d 100644 --- a/lib/WebGUI/Asset/Wobject/Article.pm +++ b/lib/WebGUI/Asset/Wobject/Article.pm @@ -17,6 +17,7 @@ use WebGUI::Cache; use WebGUI::Paginator; use WebGUI::Asset::Wobject; use WebGUI::Storage; +use WebGUI::HTML; our @ISA = qw(WebGUI::Asset::Wobject); @@ -405,7 +406,7 @@ sub view { $var{description} =~ s/\^\-\;//g; $p->setDataByArrayRef([$var{description}]); } else { - my @pages = split(/\^\-\;/,$var{description}); + my @pages = WebGUI::HTML::splitSeparator($var{description}); $p->setDataByArrayRef(\@pages); $var{description} = $p->getPage; } diff --git a/lib/WebGUI/HTML.pm b/lib/WebGUI/HTML.pm index 779b64c6d..7010771da 100644 --- a/lib/WebGUI/HTML.pm +++ b/lib/WebGUI/HTML.pm @@ -401,7 +401,59 @@ sub processReplacements { #------------------------------------------------------------------- -=head2 WebGUI::HTML::splitTag([$tag,]$html[,$count]); +=head2 splitSeparator ( $content ) + +Splits the supplied content on the separator macro, ^-;. Returns an array +of content. If the content contains HTML, and splitting the content would +result in sections of content missing start or end HTML tags, these are filled +in. Unary tags, like br, img, and hr are ignored, whether they are proper XHTML +or not. + +In the special case of the separator macro inside bare paragraph tags, + +
^-;
, + +no empty paragraph tags are generated. + +=head3 content + +The content to split. + +=cut + +sub splitSeparator { + my $content = shift; + return $content unless $content =~ /\^-;/; + $content =~ s{\s*\^-;\s*
}{\^-;}g; + my @tagStack = (); + my $parser = HTML::Parser->new( + api_version => 3, + ignore_elements => [ qw/br img hr/ ], + start_h => [ sub { push @tagStack, $_[0]; }, 'tag'], + end_h => [ sub { pop @tagStack; }, 'tag'], + ); + my @sections = (); + CHUNK: while (my ($leader, $trailer) = split /\^-;/, $content, 2) { + if (! defined $trailer) { + push @sections, $leader; + last CHUNK; + } + $parser->parse($leader); + while( my $tag = pop @tagStack) { + my $endTag = ''.$tag.'>'; + $tag = '<'.$tag.'>'; + $leader .= $endTag; + $trailer = $tag . $trailer; + } + push @sections, $leader; + $content = $trailer; + } + return @sections; +} + +#------------------------------------------------------------------- + +=head2 splitTag([$tag,]$html[,$count]); splits an block of HTML into an array based on the contents of a single tag diff --git a/t/HTML/splitSeparator.t b/t/HTML/splitSeparator.t new file mode 100644 index 000000000..3fa7c02db --- /dev/null +++ b/t/HTML/splitSeparator.t @@ -0,0 +1,113 @@ +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2009 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------- +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------- + +use FindBin; +use strict; +use lib "$FindBin::Bin/../lib"; + +use WebGUI::Test; +use WebGUI::HTML; +use WebGUI::Session; + +use Test::More; +use Test::Deep; +use Data::Dumper; + +my $session = WebGUI::Test->session; + +my @testArray = ( + { + inputText => q!section_1!, + output => [ qw/section_1/ ], + comment => 'bare text, no macro', + }, + { + inputText => q!section_1^-;section_2!, + output => [ qw/section_1 section_2/ ], + comment => 'bare text, 2 sections', + }, + { + inputText => q!section_1
^-;
section_2
!, + output => [ qw{section_1
section_2
} ], + comment => 'paragraph text, 2 sections, macro in separate paragraph', + }, + { + inputText => q!section_1
^-;
section_2
!, + output => [ qw{section_1
section_2
} ], + comment => 'paragraph text, 2 sections, macro in separate paragraph with whitespace', + }, + { + inputText => q!section_1
^-;
section_2
^-;
section_3
!, + output => [ qw{section_1
section_2
section_3
} ], + comment => 'paragraph text, 3 sections, macros in separate paragraphs with whitespace', + }, + { + inputText => q!section_1^-;section_2
!, + output => [ qw{section_1
section_2
} ], + comment => 'paragraph text, 2 sections, macro inside tags', + }, + { + inputText => q!section_1^-;section_2trailer
!, + output => [ qw{section_1
section_2trailer
} ], + comment => 'paragraph text, 2 sections, macro inside 2 nested tags', + }, + { + inputText => q!section_1^-;
section_2
section_1
', '
section_2
section_1^-;
section_2
section_1
', '
section_2
section_1
trailer_1^-;section_2
section_1
trailer_1
section_2
' ], + comment => 'paragraph text, 2 sections, macro inside tags, with br unclosed in first section', + }, + { + inputText => q!Very^-;long^-;paragraph
!, + output => [ 'Very
', 'long
', 'paragraph
' ], + comment => 'paragraph text, 3 sections, macros inside tags', + }, + { + inputText => q!Very^-;long^-;paragraph
!, + output => [ 'Very
', 'long
', 'paragraph
' ], + comment => 'paragraph text, 3 sections, macros inside tags, nesting first two tags', + }, + { + inputText => q!Very^-;long^-;paragraph
!, + output => [ 'Very
', 'long
', 'paragraph
' ], + comment => 'paragraph text, 3 sections, macros inside tags, nesting all 3 sections', + }, + { + inputText => q!Very^-;long^-;paragraph
!, + output => [ 'Very
', 'long
', 'paragraph
' ], + comment => 'paragraph text, 3 sections, macros inside tags, bridge right after macro', + }, +); + +my $numTests = scalar @testArray; + +plan tests => $numTests; + +foreach my $testSet (@testArray) { + my @output = WebGUI::HTML::splitSeparator($testSet->{inputText}); + my $ok = cmp_deeply( + \@output, + $testSet->{output}, + $testSet->{comment} + ); + if (!$ok) { + diag Dumper \@output; + } +} +