| MojoMojo documentation | Contained in the MojoMojo distribution. |
MojoMojo::Schema::Result::Content - Versioned page content
This table stores the actual page content; in other words, it's a table of
page versions (revisions). It has a composite primary key (page, version),
where page is the id of a page, and version is its version number. Each
version has a content body, a status ("released" or "removed"), and a
release_date. Revisions that have been replaced by a newer revision have a
remove_date and a comments set to "Replaced by version x.".
The type, abstract and precompiled columns are for future use.
created is essentially equal to release_date (there can be a 1-second
difference), and is used externally by other modules and in templates.
release_date and remove_date are used internally.
References MojoMojo::Schema::Result::Page.
References MojoMojo::Schema::Result::Person.
Returns an HTML string highlighting the changes between this version and the
previous version. The changes are in <span> or <div> tags with
the class fade.
Compare this content version to <old_content>, using Algorithm::Diff.
Sets a diffins CSS class for added lines, and a diffdel CSS class
for deleted lines. The <ins> and <del> HTML tags are also used.
Return the content after being run through MojoMojo::Formatter::*.
Show the merge conflict of the content for two different edit sessions of the same page.
Return the highest numbered revision.
Return the previous version of this content, or undef for the first version.
Return the publishing date of this version in a format suitable for RSS 2.0.
Extract and store all links and wanted paged from a given content version.
Encode content body using numeric entities.
Marcus Ramberg <mramberg@cpan.org>
This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself.
| MojoMojo documentation | Contained in the MojoMojo distribution. |
package MojoMojo::Schema::Result::Content; use strict; use warnings; use parent qw/MojoMojo::Schema::Base::Result/;
use DateTime::Format::Mail; use Algorithm::Diff; use Algorithm::Merge qw/merge/; use MojoMojo::WordDiff; use HTML::Entities qw/encode_entities_numeric/; __PACKAGE__->load_components(qw/DateTime::Epoch TimeStamp Core/); __PACKAGE__->table("content"); __PACKAGE__->add_columns( "page", { data_type => "INTEGER", is_nullable => 0, size => undef }, "version", { data_type => "INTEGER", is_nullable => 0, size => undef }, "creator", { data_type => "INTEGER", is_nullable => 0, size => undef }, "created", { data_type => "BIGINT", is_nullable => 0, size => 100, inflate_datetime => 'epoch', set_on_create => 1, }, "status", { data_type => "VARCHAR", is_nullable => 0, size => 20 }, "release_date", { data_type => "BIGINT", is_nullable => 0, size => 100, default_value => undef, inflate_datetime => 'epoch', datetime_undef_if_invalid => 1, }, "remove_date", { data_type => "BIGINT", is_nullable => 1, size => 100, default_value => undef, inflate_datetime => 'epoch', datetime_undef_if_invalid => 1, }, "type", { data_type => "VARCHAR", is_nullable => 1, size => 200 }, "abstract", { data_type => "TEXT", is_nullable => 1, size => 4000 }, "comments", { data_type => "TEXT", is_nullable => 1, size => 4000 }, "body", { data_type => "TEXT", is_nullable => 0, size => undef }, "precompiled", { data_type => "TEXT", is_nullable => 1, size => undef }, ); __PACKAGE__->set_primary_key( "version", "page" ); __PACKAGE__->has_many( "pages", "MojoMojo::Schema::Result::Page", { "foreign.content_version" => "self.version", "foreign.id" => "self.page", }, ); __PACKAGE__->has_many( "page_version_page_content_version_firsts", "MojoMojo::Schema::Result::PageVersion", { "foreign.content_version_first" => "self.version", "foreign.page" => "self.page", }, ); __PACKAGE__->has_many( "page_version_page_content_version_lasts", "MojoMojo::Schema::Result::PageVersion", { "foreign.content_version_last" => "self.version", "foreign.page" => "self.page", }, ); __PACKAGE__->belongs_to( "creator", "MojoMojo::Schema::Result::Person", { id => "creator" } ); __PACKAGE__->belongs_to( "page", "MojoMojo::Schema::Result::Page", { id => "page" } );
sub highlight { my ( $self, $c ) = @_; my $this_content = $self->formatted($c); my $previous_content = ( defined $self->previous ? $self->previous->formatted($c) : $this_content ); my $this = [ split /\n/, $this_content ]; my $prev = [ split /\n/, $previous_content ]; my @diff = Algorithm::Diff::sdiff( $prev, $this ); my $diff; my $hi = 0; my $pre_tag_open = 0; for my $line (@diff) { $pre_tag_open = 1 if $$line[2] =~ qr{<pre>} and $$line[2] !~ qr{</pre>}; my $tag = $pre_tag_open ? 'span' : 'div'; $hi++; if ( $$line[0] eq "+" ) { $diff .= qq(<$tag id="hi$hi" class="fade">) . $$line[2] . "</$tag>"; } elsif ( $$line[0] eq "c" ) { $diff .= qq(<$tag id="hi$hi" class="fade">) . $$line[2] . "</$tag>"; } elsif ( $$line[0] eq "-" ) { } else { $diff .= $$line[1] } $diff .= "\n"; $pre_tag_open = 0 if $$line[2] =~ qr{</pre>} and $$line[2] !~ qr{<pre>}; } return $diff; }
sub formatted_diff { my ( $self, $c, $to, $sparse ) = @_; my $this = [ $sparse ? split /\n/, ( $self->encoded_body ) : split /\n\n/, ( $self->formatted($c) ) ]; my $prev = [ $sparse ? split /\n/, ( $to->encoded_body ) : split /\n\n/, ( $to->formatted($c) ) ]; my @diff = Algorithm::Diff::sdiff( $prev, $this ); my $diff; for my $line (@diff) { if ( $$line[0] eq "+" ) { $diff .= qq(<div class="diffins">) . $$line[2] . "</div>"; } elsif ( $$line[0] eq "-" ) { $diff .= qq(<div class="diffdel">) . $$line[1] . "</div>"; } elsif ( $$line[0] eq "c" ) { $diff .= ( $sparse ? qq(<div class="diffdel">) . $$line[1] . "</div>" . qq(<div class="diffins">) . $$line[2] . "</div>" : word_diff( $$line[1], $$line[2] ) ); } elsif ( $$line[0] eq "u" ) { $diff .= ( $sparse ? '<div> ' . $$line[1] . '<div>' : $$line[1] ); } else { $diff .= "Unknown operator " . $$line[0] } } return $diff; }
sub formatted { my ( $self, $c ) = @_; my $result = $self->result_source->resultset->format_content( $c, $self->body, $self ); return $result; }
sub merge_content { my ( $self, $saved, $content, $h1, $h2, $h3 ) = @_; my $source = [ split /\n/, $self->encoded_body ]; my $a = [ split /\n/, $saved->encoded_body ]; my $b = [ split /\n/, $content ]; my @merged = merge( $source, $a, $b, { CONFLICT => sub ($$) { ( "<!-- $h1 -->\n", ( @{ $_[0] } ), "<!-- $h2 -->\n", ( @{ $_[1] } ), "<!-- $h3 -->\n", ); } } ); return join( '', @merged ); }
sub max_version { my $self = shift; my $max = $self->result_source->resultset->search( { page => $self->page->id }, { select => [ { max => 'me.version' } ], as => ['max_ver'] } ); return 0 unless $max->count; return $max->next->get_column('max_ver'); }
sub previous { my $self = shift; return $self->result_source->resultset->search( { page => $self->page->id, version => $self->version - 1 } )->next; }
sub pub_date { my $self = shift; return DateTime::Format::Mail->format_datetime( $self->created ); }
sub store_links { my ($self) = @_; return unless ( $self->status eq 'released' ); my $content = $self->body; my $page = $self->page; $page->result_source->resultset->set_paths($page); $page->links_from->delete(); $page->wantedpages->delete(); require MojoMojo::Formatter::Wiki; my ( $linked_pages, $wanted_pages ) = MojoMojo::Formatter::Wiki->find_links( \$content, $page ); return unless ( @$linked_pages || @$wanted_pages ); for (@$linked_pages) { my $link = $self->result_source->schema->resultset('Link') ->find_or_create( { from_page => $self->page->id, to_page => $_->id } ); } for (@$wanted_pages) { $_->{path} = join( '/', map { ( $self->result_source->schema->resultset('Page')->normalize_name($_) )[1]; } split( m|/|, $_->{path} ) ); my $wanted_page = $self->result_source->schema()->resultset('WantedPage') ->find_or_create( { from_page => $page->id, to_path => $_->{path} } ); } }
sub encoded_body { return encode_entities_numeric( shift->body ); }
1;