From db820616d0f5c7f49e725987b6cd900944e4ffd0 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Sat, 15 Nov 2008 11:51:58 +0100 Subject: Wrote revision and diff viewer Character-level diffs instead of the old word-level diffs. Still only works on plaintext, though. Not really sure about the style, either. --- lib/ChangeLog | 2 + lib/VNDB/Func.pm | 8 +-- lib/VNDB/Handler/Producers.pm | 18 ++++++- lib/VNDB/Util/CommonHTML.pm | 118 +++++++++++++++++++++++++++++++++++++++++- static/f/style.css | 53 +++++++++++++++++++ yawf | 2 +- 6 files changed, 194 insertions(+), 7 deletions(-) diff --git a/lib/ChangeLog b/lib/ChangeLog index 2dde0f6a..167bb9e4 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -20,6 +20,8 @@ TODO: - Functionality changes: - Ability to sort the userlist on vote and change counts - Added threads and posts counts to the global statistics + - Improved diff calculation + - Whitespace around input fields are removed 1.23 - 2008-10-22 (r117) - Removed redirects for old revision URLs (the code wasn't very secure...) diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm index bc6cbc87..ef18c837 100644 --- a/lib/VNDB/Func.pm +++ b/lib/VNDB/Func.pm @@ -15,11 +15,13 @@ sub shorten { } -# argument: unix timestamp +# argument: unix timestamp and optional format (compact/full) # return value: yyyy-mm-dd # (maybe an idea to use cgit-style ages for recent timestamps) sub date { - return strftime '%Y-%m-%d', gmtime shift; + my($t, $f) = @_; + return strftime '%Y-%m-%d', gmtime $t if !$f || $f eq 'compact'; + return strftime '%Y-%m-%d at %R', gmtime $t; } @@ -56,7 +58,7 @@ sub bb2html { my $raw = shift; my $maxlength = shift; $raw =~ s/\r//g; - return '' if !$raw && $raw != 0; + return '' if !$raw && $raw ne "0"; my($result, $length, @open) = ('', 0, 'first'); diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm index 43588031..bacabb08 100644 --- a/lib/VNDB/Handler/Producers.pm +++ b/lib/VNDB/Handler/Producers.pm @@ -18,12 +18,28 @@ YAWF::register( sub page { my($self, $pid, $rev) = @_; - my $p = $self->dbProducerGet(id => $pid, what => 'vn')->[0]; + my $p = $self->dbProducerGet( + id => $pid, + what => 'vn'.($rev ? ' changes' : ''), + $rev ? ( rev => $rev ) : () + )->[0]; return 404 if !$p->{id}; $self->htmlHeader(title => $p->{name}); $self->htmlMainTabs(p => $p); + if($rev) { + my $prev = $rev && $rev > 1 && $self->dbProducerGet(id => $pid, rev => $rev-1, what => 'changes')->[0]; + $self->htmlRevision('p', $prev, $p, + [ type => 'Type', serialize => sub { $self->{producer_types}{$_[0]} } ], + [ name => 'Name (romaji)', diff => 1 ], + [ original => 'Original name', diff => 1 ], + [ lang => 'Language', serialize => sub { "$_[0] ($self->{languages}{$_[0]})" } ], + [ website => 'Website', diff => 1 ], + [ desc => 'Description', diff => 1 ], + ); + } + if($p->{hidden}) { div class => 'mainbox'; h1 $p->{name}; diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm index f2c4d6ff..25e25982 100644 --- a/lib/VNDB/Util/CommonHTML.pm +++ b/lib/VNDB/Util/CommonHTML.pm @@ -3,10 +3,12 @@ package VNDB::Util::CommonHTML; use strict; use warnings; -use YAWF ':html'; +use YAWF ':html', 'xml_escape'; use Exporter 'import'; +use Algorithm::Diff 'sdiff'; +use VNDB::Func; -our @EXPORT = qw|htmlMainTabs htmlDenied htmlBrowse htmlBrowseNavigate|; +our @EXPORT = qw|htmlMainTabs htmlDenied htmlBrowse htmlBrowseNavigate htmlRevision|; # generates the "main tabs". These are the commonly used tabs for @@ -178,4 +180,116 @@ sub htmlBrowseNavigate { } +# Shows a revision, including diff if there is a previous revision. +# Arguments: v|p|r, old revision, new revision, @fields +# Where @fields is a list of fields as arrayrefs with: +# [ shortname, displayname, %options ], +# Where %options: +# diff => 1/0, whether do show a diff on this field +# serialize => coderef, should convert the field into a readable string, no HTML allowed +sub htmlRevision { + my($self, $type, $old, $new, @fields) = @_; + div class => 'mainbox revision'; + h1 'Revision '.$new->{rev}; + + # previous/next revision links + a class => 'prev', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}-1), '<- earlier revision' + if $new->{rev} > 1; + a class => 'next', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}+1), 'later revision ->' + if $new->{cid} != $new->{latest}; + p class => 'center'; + a href => "/$type$new->{id}", "$type$new->{id}"; + end; + + # no previous revision, just show info about the revision itself + if(!$old) { + div; + revheader($type, $new); + br; + b 'Edit summary:'; + br; br; + lit bb2html($new->{comments})||'[no summary]'; + end; + } + + # otherwise, compare the two revisions + else { + table; + thead; + Tr; + td; lit ' '; end; + td; revheader($type, $old); end; + td; revheader($type, $new); end; + end; + Tr; + td; lit ' '; end; + td colspan => 2; + b 'Edit summary of revision '.$new->{rev}.':'; + br; br; + lit bb2html($new->{comments})||'[no summary]'; + end; + end; + end; + my $i = 1; + revdiff(\$i, $old, $new, @$_) for (@fields); + end; + } + end; +} + +sub revheader { # type, obj + my($type, $obj) = @_; + b 'Revision '.$obj->{rev}; + txt ' ('; + a href => "/$type$obj->{id}?rev=1", 'edit'; + txt ')'; + br; + txt 'By '; + a href => "/u$obj->{requester}", $obj->{username}; + txt ' on '; + lit date $obj->{added}, 'full'; +} + +sub revdiff { + my($i, $old, $new, $short, $name, %o) = @_; + + my $ser1 = $o{serialize} ? $o{serialize}->($old->{$short}) : $old->{$short}; + my $ser2 = $o{serialize} ? $o{serialize}->($new->{$short}) : $new->{$short}; + return if $ser1 eq $ser2; + + if($o{diff} && $ser1 && $ser2) { + my($r1,$r2,$ch) = ('','','u'); + for (sdiff([ split //, $ser1 ], [ split //, $ser2 ])) { + if($ch ne $_->[0]) { + if($ch ne 'u') { + $r1 .= ''; + $r2 .= ''; + } + $r1 .= '' if $_->[0] eq '-' || $_->[0] eq 'c'; + $r2 .= '' if $_->[0] eq '+' || $_->[0] eq 'c'; + } + $ch = $_->[0]; + $r1 .= xml_escape $_->[1] if $ch ne '+'; + $r2 .= xml_escape $_->[2] if $ch ne '-'; + } + $r1 .= '' if $ch eq '-' || $ch eq 'c'; + $r2 .= '' if $ch eq '+' || $ch eq 'c'; + $ser1 = $r1; + $ser2 = $r2; + } else { + $ser1 = xml_escape $ser1; + $ser2 = xml_escape $ser2; + } + + $ser1 = '[empty]' if !$ser1 && $ser1 ne '0'; + $ser2 = '[empty]' if !$ser2 && $ser2 ne '0'; + + Tr $$i++ % 2 ? (class => 'odd') : (); + td class => 'tcname', $name; + td; lit $ser1; end; + td; lit $ser2; end; + end; +} + + 1; diff --git a/static/f/style.css b/static/f/style.css index 65dd432e..fefdac87 100644 --- a/static/f/style.css +++ b/static/f/style.css @@ -444,6 +444,59 @@ div.warning li, div.notice li { +/****** Revision information ******/ + +div.revision { + padding-bottom: 10px!important; +} +div.revision div, div.revision table { + border: 1px solid #258; + margin: 0 auto; + width: 90%; + /*background: url(/f/boxbg.png) repeat;*/ + background-color: #13273a; + clear: both; +} +div.revision table thead tr td { + background-color: transparent!important; + text-align: center; + font-weight: normal; +} +div.revision table td { + border-right: 1px solid #258; + padding: 5px; +} +div.revision div { + padding: 5px; + text-align: center; +} +.diff_add { + font-weight: normal; + background-color: #354; +} +.diff_del { + font-weight: normal; + background-color: #534; +} +div.revision .next { + float: right; + margin-right: 5%; +} +div.revision .prev { + float: left; + margin-left: 5%; +} +div.revision .item { + text-align: center; +} +div.revision .tcname { + width: 100px; +} + + + + + /****** Icons *******/ .icons { diff --git a/yawf b/yawf index 039c6309..d6a712bc 160000 --- a/yawf +++ b/yawf @@ -1 +1 @@ -Subproject commit 039c6309efa2fbc9b1d745e44a75ea9c52eb15ae +Subproject commit d6a712bcaa85bed0d427cb36a99e1f8bc128d17f -- cgit v1.2.3