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.'>'; + $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

!, + output => [ '

section_1

', '


section_2

' ], + comment => 'paragraph text, 2 sections, macro inside tags, with br self-close', + }, + { + inputText => q!

section_1^-;
section_2

!, + output => [ '

section_1

', '


section_2

' ], + comment => 'paragraph text, 2 sections, macro inside tags, with br unclosed', + }, + { + inputText => q!

section_1
trailer_1^-;section_2

!, + output => [ '

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; + } +} +