Merge commit 'intrigeri/pedigree'
authorJoey Hess <joey@kodama.kitenet.net>
Wed, 16 Jul 2008 21:31:15 +0000 (17:31 -0400)
committerJoey Hess <joey@kodama.kitenet.net>
Wed, 16 Jul 2008 21:31:15 +0000 (17:31 -0400)
52 files changed:
IkiWiki.pm
IkiWiki/Plugin/aggregate.pm
IkiWiki/Plugin/conditional.pm
IkiWiki/Plugin/edittemplate.pm
IkiWiki/Plugin/fortune.pm
IkiWiki/Plugin/googlecalendar.pm
IkiWiki/Plugin/graphviz.pm
IkiWiki/Plugin/img.pm
IkiWiki/Plugin/inline.pm
IkiWiki/Plugin/linkmap.pm
IkiWiki/Plugin/meta.pm
IkiWiki/Plugin/pagetemplate.pm
IkiWiki/Plugin/pinger.pm
IkiWiki/Plugin/polygen.pm
IkiWiki/Plugin/postsparkline.pm
IkiWiki/Plugin/shortcut.pm
IkiWiki/Plugin/sparkline.pm
IkiWiki/Plugin/table.pm
IkiWiki/Plugin/template.pm
IkiWiki/Plugin/testpagespec.pm
IkiWiki/Plugin/teximg.pm
debian/changelog
doc/bugs/Broken_URL_to_your_blog_script.mdwn [new file with mode: 0644]
doc/bugs/__96____96__clear:_both__39____39___for___96__.page__42____39____63__.mdwn
doc/bugs/aggregateinline_planets_wrongly_link_to_posts.mdwn
doc/ikiwiki-transition.mdwn
doc/ikiwiki.setup
doc/plugins/aggregate.mdwn
doc/plugins/write.mdwn
doc/plugins/write/tutorial.mdwn
doc/post-commit/discussion.mdwn
doc/rcs/git/discussion.mdwn
doc/rcs/mercurial.mdwn
doc/roadmap.mdwn
doc/style.css
doc/tips/blog_script.mdwn
doc/todo/Allow_TITLE_to_include_part_of_the_path_in_addition_to_the_basename.mdwn
doc/todo/Moving_Pages.mdwn
doc/todo/aggregate_to_internal_pages.mdwn
doc/todo/applydiff_plugin.mdwn [new file with mode: 0644]
doc/todo/color_plugin.mdwn [new file with mode: 0644]
doc/todo/darcs.mdwn
doc/todo/else_parameter_for_map_plugin.mdwn [new file with mode: 0644]
doc/todo/mercurial.mdwn
doc/todo/pedigree_plugin.mdwn [new file with mode: 0644]
doc/users/intrigeri.mdwn [new file with mode: 0644]
docwiki.setup
ikiwiki-transition
po/ikiwiki.pot
t/html.t
templates/inlinepage.tmpl
templates/page.tmpl

index bcbbabbe0587f105b43b4dc83cd0ae3a025ae7bd..6a1823c5a940461ab8cf8ad5952a889323713bbf 100644 (file)
@@ -769,21 +769,30 @@ sub preprocess ($$$;$$) { #{{{
                        }
                        my $ret;
                        if (! $scan) {
-                               $ret=$hooks{preprocess}{$command}{call}->(
-                                       @params,
-                                       page => $page,
-                                       destpage => $destpage,
-                                       preview => $preprocess_preview,
-                               );
+                               $ret=eval {
+                                       $hooks{preprocess}{$command}{call}->(
+                                               @params,
+                                               page => $page,
+                                               destpage => $destpage,
+                                               preview => $preprocess_preview,
+                                       );
+                               };
+                               if ($@) {
+                                       chomp $@;
+                                       $ret="[[!$command <span class=\"error\">".
+                                               gettext("Error").": $@"."</span>]]";
+                               }
                        }
                        else {
                                # use void context during scan pass
-                               $hooks{preprocess}{$command}{call}->(
-                                       @params,
-                                       page => $page,
-                                       destpage => $destpage,
-                                       preview => $preprocess_preview,
-                               );
+                               eval {
+                                       $hooks{preprocess}{$command}{call}->(
+                                               @params,
+                                               page => $page,
+                                               destpage => $destpage,
+                                               preview => $preprocess_preview,
+                                       );
+                               };
                                $ret="";
                        }
                        $preprocessing{$page}--;
index b5354a823482e243e3c7d9fdd9ec4a2db6e010eb..e000bc8648a39f33cea5aef932286255f343f4a2 100644 (file)
@@ -21,6 +21,7 @@ sub import { #{{{
        hook(type => "preprocess", id => "aggregate", call => \&preprocess);
         hook(type => "delete", id => "aggregate", call => \&delete);
        hook(type => "savestate", id => "aggregate", call => \&savestate);
+       hook(type => "htmlize", id => "_aggregated", call => \&htmlize);
        if (exists $config{aggregate_webtrigger} && $config{aggregate_webtrigger}) {
                hook(type => "cgi", id => "aggregate", call => \&cgi);
        }
@@ -30,7 +31,10 @@ sub getopt () { #{{{
         eval q{use Getopt::Long};
        error($@) if $@;
         Getopt::Long::Configure('pass_through');
-        GetOptions("aggregate" => \$config{aggregate});
+        GetOptions(
+               "aggregate" => \$config{aggregate},
+               "aggregateinternal!" => \$config{aggregateinternal},
+       );
 } #}}}
 
 sub checkconfig () { #{{{
@@ -110,6 +114,61 @@ sub launchaggregation () { #{{{
        return 1;
 } #}}}
 
+#  Pages with extension _aggregated have plain html markup, pass through.
+sub htmlize (@) { #{{{
+       my %params=@_;
+       return $params{content};
+} #}}}
+
+# Used by ikiwiki-transition aggregateinternal.
+sub migrate_to_internal { #{{{
+       if (! lockaggregate()) {
+               error("an aggregation process is currently running");
+       }
+
+       IkiWiki::lockwiki();
+       loadstate();
+       $config{verbose}=1;
+
+       foreach my $data (values %guids) {
+               next unless $data->{page};
+               next if $data->{expired};
+               
+               $config{aggregateinternal} = 0;
+               my $oldname = pagefile($data->{page});
+               my $oldoutput = $config{destdir}."/".IkiWiki::htmlpage($data->{page});
+               
+               $config{aggregateinternal} = 1;
+               my $newname = pagefile($data->{page});
+               
+               debug "moving $oldname -> $newname";
+               if (-e $newname) {
+                       if (-e $oldname) {
+                               error("$newname already exists");
+                       }
+                       else {
+                               debug("already renamed to $newname?");
+                       }
+               }
+               elsif (-e $oldname) {
+                       rename($oldname, $newname) || error("$!");
+               }
+               else {
+                       debug("$oldname not found");
+               }
+               if (-e $oldoutput) {
+                       require IkiWiki::Render;
+                       debug("removing output file $oldoutput");
+                       IkiWiki::prune($oldoutput);
+               }
+       }
+       
+       savestate();
+       IkiWiki::unlockwiki;
+       
+       unlockaggregate();
+} #}}}
+
 sub needsbuild (@) { #{{{
        my $needsbuild=shift;
        
@@ -131,7 +190,7 @@ sub preprocess (@) { #{{{
 
        foreach my $required (qw{name url}) {
                if (! exists $params{$required}) {
-                       return "[[aggregate ".sprintf(gettext("missing %s parameter"), $required)."]]";
+                       error sprintf(gettext("missing %s parameter"), $required)
                }
        }
 
@@ -595,7 +654,7 @@ sub pagefile ($) { #{{{
 } #}}}
 
 sub htmlfn ($) { #{{{
-       return shift().".".$config{htmlext};
+       return shift().".".($config{aggregateinternal} ? "_aggregated" : $config{htmlext});
 } #}}}
 
 my $aggregatelock;
index 57db010544b52d436e7dac2ed42e34ef80445360..6be52eaa6d43b6cc5052a657a0bf907a2d1c78f1 100644 (file)
@@ -15,7 +15,7 @@ sub preprocess_if (@) { #{{{
 
        foreach my $param (qw{test then}) {
                if (! exists $params{$param}) {
-                       return "[[if ".sprintf(gettext('%s parameter is required'), $param)."]]";
+                       error sprintf(gettext('%s parameter is required'), $param);
                }
        }
 
index 76c1cd42aed37b24ff3f313a50c0d49cd4112aa7..d1716a31564031813e7d9f273ab7ff3ca02f3f5c 100644 (file)
@@ -38,10 +38,10 @@ sub preprocess (@) { #{{{
        return "" if $params{page} ne $params{destpage};
 
        if (! exists $params{template} || ! length($params{template})) {
-               return "[[meta ".gettext("template not specified")."]]";
+               error gettext("template not specified")
        }
        if (! exists $params{match} || ! length($params{match})) {
-               return "[[meta ".gettext("match not specified")."]]";
+               error gettext("match not specified")
        }
 
        $pagestate{$params{page}}{edittemplate}{$params{match}}=$params{template};
@@ -108,7 +108,9 @@ sub filltemplate ($$) { #{{{
                );
        };
        if ($@) {
-               return "[[pagetemplate ".gettext("failed to process")." $@]]";
+               # Indicate that the earlier preprocessor directive set 
+               # up a template that doesn't work.
+               return "[[!pagetemplate ".gettext("failed to process")." $@]]";
        }
 
        $template->param(name => $page);
index a3b13f687dac48aa37eee64ddf2eb7035dbac064..a78a73d5f1f4fa034777408896496971643d5f3b 100644 (file)
@@ -15,7 +15,7 @@ sub preprocess (@) { #{{{
        my $f = `fortune 2>/dev/null`;
 
        if ($?) {
-               return "[[".gettext("fortune failed")."]]";
+               error gettext("fortune failed");
        }
        else {
                return "<pre>$f</pre>\n";
index c6409e5e6db3732e1efd3ea4d5232b5dc66c76be..7efa1daa377538fdb2174eada674fca300701086 100644 (file)
@@ -19,7 +19,7 @@ sub preprocess (@) { #{{{
        # Avoid XSS attacks..
        my ($url)=$params{html}=~m#iframe\s+src="http://www\.google\.com/calendar/embed\?([^"<>]+)"#;
        if (! defined $url || ! length $url) {
-               return "[[googlecalendar ".gettext("failed to find url in html")."]]";
+               error gettext("failed to find url in html")
        }
        my ($height)=$params{html}=~m#height="(\d+)"#;
        my ($width)=$params{html}=~m#width="(\d+)"#;
index fe3559857a211807a133d9b95be05dafac5254b7..b13d15fa6350aadd237494350dd1c8949bf72700 100644 (file)
@@ -55,7 +55,7 @@ sub render_graph (\%) { #{{{
 
                waitpid $pid, 0;
                $SIG{PIPE}="DEFAULT";
-               return  "[[graph ".gettext("failed to run graphviz")."]]" if ($sigpipe);
+               error gettext("failed to run graphviz") if $sigpipe;
 
                if (! $params{preview}) {
                        writefile($dest, $config{destdir}, $png, 1);
@@ -82,7 +82,7 @@ sub graph (@) { #{{{
        $params{src} = "" unless defined $params{src};
        $params{type} = "digraph" unless defined $params{type};
        $params{prog} = "dot" unless defined $params{prog};
-       return "[[graph ".gettext("prog not a valid graphviz program")."]]" unless $graphviz_programs{$params{prog}};
+       error gettext("prog not a valid graphviz program") unless $graphviz_programs{$params{prog}};
 
        return render_graph(%params);
 } # }}}
index 49e1d57d61b49a3eb0faa7740a2a3a5c74fd744b..17a9367d3339145170256d44c734663f561e94ec 100644 (file)
@@ -46,14 +46,14 @@ sub preprocess (@) { #{{{
        my $base = IkiWiki::basename($file);
 
        eval q{use Image::Magick};
-       return "[[img ".gettext("Image::Magick not installed")."]]" if $@;
+       error gettext("Image::Magick is not installed") if $@;
        my $im = Image::Magick->new;
        my $imglink;
        my $r;
 
        if ($params{size} ne 'full') {
                my ($w, $h) = ($params{size} =~ /^(\d+)x(\d+)$/);
-               return "[[img ".sprintf(gettext('bad size "%s"'), $params{size})."]]"
+               error sprintf(gettext('bad size "%s"'), $params{size})
                        unless (defined $w && defined $h);
 
                my $outfile = "$config{destdir}/$dir/${w}x${h}-$base";
@@ -63,14 +63,14 @@ sub preprocess (@) { #{{{
 
                if (-e $outfile && (-M srcfile($file) >= -M $outfile)) {
                        $r = $im->Read($outfile);
-                       return "[[img ".sprintf(gettext("failed to read %s: %s"), $outfile, $r)."]]" if $r;
+                       error sprintf(gettext("failed to read %s: %s"), $outfile, $r) if $r;
                }
                else {
                        $r = $im->Read(srcfile($file));
-                       return "[[img ".sprintf(gettext("failed to read %s: %s"), $file, $r)."]]" if $r;
+                       error sprintf(gettext("failed to read %s: %s"), $file, $r) if $r;
 
                        $r = $im->Resize(geometry => "${w}x${h}");
-                       return "[[img ".sprintf(gettext("failed to resize: %s"), $r)."]]" if $r;
+                       error sprintf(gettext("failed to resize: %s"), $r) if $r;
 
                        # don't actually write file in preview mode
                        if (! $params{preview}) {
@@ -84,7 +84,7 @@ sub preprocess (@) { #{{{
        }
        else {
                $r = $im->Read(srcfile($file));
-               return "[[img ".sprintf(gettext("failed to read %s: %s"), $file, $r)."]]" if $r;
+               error sprintf(gettext("failed to read %s: %s"), $file, $r) if $r;
                $imglink = $file;
        }
 
@@ -101,7 +101,7 @@ sub preprocess (@) { #{{{
        }
 
        if (! defined($im->Get("width")) || ! defined($im->Get("height"))) {
-               return "[[img ".sprintf(gettext("failed to determine size of image %s"), $file)."]]";
+               error sprintf(gettext("failed to determine size of image %s"), $file)
        }
 
        my $imgtag='<img src="'.$imgurl.
index 32915c342d33898a68e8cf8b3a2a48845eeb0311..5517e3c9434e9d483f343e8c676db6da42efcda7 100644 (file)
@@ -98,7 +98,7 @@ sub preprocess_inline (@) { #{{{
        my %params=@_;
        
        if (! exists $params{pages}) {
-               return "[[inline ".gettext("missing pages parameter")."]]";
+               error gettext("missing pages parameter");
        }
        my $raw=yesno($params{raw});
        my $archive=yesno($params{archive});
index 82b38f4cb79909c449e29bd8a68340db9d343bde..ab199b7238511b74b36255363809d902ef773eb9 100644 (file)
@@ -94,9 +94,7 @@ sub genmap ($) { #{{{
        
        waitpid $pid, 0;
        $SIG{PIPE}="DEFAULT";
-       if ($sigpipe) {
-               return  "[[linkmap ".gettext("failed to run dot")."]]";
-       }
+       error gettext("failed to run dot") if $sigpipe;
 
        return $ret;
 } #}}}
index d00b6854f698126e6b6548fc0705deefc0f6f748..4e0e9e8c72162d93e99cf874da29672ff1b11ab6 100644 (file)
@@ -138,7 +138,7 @@ sub preprocess (@) { #{{{
                # editable page as a stylesheet
                my $stylesheet=bestlink($page, $value.".css");
                if (! length $stylesheet) {
-                       return "[[meta ".gettext("stylesheet not found")."]]";
+                       error gettext("stylesheet not found")
                }
                push @{$metaheaders{$page}}, '<link href="'.urlto($stylesheet, $page).
                        '" rel="'.encode_entities($rel).
@@ -172,7 +172,7 @@ sub preprocess (@) { #{{{
                        add_depends($page, $redir_page);
                        my $link=bestlink($page, $redir_page);
                        if (! length $link) {
-                               return "[[meta ".gettext("redir page not found")."]]";
+                               error gettext("redir page not found")
                        }
 
                        $value=urlto($link, $page);
@@ -185,7 +185,7 @@ sub preprocess (@) { #{{{
                        my %seen;
                        while (exists $pagestate{$at}{meta}{redir}) {
                                if ($seen{$at}) {
-                                       return "[[meta ".gettext("redir cycle is not allowed")."]]";
+                                       error gettext("redir cycle is not allowed")
                                }
                                $seen{$at}=1;
                                $at=$pagestate{$at}{meta}{redir};
index 69a2433a8ffb1d74119762c8d9aeae3e3cedae01..205f5a9d77b13ce34b6b30d7d528f7658315df09 100644 (file)
@@ -18,7 +18,7 @@ sub preprocess (@) { #{{{
        if (! exists $params{template} ||
            $params{template} !~ /^[-A-Za-z0-9._+]+$/ ||
            ! defined IkiWiki::template_file($params{template})) {
-                return "[[pagetemplate ".gettext("bad or missing template")."]]";
+                error gettext("bad or missing template")
        }
 
        if ($params{page} eq $params{destpage}) {
index c6fa76e3f8fde2652e7703e50b84f03f1a1ff829..614d428853c7d0d2efbaa74987edc97e6643a452 100644 (file)
@@ -34,7 +34,7 @@ sub needsbuild (@) { #{{{
 sub preprocess (@) { #{{{
        my %params=@_;
        if (! exists $params{from} || ! exists $params{to}) {
-               return "[[ping ".gettext("requires 'from' and 'to' parameters")."]]";
+               error gettext("requires 'from' and 'to' parameters");
        }
        if ($params{from} eq $config{url}) {
                $pagestate{$params{destpage}}{pinger}{$params{to}}=1;
index 5208a44ec5c9a342ff798a3ec8401f240f8562ba..70378cf1b7102cf383e6839cb6dfd4d64ddf2a02 100644 (file)
@@ -29,7 +29,7 @@ sub preprocess (@) { #{{{
 
        my $grmfile = '/usr/share/polygen/ita/polygen.grm';
        if (! -d '/usr/share/polygen') {
-               return "[[".gettext("polygen not installed")."]]";
+               error gettext("polygen not installed");
        }
        find({wanted => sub {
                        if (substr($File::Find::name, -length($grammar)) eq $grammar) {
@@ -48,7 +48,7 @@ sub preprocess (@) { #{{{
        }
 
        if ($?) {
-               $res="[[".gettext("polygen failed")."]]";
+               error gettext("command failed");
        }
 
        # Strip trailing spaces and newlines so that we flow well with the
index 9e885741e073bc4ded2e3947366ea6265d8249db..6fc96f8b343cbca8eeeb893c41e2569a962d915c 100644 (file)
@@ -29,14 +29,14 @@ sub preprocess (@) { #{{{
        }
 
        if (! exists $params{formula}) {
-               return "[[postsparkline ".gettext("missing formula")."]]";
+               error gettext("missing formula")
        }
        my $formula=$params{formula};
        $formula=~s/[^a-zA-Z0-9]*//g;
        $formula=IkiWiki::possibly_foolish_untaint($formula);
        if (! length $formula ||
            ! IkiWiki::Plugin::postsparkline::formula->can($formula)) {
-               return "[[postsparkline ".gettext("unknown formula")."]]";
+               error gettext("unknown formula");
        }
 
        add_depends($params{page}, $params{pages});
@@ -53,7 +53,7 @@ sub preprocess (@) { #{{{
 
        my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)};
        if ($@) {
-               return "[[postsparkline error $@]]";
+               error $@;
        }
 
        if (! @data) {
index f1a38ea48070ed255ea8046e8b4d5c1dd6787af3..8df60cfe2a34b5e428e1eafcae88ac9c71a3c0ed 100644 (file)
@@ -24,7 +24,7 @@ sub preprocess_shortcut (@) { #{{{
        my %params=@_;
 
        if (! defined $params{name} || ! defined $params{url}) {
-               return "[[shortcut ".gettext("missing name or url parameter")."]]";
+               error gettext("missing name or url parameter");
        }
 
        hook(type => "preprocess", no_override => 1, id => $params{name},
index 69b3512c27e708d1155fab842e76b46b7dbff9f5..bcff46aeb47ed8156b8d866f348ffab29a7a0f23 100644 (file)
@@ -60,13 +60,13 @@ sub preprocess (@) { #{{{
                        }
                }
                elsif (! length $value) {
-                       return "[[sparkline ".gettext("parse error")." \"$key\"]]";
+                       error gettext("parse error")." \"$key\"";
                }
                elsif ($key eq 'featurepoint') {
                        my ($x, $y, $color, $diameter, $text, $location)=
                                split(/\s*,\s*/, $value);
                        if (! defined $diameter || $diameter < 0) {
-                               return "[[sparkline ".gettext("bad featurepoint diameter")."]]";
+                               error gettext("bad featurepoint diameter");
                        }
                        $x=int($x);
                        $y=int($y);
@@ -76,7 +76,7 @@ sub preprocess (@) { #{{{
                        if (defined $location) {
                                $location=$locmap{$location};
                                if (! defined $location) {
-                                       return "[[sparkline ".gettext("bad featurepoint location")."]]";
+                                       error gettext("bad featurepoint location");
                                }
                        }
                        $php.=qq{\$sparkline->SetFeaturePoint($x, $y, '$color', $diameter};
@@ -87,23 +87,23 @@ sub preprocess (@) { #{{{
        }
 
        if ($c eq 0) {
-               return "[[sparkline ".gettext("missing values")."]]";
+               error gettext("missing values");
        }
 
        my $height=int($params{height} || 20);
        if ($height < 2 || $height > 100) {
-               return "[[sparkline ".gettext("bad height value")."]]";
+               error gettext("bad height value");
        }
        if ($style eq "Bar") {
                $php.=qq{\$sparkline->Render($height);\n};
        }
        else {
                if (! exists $params{width}) {
-                       return "[[sparkline ".gettext("missing width parameter")."]]";
+                       error gettext("missing width parameter");
                }
                my $width=int($params{width});
                if ($width < 2 || $width > 1024) {
-                       return "[[sparkline ".gettext("bad width value")."]]";
+                       error gettext("bad width value");
                }
                $php.=qq{\$sparkline->RenderResampled($width, $height);\n};
        }
@@ -141,7 +141,7 @@ sub preprocess (@) { #{{{
                waitpid $pid, 0;
                $SIG{PIPE}="DEFAULT";
                if ($sigpipe) {
-                       return  "[[sparkline ".gettext("failed to run php")."]]";
+                       error gettext("failed to run php");
                }
 
                if (! $params{preview}) {
index 11474c8f08412c701a58f60ce350888f84a1057a..892ea182e267229531db7e6b64a4067a6294b6a1 100644 (file)
@@ -19,7 +19,7 @@ sub preprocess (@) { #{{{
 
        if (exists $params{file}) {
                if (! $pagesources{$params{file}}) {
-                       return "[[table ".gettext("cannot find file")."]]";
+                       error gettext("cannot find file");
                }
                $params{data} = readfile(srcfile($params{file}));
                add_depends($params{page}, $params{file});
@@ -61,7 +61,7 @@ sub preprocess (@) { #{{{
                        defined $params{delimiter} ? $params{delimiter} : "|",);
        }
        else {
-               return "[[table ".gettext("unknown data format")."]]";
+               error gettext("unknown data format");
        }
 
        my $header;
@@ -69,7 +69,7 @@ sub preprocess (@) { #{{{
                $header=shift @data;
        }
        if (! @data) {
-               return "[[table ".gettext("empty data")."]]";
+               error gettext("empty data");
        }
 
        my @lines;
index aa1f57c0703ebcea645bb8818ef779ffaa520d1c..c33dbbb83b8d1623ffd1348667247ec3be04f082 100644 (file)
@@ -16,7 +16,7 @@ sub preprocess (@) { #{{{
        my %params=@_;
 
        if (! exists $params{id}) {
-               return "[[template ".gettext("missing id parameter")."]]";
+               error gettext("missing id parameter")
        }
 
        my $template_page="templates/$params{id}";
@@ -42,7 +42,7 @@ sub preprocess (@) { #{{{
                );
        };
        if ($@) {
-               return "[[template ".gettext("failed to process:")." $@]]";
+               error gettext("failed to process:")." $@"
        }
 
        $params{basename}=IkiWiki::basename($params{page});
index f9ec90d8791f8b5e6aa422ceb527fe272bfea9df..4faef7be197a8b20362132521ae67de2976a3ad8 100644 (file)
@@ -14,7 +14,7 @@ sub preprocess (@) { #{{{
        
        foreach my $param (qw{match pagespec}) {
                if (! exists $params{$param}) {
-                       return "[[testpagespec $param parameter is required]]";
+                       error sprintf(gettext("%s parameter is required"), $param);
                }
        }
 
index 8c3e88c6974a8f2d5aa00fc119ba1f8941f4c943..6a6bdd4fa404739789eadd065cad4c8c34e4082f 100644 (file)
@@ -27,14 +27,14 @@ sub preprocess (@) { #{{{
        
        my $code = $params{code};
        if (! defined $code && ! length $code) {
-               return "[[teximg ".gettext("missing tex code"). "]]";
+               error gettext("missing tex code");
        }
 
        if (check($code)) {
                return create($code, check_height($height), \%params);
        }
        else {
-               return "[[teximg ".gettext("code includes disallowed latex commands"). "]]";
+               error gettext("code includes disallowed latex commands")
        }
 } #}}}
 
@@ -85,7 +85,7 @@ sub create ($$$) { #{{{
                        .qq{" class="teximg" />};
        }
        else {
-               return qq{[[teximg <a href="$logurl">}.gettext("failed to generate image from code")."</a>]]";
+               error qq{<a href="$logurl">}.gettext("failed to generate image from code")."</a>";
        }
 } #}}}
 
index f10200a52644823f199d428420d6f7e01966f4b0..9039829acdef5088ce748c70b7fbd064901e001c 100644 (file)
@@ -15,10 +15,23 @@ ikiwiki (2.54) UNRELEASED; urgency=low
   * Change deb dependencies to list Text::Markdown before markdown, since
     the former, while slower, has a much better html parser that avoids
     numerous bugs.
-  * meta, inline: Support guid options, to allow forcing a particular url or
-    uuid in feeds. (smcv)
   * Move yesno function out of inline and into IkiWiki core, not exported.
-  * meta: fix title() PageSpec (smcv)
+  * Error handling improvement for preprocess hooks. It's now safe to call
+    error() from such hooks; it will cause a nicely formatted error message
+    to be inserted into the page.
+  * Cut the size of the binary package in half by excluding pages for bugs
+    and todo items from the html shipped in it.
+
+  [ Simon McVittie ]
+  * meta, inline: Support guid options, to allow forcing a particular url or
+    uuid in feeds.
+  * meta: fix title() PageSpec
+  * Some footer style changes.
+  * aggregate: Add an `aggregateinternal` option, which allows storing
+    aggregated data to internal-use files, rather than wiki pages. This
+    can save disk space, and be faster.
+  * ikiwiki-transition: Add a `aggregateinternal` transition to rename
+    the aggregated files.
 
  -- Josh Triplett <josh@freedesktop.org>  Wed, 09 Jul 2008 21:30:33 -0700
 
diff --git a/doc/bugs/Broken_URL_to_your_blog_script.mdwn b/doc/bugs/Broken_URL_to_your_blog_script.mdwn
new file mode 100644 (file)
index 0000000..3d6661d
--- /dev/null
@@ -0,0 +1,10 @@
+Joey, I would like to see your blog script I've found
+at [[Tips|tips/blog_script]] page, but it seems that the URL
+(http://git.kitenet.net/?p=joey/home;a=blob_plain;f=bin/blog)
+to its Git repo is broken:
+
+    403 Forbidden - No such project
+
+--[[Paweł|ptecza]]
+
+> [[fixed|done]] --[[Joey]]
index e389ce3ed23699a95dd929cfbdb79fa6a3ca5e98..a1b5ba94acb1ec1185147ee2a7a931e5816e38a9 100644 (file)
@@ -15,3 +15,21 @@ adding this `clear: both`?
 > before the modification date. So all of them have to clear both above and
 > below. I'm sure there are better ways for the CSS to handle that.
 > --[[Joey]] 
+
+>> There is indeed a better way - all the optional things below the
+>> content are wrapped in `<div id="footer">`, so to have the browser wait
+>> until all floating boxes have finished before rendering the footer, it
+>> would be sufficient to have `#footer { clear: both; }` and remove all
+>> the other footer-related `clear` attributes. I'm not sure what you mean
+>> by "clear above and below" - the clear attribute takes values none, left,
+>> right or both, and its purpose is to stop floating boxes (sidebars,
+>> mainly) from overlapping with footers.
+>>
+>> ... oh, I see what you mean - this affects inlines too. In inlinepage.tmpl
+>> we could wrap the "pseudo-footer" in `<div class="inlinefooter">` too?
+>> Then sites could choose whether to set clear:both on the inlinefooter
+>> or not, and this would be separate from the same styling on whole pages.
+>>
+>> [[done]] --[[smcv]]
+
+[[patch]]
index e722e9d73bcf7740c709621118a87402584b62ec..58c247631276fab0e7298c7432d811d6fc314cc6 100644 (file)
@@ -1,6 +1,17 @@
 [[!meta title="aggregate/inline planets wrongly link to posts"]]
 
 Please see 
-<http://vcs-pkg.org/planet/>. The headers of posts link to the HTML pages, which ikiwiki scraped. Also, the `\[[meta]]` titles and author directives aren't processed, but included inline. I believe that the headers should link to the posts directly, not the "cached" copies ikiwiki keeps around.
+<http://vcs-pkg.org/planet/>. The headers of posts link to the HTML pages, which ikiwiki scraped.
+I believe that the headers should link to the posts directly, not the "cached" copies ikiwiki keeps around.
+
+> As far as I can see, that problem no longer exists.
+
+Also, the `\[[meta]]` titles and author directives aren't processed, but included inline. 
+
+> Hmm, I don't see that either.
 
 What's also not ideal is that the cached copies can be edited. Any edits there will never make it to the VCS and thus won't show up in recentchanges.
+
+> That can be disabled now by enabling `aggreageinternal` --[[Joey]]
+
+> Calling this [[done]], please let me know if I missed something.
index 693c1db832472f85d3fc6823197b6970082dec2a..3290ca7e908b4328c60329523da5cfd973e0ae6f 100644 (file)
@@ -25,6 +25,11 @@ Note that if the page contains wiki links with spaces, which some
 older versions of ikiwiki accepted, the prefix_directives transition will
 treat these as preprocessor directives and convert them.
 
+# aggregateinternal
+
+The `aggregateinternal` mode moves pages aggregated by the aggregate plugin
+so that the `aggregateinternal` option can be enabled.
+
 # indexdb
 
 The `indexdb` mode handles converting a plain text `.ikiwiki/index` file to
index 6d327fd9861d298cda18b5aaefa74d6a35854922..10cb3da1d5e26f1c6392ecfa51aaa3cf52f8ea43 100644 (file)
@@ -174,8 +174,12 @@ use IkiWiki::Setup::Standard {
        # pages anonymous users can edit
        #anonok_pagespec => "*",
        
-       # For use with the aggregate plugin, to allow aggregation to be
-       # triggered via the web.
+       # For use with the aggregate plugin.
+       # Enable aggregation to internal pages. New wikis should set this to 1,
+       # but if you use aggregate already, read the aggregate plugin docs
+       # before enabling it.
+       #aggregateinternal => 1,
+       # Allow aggregation to be triggered via the web.
        #aggregate_webtrigger => 1,
        
        # For use with the pinger plugin, how many seconds to wait before
index 574c8b125e9486e3433a89711eddd4ebbab03fb0..ecca0232ea0aacbac18a451dc3446a10d27787f5 100644 (file)
@@ -1,10 +1,10 @@
-[[template id=plugin name=aggregate author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=aggregate author="[[Joey]]"]]
+[[!tag type/useful]]
 
 This plugin allows content from other feeds to be aggregated into the wiki.
-Aggregate a feed as follows
+Aggregate a feed as follows:
 
-       \[[aggregate name="example blog"
+       \[[!aggregate name="example blog" dir="example"
        feedurl="http://example.com/index.rss"
        url="http://example.com/" updateinterval="15"]]
 
@@ -13,12 +13,17 @@ more frequently than once every 15 minutes, and puts a page per post under
 the example/ directory in the wiki.
 
 You can then use ikiwiki's [[ikiwiki/blog]] support to create a blog of one or
-more aggregated feeds.
+more aggregated feeds. For example:
+
+       \[[!inline pages="internal(example/*)"]]
 
 ## setup
 
-Make sure that you have the [[html]] plugin enabled, as the created pages are
-in html format. The [[meta]] and [[tag]] plugins are also recommended. The
+New users of aggregate should enable the `aggregateinternal => 1` option in the
+.setup file. If you don't do so, you will need to enable the [[html]] plugin
+as well as aggregate itself, since feed entries will be stored as HTML.
+
+The [[meta]] and [[tag]] plugins are also recommended. The
 [[htmltidy]] plugin is suggested, since feeds can easily contain html
 problems, some of which tidy can fix.
 
@@ -31,7 +36,7 @@ crontab entry:
 Alternatively, you can allow `ikiwiki.cgi` to trigger the aggregation. You
 should only need this if for some reason you cannot use cron, and instead
 want to use a service such as [WebCron](http://webcron.org). To enable
-this, enable on `aggregate_webtrigger` in your setup file. The url to
+this, turn on `aggregate_webtrigger` in your setup file. The url to
 visit is `http://whatever/ikiwiki.cgi?do=aggregate_webtrigger`. Anyone
 can visit the url to trigger an aggregation run, but it will only check
 each feed if its `updateinterval` has passed.
@@ -59,9 +64,44 @@ directive:
 * `tag` - A tag to tag each post from the feed with. A good tag to use is
   the name of the feed. Can be repeated multiple times. The [[tag]] plugin
   must be enabled for this to work.
-* `template` - Template to use for creating the html pages. Defaults to
+* `template` - Template to use for creating the aggregated pages. Defaults to
   aggregatepost.
 
 Note that even if you are using subversion or another revision control
 system, pages created by aggregation will *not* be checked into revision
 control.
+
+## internal pages and `aggregateinternal`
+
+This plugin creates a page for each aggregated item. 
+
+If the `aggregateinternal` option is enabled in the setup file (which is
+recommended), aggregated pages are stored in the source directory with a
+"._aggregated" extension. These pages cannot be edited by web users, and
+do not generate first-class wiki pages. They can still be inlined into a
+blog, but you have to use `internal` in [[PageSpecs|IkiWiki/PageSpec]],
+like `internal(blog/*)`.
+
+For backward compatibility, the default is that these pages have the
+".html" extension, and are first-class wiki pages -- each one generates
+a separate HTML page in the output, and they can even be edited.
+
+That turns out to not be ideal for aggregated content, because publishing
+files for each of those pages is a waste of disk space and CPU, and you
+probably don't want to allow them to be edited. So, there is an alternative
+method that can be used (and is recommended), turned on by the
+`aggregateinternal` option in the setup file.
+
+If you are already using aggregate and want to enable `aggregateinternal`,
+you should follow this process:
+
+1. Update all [[PageSpecs|ikiwiki/PageSpec]] that refer to the aggregated
+   pages -- such as those in inlines. Put "internal()" around globs 
+   in those PageSpecs. For example, if the PageSpec was `foo/*`, it should
+   be changed to `internal(foo/*)`. This has to be done because internal
+   pages are not matched by regular globs.
+2. Turn on `aggregateinternal` in the setup file.
+3. Use [[ikiwiki-transition]] to rename all existing aggregated `.html`
+   files in the srcdir. The command to run is
+   `ikiwiki-transition aggregateinternal $setupfile`,
+4. Refresh the wiki. (`ikiwiki -setup your.setup -refresh`)
index 6b49ec58d9379b86b8fc6c842bce8479401681d8..4dc55e30219667428cff64d57931683cb88ebd71 100644 (file)
@@ -412,12 +412,13 @@ Aborts with an error message. If the second parameter is passed, it is a
 function that is called after the error message is printed, to do any final
 cleanup.
 
-Note that while any plugin can use this for a fatal error, plugins should
-try to avoid dying on bad input when building a page, as that will halt
-the entire wiki build and make the wiki unusable. So for example, if a
-[[ikiwiki/PreProcessorDirective]] is passed bad parameters, it's better to
-return an error message, which can appear on the wiki page, rather than
-calling error().
+If called inside a preprocess hook, error() does not abort the entire
+wiki build, but instead replaces the [[ikiwiki/PreProcessorDirective]] with
+a version containing the error message.
+
+In other hooks, error() is a fatal error, so use with care. Try to avoid
+dying on bad input when building a page, as that will halt
+the entire wiki build and make the wiki unusable.
 
 #### `template($;@)`
 
index 8b12fd183c01f1bec27b37bb549bf06f34a1d1be..94b72c763c565ddc86efe1e48d0c700a7d5ee62f 100644 (file)
@@ -169,7 +169,7 @@ be a guard on how high it will go.
                }
                my $num=$last{$page}++;
                if ($num > 25) {
-                       return "[[fib will only calculate the first 25 numbers in the sequence]]";
+                       error "can only calculate the first 25 numbers in the sequence";
                }
                return fib($num);
        }
@@ -182,7 +182,7 @@ does for numbers less than 1. Or for any number that's not an integer. In
 either case, it will run forever. Here's one way to fix that:
 
                if (int($num) != $num || $num < 1) {
-                       return "[[fib positive integers only, please]]";
+                       error "positive integers only, please";
                }
 
 As these security problems have demonstrated, even a simple input from the
index 3c2b264fb3a7a5f65617473d1be898d7b35d009f..08125d9ff6d6f5814adfe0b10d8165fc363b2507 100644 (file)
@@ -34,3 +34,10 @@ Regards.
 >              notify => 1,
 >      }
 >      ],
+
+
+Hello, I've setup ikiwiki with subversion. I can edit pages from web browser using CGI and, when I go to recentchanges, it shows that modification with "web" word. But, if I modify any .mdwn file, it gets updated in website but it doesn't show in recentchanges entry with "svn" word. If I run "svn ci -m changes", it shows in recentchanges correctly.
+
+So, I think I miss something, because I don't think I must run "svn add" or "svn commit" anytime I modify or create a wiki file.
+
+Thanks
index 4c7df375a07c05dfa91fdb6e3e816f3e727c6518..2bb61c6a1c3fe9ab227be93c03a3003ae73a656a 100644 (file)
@@ -83,3 +83,11 @@ Thanks to gitte on #git on Freenode and of course joeyh. Have a look at [[rcs/de
 I think it would be a good thing if the various git pages where somehow unified. It seems to me that [[tips/laptop_wiki_with_git]] is currently not so different from [[git]]. Let us see what joeyh thinks about the new git pages, but if this level of detail is to go there, I think it could pretty much include (maybe as sub pages) the info in [[tips/laptop_wiki_with_git]] and [[tips/laptop_wiki_with_git_extended]] --[[DavidBremner]]
 
 # Does 'push' from the shallow clones work for you? git-clone and git-fetch explicitly state it doesn't... 
+
+-------
+
+## Permissions for web users and local users editing and creating pages
+What is the right permissions setup for a situation where both web and local users will be editing and creatingt pages? 
+My usage is this: I have a repository /srv/git/wiki.git chowned to me:apache with 775/664 permissions recursively (where 'me' is my account and the ikiwiki administrator), a /srv/www/ikisrc chowned to apache:apache, and a /srv/www/html/wiki chowned to apache:apache. As is, I can commit to the wiki.git repo (because it is owned by me) and web users can commit to it as well (because the group also has write access) what happens when I create a new page from either of those sources? For example, the apache user running ikiwiki.cgi would create /srv/www/ikisrc/something.mdwn, commit and push it to /srv/git/wiki.git, but that new object is owned by apache:apache. If I then try to commit a change to something.mdwn from a cloned repo sitting on my laptop, for example, will the commit not fail because apache created the files? 
+
+Does that mean that apache:apache should just own everything, and I should only commit through that user (via git:// protocol only, maybe, or ssh as apache instead of myself)? For some reason, my head can't quite wrap itself around the whole permissions issue. Thanks. --mrled
index 5eaae199742fe6c6079ea72b1712f01cc10a3bb2..b4baf07f4a32ba4af0bdfd40e3cd0d3f2657d80e 100644 (file)
@@ -2,7 +2,17 @@
 system developed by Matt Mackall. Ikiwiki supports storing a wiki in a
 mercurial repository.
 
-Ikiwiki can run as a post-update hook to update a wiki whenever commits
+Ikiwiki can run as a `post-commit` and/or `incoming` hook to update a wiki whenever commits or remote pushes
 come in. When running as a [[cgi]] with Mercurial, ikiwiki automatically
 commits edited pages, and uses the Mercurial history to generate the
 [[RecentChanges]] page.
+
+Example for a `.hg/hgrc` file in `$SRCDIR`:
+
+    [hooks]
+    post-commit = /home/abe/bin/rebuildwiki
+    incoming = /home/abe/bin/rebuildwiki
+
+Do not use `commit` or `precommit` hooks or ikiwiki will run into a dead lock when committing in `$SRCDIR`
+
+See also [[todo/mercurial|todo/mercurial]]
index af46e162be7f89ab3efb33dc5dc96f1c0b3343ce..32752715d8fe4b1f2c50219227ff396c50884080 100644 (file)
@@ -42,7 +42,8 @@ backwards compatability.
 Still in the early planning stages, version 3.0 will be an opportunity to
 make significant transitions.
 
-* Default to using prefix_directives.
+* Default to using `prefix_directives`.
+* Default to using `aggregateinternal`.
 
 ----
 
index 246da1ffc9648c16217bbce2d5c21dccd0939d25..0e3bfb3e6caf3226988a74f5f299debd8ab62ee2 100644 (file)
        padding: .2em .4em;
 }
 
-.tags {
+.pagefooter {
        clear: both;
 }
 
+.tags {
+}
+
 #pageinfo {
-       clear: both;
        margin: 1em 0;
        border-top: 1px solid #000;
 }
@@ -140,7 +142,6 @@ div.recentchanges {
 .pagedate,
 .pagelicense,
 .pagecopyright {
-       clear: both;
        font-style: italic;
        display: block;
        margin-top: 1em;
index b0f5f14c160451367a4f133091948ad9e55689b9..1dfd715383526269b2d3ea867ae6abcc80bb8f2a 100644 (file)
@@ -1,4 +1,4 @@
-I have a [blog](http://git.kitenet.net/?p=joey/home;a=blob_plain;f=bin/blog)
+I have a [blog](http://git.kitenet.net/?p=joey/home.git;a=blob_plain;f=bin/blog)
 program that I use to write blog posts in a text editor. The first line I
 enter is used as the title, and it automatically comes up with a unique page
 name based on the title and handles all the details of posting to my blog.
index 27d238ecd9d2616da57e70dd05ac0f13d83f70b1..b97c81efa2c1ea6e0e647b65a0b43e12efa81bc0 100644 (file)
@@ -75,5 +75,5 @@ a dedicated plugin, called `genealogictitle` or whatever, and :
 
 >> Well, it seems I once more designed a solution before clearly
 >> defining my problem... What I really need is more generic, can be
->> done as a plugin, and deserves its own todo item (yet to come), so
+>> done as a plugin, and deserves its own [[todo|pedigree_plugin]], so
 >> I'm tagging this one wontfix^W [[done]]. I'm sorry. -- intrigeri
index 2e0603ca77bf4551f18785f3b9ccddaa21a89149..38a5d3ad288c7247c6544a4c6d1944d8f5476e42 100644 (file)
@@ -313,3 +313,134 @@ before it is moved? Bail, or shrug and proceed?
      <TMPL_IF NAME="RECENTCHANGESURL">
      <li><a href="<TMPL_VAR RECENTCHANGESURL>">RecentChanges</a></li>
      </TMPL_IF>
+
+----
+
+I'm going to try to run through a full analysis and design for moving and
+deleting pages here. I want to make sure all cases are covered. --[[Joey]]
+
+## UI
+
+The UI I envision is to add "Rename" and "Delete" buttons to the file edit
+page. Both next to the Save button, and also at the bottom of the attachment
+management interface.
+
+The attachment(s) to rename or delete would be selected using the check boxes
+and then the button applies to all of them. Deleting multiple attachments
+in one go is fine; renaming multiple attachments in one go is ambiguous,
+and it can just error out if more than one is selected for rename.
+(Alternatively, it could allow moving them all to a different subdirectory.)
+
+The Delete buttons lead to a page to confirm the deletion(s).
+
+The Rename buttons lead to a page with a text edit box for editing the
+page name. The title of the page is edited, not the actual filename.
+
+There will also be a optional comment field, so a commit message can be
+written for the rename/delete.
+
+Note that there's an edge case concerning pages that have a "/" encoded
+as part of their title. There's no way for a title edit box to
+differentiate between that, and a "/" that is instended to refer to a
+subdirectory to move the page to. Consequence is that "/" will always be
+treated literally, as a subdir separator; it will not be possible to use
+this interface to put an encoded "/" in a page's name.
+
+Once a page is renamed, ikiwiki will return to the page edit interface,
+now for the renamed page. Any modifications that the user had made to the
+textarea will be preserved.
+
+Similarly, when an attachment is renamed, or deleted, return to the page
+edit interface (with the attachments displayed).
+
+When a page is deleted, redirect the user to the toplevel index.
+
+Note that this design, particularly the return to the edit interface after
+rename, means that the rename button can *only* be put on the page edit ui.
+It won't be possible to put it on the action bar or somewhere else. (It
+would be possible to code up a different rename button that doesn't do
+that, and use it elsewhere.)
+
+## SubPages
+
+When renaming `foo`, it probably makes sense to also rename
+`foo/Discussion`. Should other SubPages in `foo/` also be renamed? I think
+it's probably simplest to rename all of its SubPages too.
+
+When deleting `foo`, I don't think SubPages should be deleted. The
+potential for mistakes and abuse is too large.
+
+## link fixups
+
+When renaming a page, it's desirable to keep links that point to it
+working. Rather than use redirection pages, I think that all pages that
+link to it should be modified to fix their links.
+
+In some cases, a redirection page will be wanted, to keep long-lived urls
+working. Since the meta plugin supports creating such pages, and since they
+won't always be needed, I think it will be simplest to just leave it up to
+the user to create such a redirection page after renaming a page.
+
+## who can delete/rename what?
+
+The source page must be editable by the user to be deleted/renamed.
+When renaming, the dest page must not already exist, and must be creatable
+by the user, too.
+
+When deleting/renaming attachments, the `allowed_attachments` PageSpec
+is checked too.
+
+## RCS
+
+Two new optional functions are added to the RCS interface:
+
+* `rcs_delete(file, message, rcstoken, user, ipaddr)`
+* `rcs_rename(old, new, message, rcstoken, user, ipaddr)`
+
+The page move/rename code will check if these are not available, and error
+out.
+
+Similar to `rcs_commit` both of these take a rcstoken, which is generated
+by an earlier `rcs_prepedit`.
+
+## conflicts
+
+Cases that have to be dealt with:
+
+* Alice clicks "delete" button for a page; Bob makes a modification;
+  Alice confirms deletion. Ideally in this case, Alice should get an error
+  message that there's a conflict.
+* Alice opens edit UI for a page; Bob makes a modification; Alice
+  clicks delete button and confirms deletion. Again here, Alice should get
+  a conflict error. Note that this means that the rcstoken should be
+  recorded when the edit UI is first opened, not when the delete button is
+  hit.
+* Alice and Bob both try to delete a page at the same time. It's fine for
+  the second one to get a message that it no longer exists. Or just to
+  silently fail to delete the deleted page..
+* Alice deletes a page; Bob had edit window open for it, and saves
+  it afterwards. I think that Bob should win in this case; Alice can always
+  notice the page has been added back, and delete it again.
+* Alice clicks "rename" button for a page; Bob makes a modification;
+  Alice confirms rename. This case seems easy, it should just rename the
+  modified page.
+* Alice opens edit UI for a page; Bob makes a modification; Alice
+  clicks rename button and confirms rename. Seems same as previous case.
+* Alice and Bob both try to rename a page at the same time (to probably
+  different names). Or one tries to delete, and the other to rename. 
+  I think it's acceptible for the second one to get an error message that
+  the page no longer exists.
+* Alice renames a page; Bob had edit window open for it, and saves
+  it afterwards, under old name. I think it's acceptible for Bob to succeed
+  in saving it under the old name in this case, though not ideal.
+* Alice renames (or deletes) a page. In the meantime, Bob is uploading an
+  attachment to it, and finishes after the rename finishes. Is it
+  acceptible for the attachment to be saved under the old name?
+* Alice starts creating a new page. In the meantime, Bob renames a
+  different page to that name. Alice should get an error message when
+  committing; and it should have conflict markers. Ie, this should work the
+  same as if Bob had edited the new page at the same time as Alice did.
+* Bob starts renaming a page. In the meantime, Alice creates a new page
+  with the name he's renaming it to. Here Bob should get a error message
+  that he can't rename the page to an existing name. (A conflict resolution
+  edit would also be ok.)
index 90b6e5f0957b2d44b6f4ca7fab1f434ffda14409..38427133f006e73338bf426eafde5a822eaa89e2 100644 (file)
@@ -51,4 +51,9 @@ change their pagespecs to use `internal()`.
 > to move the pages, and even, possibly update the pagespecs (not sure how
 > it could figure out which ones tho). --[[Joey]]
 
-[[patch]]
+> I've patched ikiwiki-transition to have an aggregateinternal mode.
+> See my aggregateinternal branch, again.
+> "ikiwiki-transition aggregateinternal $setupfile" moves the pages around,
+> although it doesn't update the pagespecs (I wouldn't know how...) --[[smcv]]
+
+[[tag patch done]]
diff --git a/doc/todo/applydiff_plugin.mdwn b/doc/todo/applydiff_plugin.mdwn
new file mode 100644 (file)
index 0000000..d3eb979
--- /dev/null
@@ -0,0 +1,56 @@
+[[!tag wishlist]]
+
+[[!toc ]]
+
+Summary
+=======
+
+Allow a user to apply an arbitrary diff, in order to modify a given
+page (or, even better, a given set of pages).
+
+Rationale
+=========
+
+To edit intensively an ikiwiki-powered website can quickly get
+annoying for anybody meeting enough of the following conditions:
+
+* living mainly offline
+* having no commit access to the RCS backing up the site (BTW, please
+  note I can send my ssh public key to anyone who asks for, free of
+  charges)
+* hating web-browsers and despising textareas
+* loving in his/her own preferred `$EDITOR`
+
+... and when one gathers all of these defaults, she/he is on her/his
+way to get mad. Soon.
+
+Before it's too late, some dareful ones dream of the following
+playflow:
+
+1. Go online.
+1. Update local working copy.
+1. Go offline.
+1. `$EDITOR` : write, report, answer, propose
+1. Go online.
+1. Update local working copy (and optionally fix conflicts between
+   local changes and remote ones).
+1. Generate a diff.
+1. Use a web-browser to paste the diffs (or better, upload them into
+   a form) somewhere on the wiki, and click "Apply".
+1. git pull (to reflect locally the fact that the diff has been
+   applied to the remote repo)
+1. Go offline.
+
+(This is for sure a bit theoretical: the ones who dream of this would
+actually insert various steps about branching, merging and rebasing
+random stuff.)
+
+Design
+======
+
+This has to be thought very carefully, to avoid one to apply diffs to
+pages he/she is not allowed to edit. Restricting a given diff to
+modify only *one* page may be easier.
+
+Implementation
+==============
diff --git a/doc/todo/color_plugin.mdwn b/doc/todo/color_plugin.mdwn
new file mode 100644 (file)
index 0000000..8efd437
--- /dev/null
@@ -0,0 +1,36 @@
+Recently I've wanted to colour some piece of text on my Ikiwiki page.
+It seems that Markdown can do it only using HTML tags, so I used
+`<span class="color">foo bar baz</span>`.
+
+However, in my opinion mixing Markdown syntax and HTML tags is rather ugly,
+so maybe we should create a new color plugin to add more color to Ikiwiki ;)
+I know that another Wikis have similar plugin, for example
+[WikiDot](http://www.wikidot.com/).
+
+I've noticed that htmlscrubber plugin strips `style` attribute, because of
+security, so probably we need to use `class` attribute of HTML. But then
+we have to customize our `local.css` file to add all color we want to use.
+It's not as easy in usage like color name or definition as plugin argument,
+but I don't have a better idea right now.
+
+What do you think about it? --[[PaweÅ‚|ptecza]]
+
+> Making a plugin preserve style attributes can be done, it just has to add
+> them after the sanitize step, which strips them. The general method is
+> adding placeholders first, and replacing them with the real html later.
+> 
+> The hard thing to me seems to be finding a syntax that is better than a
+> `<span>`. A preprocessor directive is not really any less ugly than html
+> tags, though at least it could play nicely with nested markdown: --[[Joey]]
+> 
+>      \[[color red,green """
+>      Xmas-colored markdown here
+>      """]]
+
+>> I'm glad you like that idea. In my opinion your syntax looks good.
+>> Out of curiosity, why did you used 2 colors in your example? What is HTML
+>> result for it? ;)
+
+>> I can try to create that plugin, if you are too busy now. I'm not Perl
+>> hacker, but I wrote a lot of Perl scripts in my life and color plugin
+>> doesn't seem to be very hard task. --[[PaweÅ‚|ptecza]]
index c31ce105c467c7ca06a17ed4a5f54e3c9f32494c..84c99dabae0c4801cca429f5f1e44e1b160f4ddd 100644 (file)
@@ -480,4 +480,8 @@ It is in a [darcs repository](http://joyful.com/darcsweb/darcsweb.cgi?r=ikiwiki-
 >   conflicts and return a page with conflict markers for the user to fix
 >   the conflict.
 
+I have addressed the recentchanges bit, you can find my hacked up darcs.pm at <http://web.mornfall.net/stuff/web-root/IkiWiki/Rcs/darcs.pm>.
+
+It's got couple of FIXMEs, and a very site-specific filter for recentchanges. Not sure how to do that better though. I will eventually add web commits, probably of my own (and mention it here).
+
 [[tag patch]]
diff --git a/doc/todo/else_parameter_for_map_plugin.mdwn b/doc/todo/else_parameter_for_map_plugin.mdwn
new file mode 100644 (file)
index 0000000..9508e08
--- /dev/null
@@ -0,0 +1,9 @@
+[[!tag patch]]
+
+[[plugins/map]] (and I) could benefit from a bonus parameter:
+
+       else="Display this if no page matches the PageSpec"
+
+This was quite simple, so I implemented this (branch "map" in my
+ikiwiki repo, see my user page for the up-to-date URL). Not patched the
+documentation yet, I'm waiting for feedback first, but I'll do it for sure. -- [[intrigeri]]
index 0a1098f70fe3ff3d922ac949ebd61865a47a2d05..77b538c02a9876834bb722a1edb7054ad4258153 100644 (file)
@@ -1,5 +1,3 @@
-* Need to get post commit hook working (or an example of how to use it.)
-  * See below. --[[bma]]
 * rcs_notify is not implemented (not needed in this branch --[[Joey]])
 * Is the code sufficiently robust? It just warns when mercurial fails.
 * When rcs_commit is called with a $user that is an openid, it will be
diff --git a/doc/todo/pedigree_plugin.mdwn b/doc/todo/pedigree_plugin.mdwn
new file mode 100644 (file)
index 0000000..9504a96
--- /dev/null
@@ -0,0 +1,182 @@
+After realizing (thanks to
+[[Allow_TITLE_to_include_part_of_the_path_in_addition_to_the_basename]])
+that I needed some kind of "parentlinks on steroids", I wrote a new
+plugin, called pedigree.
+
+This plugin provides a bunch of loops that one can use in his/her
+`HTML::Template`'s to iterate over all or a subset of a page's
+parents. Inside these loops, half a dozen variables are made
+available, in addition to `PAGE` and `URL` that are already provided
+by parentlinks.
+
+Amongst many possibilities, one can e.g. simply use this plugin to
+give every parent link a different `class=` attribute, depending
+either on its depth in the path leading to the current page, or on its
+distance to it.
+
+The code and documentation (including simple and complex usage
+examples) are in the 'pedigree' Git branch in this repo:
+
+       git://repo.or.cz/ikiwiki/intrigeri.git
+
+Seems there is also a [gitweb](http://repo.or.cz/w/ikiwiki/intrigeri.git).
+
+> Ok, I'll take a look. BTW, could you allow user joey on repo.or.cz
+> push access to the main ikiwiki repo you set up there? --[[Joey]]
+
+>> I did not. The main ikiwiki repo on repo.or.cz seems to have been
+>> been setup by johannes.schindelin@gmx.de ; mine is what they call
+>> a "fork" (but it's not, obviously). -- intrigeri
+
+Any opinions on the idea/design/implementation?
+
+> Seems that there should be a more generic way to do `PEDIGREE_BUT_ROOT`
+> and `PEDIGREE_BUT_TWO_OLDEST` (also `is_second_ancestor`,
+> `is_grand_mother` etc). One way would be to include in `PEDIGREE`
+> a set of values like `depth_1`, `depth_2`, etc. The one corresponding
+> to the `absdepth` would be true. This would allow a template like this:
+
+       <TMPL_LOOP NAME="PEDIGREE">
+         <TMPL_IF NAME="depth_1">
+           </TMPL_ELSE>
+           <TMPL_IF NAME="depth_2">
+           </TMPL_ELSE>
+             <TMPL_VAR PAGE> /* only showing pages 2 levels deep */
+           </TMPL_IF>
+         </TMPL_IF>
+       </TMPL_LOOP>
+
+> The only missing information would be `reldepth`, but in the above
+> example the author of that template knows that it's `absdepth - 1`
+> (Things would be a lot nicer if `HTML::Template` had equality tests!)
+> 
+> Since this would make it more generic and also fix your one documented
+> bug, I can see no reason not to do it. ;-) --[[Joey]]
+
+>> Thanks for your comments. I'll answer soon. (Grrr, I really
+>> need to find a way to edit this wiki offline, every minute
+>> online costs bucks to me, my old modem gently weeps,
+>> and I hate webbrowsers.) -- intrigeri
+
+>>> Well, I maybe didn't get your idea properly; I may be missing 
+>>> something obvious, but:
+
+>>> * I don't understand how this would replace `is_grand_mother`. As a template
+>>>   writer, I don't know, given an absolute array index (and this is the only
+>>>   piece of data your solution gives me), if it will be e.g. the before-last
+>>>   (how do I say this in correct English?) element of an array whose
+>>>   (variable) size is unknown to me.
+>>> * Knowing that `reldepth`'s value is, in a given loop, always equal to
+>>>   `absdepth - 1` is of little use to me (as a template writer): how do I use
+>>>   this piece of information programmatically in my templates, if I want all
+>>>   links with `reldepth==2` to be given the same style? I guess some bits of
+>>>   Javascript might do the trick, but if it's getting so complicated, I'll
+>>>   just style my parentlinks another way.
+
+>>>> Perhaps I misunderstood what `is_grand_mother` is supposed to do. The
+>>>> docs were not very clear to me. If it's supposed to be 2 down from
+>>>> the page, (and not from the root), this could be achieved by reversing
+>>>> the `depth_n` variables. So the page gets `depth_1` set, its parent gets
+>>>> `depth_2` set, etc. If you want to be able to include/exclude
+>>>> from both ends, you could also have a `height_n` that is 1 for the
+>>>> root, and counts upwards. --[[Joey]]
+
+>>> In my understanding, your suggestion gives us little more than can already
+>>> be achieved anyway with `HTML::Template`'s `loop_context_vars` (i.e.
+>>> `__first__`, `__last__` and `__counter__`). The only added bonus is doing
+>>> custom stuff for an arbitrary element in the loop, chosen by its absolute
+>>> depth. Please correct me if needed.
+
+>>> (Intermezzo: in the meantime, to suit my personal real-world needs, I added
+>>> a `DISTANCE` loop-variable. Quoting the documentation, it's "thedistance,
+>>> expressed in path elements, from the current page to the current path
+>>> element; e.g. this is 1 for the current page's mother, 2 for its
+>>> grand-mother, etc.".)
+
+>>> Anyway, your comments have made me think of other ways to simplify a bit
+>>> this plugin, which admittedly provides too much overlapping functionality.
+>>> Bellow is my reasoning.
+
+>>> In one of my own real world examples, my two main use cases are :
+
+>>> * the "full-blown example" provided in the documentation (i.e.
+>>>   displaying every parent but mother and grand'ma as a group, and giving
+>>>   every of these two last ones their dedicated div);
+>>> * skipping the two oldest parents, and inside what's left, displaying the
+>>>   three youngest parents (i.e. mother, grand'ma and grand'grand'ma), each
+>>>   one with a dedicated style;
+
+>>> Both of these can be achieved by combining `PEDIGREE`, `DISTANCE`, and some
+>>> CSS tricks to hide some parts of the list. `IS_MOTHER` and
+>>> `IS_GRAND_MOTHER`, as well as `PEDIGREE_BUT_TWO_OLDEST`, would be convenient
+>>> shortcuts, but I do not formally need them.
+
+>>> So... it seems things can be simplified greatly:
+
+>>> * I initially added `RELDEPTH` for completeness, but I'm not sure anyone
+>>>   would use it. Let's give it up.
+>>> * Once `RELDEPTH` is lost (modulo Git tendencies to preserve history), the
+>>>   known bug is gone as well, and `PEDIGREE_BUT_ROOT` and
+>>>   `PEDIGREE_BUT_TWO_OLDEST` are now only convenient shortcuts functions;
+>>>   they could as well disappear, if you prefer to.
+
+>>> It appears then that I'd be personally happy with the single `PEDIGREE` loop
+>>> (renamed to `PARENTLINKS`), providing only `PAGE`, `URL`, `ABSDEPTH` (maybe
+>>> renamed to `DEPTH`), and `DISTANCE`. This would make my templates a bit more
+>>> complicated to write and read, but would also keep the plugin's code to the
+>>> bare minimum. Let's say it is my up-to-date proposal. (Well, if the various
+>>> shortcuts don't really annoy you, I'd be glad to keep them ;)
+
+>>>> This sounds fairly similar to what I just described above. (I called
+>>>> DISTANCE "height".) I don't know about the CSS tricks; seems like if
+>>>> `DEPTH_n` and `DISTANCE_n` are provided, you can test for them inside
+>>>> the loop using HTML::Template's lame testing, and isolate any page or
+>>>> range of pages. --[[Joey]]
+
+>>>>> Ok, I definitely like this idea, as an effective and generic
+>>>>> page-range selection tool; this seems the way to go to me.
+
+>>>>> But if you discard the `DEPTH` and `HEIGHT`
+>>>>> counters, we lack a way to **style**, for example, every parent link
+>>>>> depending on its depth or height; one can do this for arbitrary
+>>>>> parents (chosen by their height or depth), but *not* for *any* parent,
+>>>>> since there is no way to express, with HTML::Template, something like
+>>>>> "display the name of the only `DEPTH_n` variable that is currently
+>>>>> true". So I am in favor of keeping the `DEPTH` and `HEIGHT` counters,
+>>>>> to allow constructs like:
+
+       <TMPL_LOOP NAME="PARENTLINKS">
+       <a href="<TMPL_VAR NAME="URL">" class="parentdistance<TMPL_VAR NAME="DISTANCE">">
+         <TMPL_VAR NAME="PAGE">
+       </a> / 
+       </TMPL_LOOP>
+
+>>>>> This seems to me a nice functionality bonus, and should not
+>>>>> imply too bloated code. I'm thus going to rewrite the plugin
+>>>>> with only `PEDIGREE`, `DEPTH`, `HEIGHT`, `DEPTH_n` and
+>>>>> `HEIGHT_n`. -- intrigeri
+
+>>>>>> Done, and pushed in my pedigree branch. Update: I've also done and
+>>>>>> pushed two commits that rename the plugin and replace 
+>>>>>> the core parentlinks with this one. --[[intrigeri]]
+
+(I'll try never to rebase this branch, but writing this plugin has
+been a pretext for me to start learning Git, so...)
+
+To finish with, it seems no plugin bundled with ikiwiki uses the current
+parentlinks implementation, so one could event think of moving it from the
+core to this plugin (which should then be enabled by default, since the
+default templates do use parentlinks ;).
+
+> I think that moving parentlinks out to a plugin is a good idea.
+> However, if it's done, I think the plugin should be named parentlinks,
+> and should continue to use the same template variables as are used now,
+> to avoid needing to change custom templates. Pedigree is a quite nice
+> name, but renaming it to parentlinks seems to be the way to go to me.
+> --[[Joey]]
+
+>> Agreed. -- intrigeri
+
+>> Just commited a testsuite for this plugin, BTW. It's nearly twice 
+>> big as the plugin itself, I'm wondering... -- intrigeri
+
diff --git a/doc/users/intrigeri.mdwn b/doc/users/intrigeri.mdwn
new file mode 100644 (file)
index 0000000..681b357
--- /dev/null
@@ -0,0 +1,4 @@
+intrigeri AT boum.org, already loving ikiwiki.
+
+* [gnupg key](http://gaffer.boum.org/intrigeri/intrigeri.asc)
+* Git repository ([gitweb](http://repo.or.cz/w/ikiwiki/intrigeri.git)) with various ikiwiki {feature, bugfix}-branches : `git://repo.or.cz/ikiwiki/intrigeri.git`
index 0a6a86678e7591f4c3178cbe0e8c5e2236ac3148..ba3dd680d409d8afcf9e0e4019e618e6884acde2 100644 (file)
@@ -9,7 +9,7 @@ use IkiWiki::Setup::Standard {
        underlaydir => "underlays/basewiki",
        wrappers => [],
        discussion => 0,
-       exclude => qr/\/discussion/,
+       exclude => qr/\/discussion|bugs\/*|todo\/*/,
        locale => '',
        verbose => 1,
        syslog => 0,
index ce081fe63f63ffe0eb22492148ff8228994fee32..3e2c89bf9d0166d2a1b29d56541b4b8c272d75d7 100755 (executable)
@@ -99,12 +99,25 @@ sub hashpassword {
        }
 }
 
+sub aggregateinternal {
+       require IkiWiki::Setup;
+       require IkiWiki::Plugin::aggregate;
+
+       %config = (IkiWiki::defaultconfig(), IkiWiki::Setup::load(shift));
+       IkiWiki::checkconfig();
+
+       IkiWiki::Plugin::aggregate::migrate_to_internal();
+
+       print "... now add aggregateinternal => 1 to your .setup file\n";
+}
+
 sub usage {
        print STDERR "Usage: ikiwiki-transition type ...\n";
        print STDERR "Currently supported transition subcommands:\n";
        print STDERR "  prefix_directives file\n";
        print STDERR "  indexdb srcdir\n";
        print STDERR "  hashpassword srcdir\n";
+       print STDERR "  aggregateinternal setupfile\n";
        exit 1;
 }
 
@@ -120,6 +133,9 @@ elsif ($mode eq 'hashpassword') {
 elsif ($mode eq 'indexdb') {
        indexdb(@ARGV);
 }
+elsif ($mode eq 'aggregateinternal') {
+       aggregateinternal(@ARGV);
+}
 else {
        usage();
 }
index f94f5bdd3b2b9737204ed333a31098c37e0c4cf2..71cddfdd0348fe5144db3b8ebb541d1236c737c7 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-07-12 23:07-0400\n"
+"POT-Creation-Date: 2008-07-13 15:04-0400\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -71,7 +71,7 @@ msgstr ""
 msgid "You are banned."
 msgstr ""
 
-#: ../IkiWiki/CGI.pm:758 ../IkiWiki/CGI.pm:759
+#: ../IkiWiki/CGI.pm:758 ../IkiWiki/CGI.pm:759 ../IkiWiki.pm:782
 msgid "Error"
 msgstr ""
 
@@ -194,7 +194,7 @@ msgstr ""
 msgid "There are no broken links!"
 msgstr ""
 
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/conditional.pm:18 ../IkiWiki/Plugin/testpagespec.pm:17
 #, perl-format
 msgid "%s parameter is required"
 msgstr ""
@@ -212,7 +212,7 @@ msgstr ""
 msgid "edittemplate %s registered for %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:113
 msgid "failed to process"
 msgstr ""
 
@@ -233,7 +233,7 @@ msgid "prog not a valid graphviz program"
 msgstr ""
 
 #: ../IkiWiki/Plugin/img.pm:49
-msgid "Image::Magick not installed"
+msgid "Image::Magick is not installed"
 msgstr ""
 
 #: ../IkiWiki/Plugin/img.pm:56
@@ -287,7 +287,7 @@ msgstr ""
 msgid "RPC::XML::Client not found, not pinging"
 msgstr ""
 
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:97
 msgid "failed to run dot"
 msgstr ""
 
@@ -408,7 +408,7 @@ msgid "polygen not installed"
 msgstr ""
 
 #: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
+msgid "command failed"
 msgstr ""
 
 #: ../IkiWiki/Plugin/postsparkline.pm:32
@@ -612,47 +612,47 @@ msgstr ""
 msgid "getctime not implemented"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:286 ../IkiWiki/Render.pm:307
+#: ../IkiWiki/Render.pm:290 ../IkiWiki/Render.pm:311
 #, perl-format
 msgid "skipping bad filename %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:361
+#: ../IkiWiki/Render.pm:365
 #, perl-format
 msgid "removing old page %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:401
+#: ../IkiWiki/Render.pm:405
 #, perl-format
 msgid "scanning %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:406
+#: ../IkiWiki/Render.pm:410
 #, perl-format
 msgid "rendering %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:427
+#: ../IkiWiki/Render.pm:431
 #, perl-format
 msgid "rendering %s, which links to %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:448
+#: ../IkiWiki/Render.pm:452
 #, perl-format
 msgid "rendering %s, which depends on %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:487
+#: ../IkiWiki/Render.pm:491
 #, perl-format
 msgid "rendering %s, to update its backlinks"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:499
+#: ../IkiWiki/Render.pm:503
 #, perl-format
 msgid "removing %s, no longer rendered by %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:523
+#: ../IkiWiki/Render.pm:527
 #, perl-format
 msgid "ikiwiki: cannot render %s"
 msgstr ""
@@ -729,6 +729,6 @@ msgstr ""
 msgid "%s preprocessing loop detected on %s at depth %i"
 msgstr ""
 
-#: ../IkiWiki.pm:1203
+#: ../IkiWiki.pm:1212
 msgid "yes"
 msgstr ""
index 66e90d8e3bc91d8323283be6c10d313fa603beef..3faf44154203aaa88a0bef7e1ad152311497747b 100755 (executable)
--- a/t/html.t
+++ b/t/html.t
@@ -6,7 +6,7 @@ use Test::More;
 my @pages;
 
 BEGIN {
-       @pages=qw(index todo features news plugins/map security);
+       @pages=qw(index features news plugins/map security);
        if (! -x "/usr/bin/validate") {
                plan skip_all => "/usr/bin/validate html validator not present";
        }
index 71d57b00830fcdf821d87535f195e8add7d4e173..ffcb897a8d250b88fd1a3e22d1ab765329da39f6 100644 (file)
@@ -1,4 +1,7 @@
 <div class="inlinepage">
+
+<div class="inlineheader">
+
 <TMPL_IF NAME="AUTHOR">
 <span class="author">
 <TMPL_IF NAME="AUTHORURL">
 <a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a>
 </TMPL_IF>
 </span>
+
+</div><!--.inlineheader-->
+
+<div class="inlinecontent">
 <TMPL_VAR CONTENT>
+</div><!--.inlinecontent-->
+
+<div class="inlinefooter">
 
 <span class="pagedate">
 Posted <TMPL_VAR CTIME>
@@ -52,7 +62,9 @@ License: <TMPL_VAR LICENSE>
 <li><TMPL_VAR DISCUSSIONLINK></li>
 </TMPL_IF>
 </ul>
-</div>
+</div><!--.actions-->
 </TMPL_IF>
 
-</div>
+</div><!--.inlinefooter-->
+
+</div><!--.inlinepage-->
index 166f3c5604c2fc91bade3963600ae84917fd8b97..f2f9c34cc1cfdbaff1dc32ed0f2e717e81ea99e1 100644 (file)
 </head>
 <body>
 
+<div class="pageheader">
 <div class="header">
 <span>
+<span class="parentlinks">
 <TMPL_LOOP NAME="PARENTLINKS">
 <a href="<TMPL_VAR NAME=URL>"><TMPL_VAR NAME=PAGE></a>/ 
 </TMPL_LOOP>
+</span>
+<span class="title">
 <TMPL_VAR TITLE>
 </span>
+</span><!--.header-->
 <TMPL_IF NAME="SEARCHFORM">
 <TMPL_VAR SEARCHFORM>
 </TMPL_IF>
@@ -50,6 +55,7 @@
 </ul>
 </div>
 </TMPL_IF>
+</div> <!-- .pageheader -->
 
 <TMPL_IF SIDEBAR>
 <div id="sidebar">
@@ -61,7 +67,7 @@
 <TMPL_VAR CONTENT>
 </div>
 
-<div id="footer">
+<div id="footer" class="pagefooter">
 <div id="pageinfo">
 
 <TMPL_IF NAME="TAGS">
@@ -88,7 +94,7 @@ Links:
 </span>
 </span>
 </TMPL_IF>
-</div>
+</div><!-- #backlinks -->
 </TMPL_IF>
 
 <TMPL_IF COPYRIGHT>
@@ -110,10 +116,10 @@ Last edited <TMPL_VAR NAME=MTIME>
 <!-- Created <TMPL_VAR NAME=CTIME> -->
 </div>
 
-</div>
+</div><!-- #pageinfo -->
 <TMPL_IF EXTRAFOOTER><TMPL_VAR EXTRAFOOTER></TMPL_IF>
 <!-- from <TMPL_VAR NAME=WIKINAME> -->
-</div>
+</div><!-- .pagefooter #footer -->
 
 </body>
 </html>